CHANGE: Split Runtime and Editor code into separate folders to prepare for Module migration#2321
CHANGE: Split Runtime and Editor code into separate folders to prepare for Module migration#2321jfreire-unity wants to merge 119 commits intodevelopfrom
Conversation
- Move InputSystem/* to Runtime/ (preserving history) - Move InputSystem/Editor to Editor/ (preserving history) - Add meta files for new folder structure - Follows Unity package layout conventions - All file history preserved via git mv
Also exposes the required internals between assemblies.
This is done to avoid calling into Edito specific code. Instead, it will be called if Editor code has registered a callback.
Due to refactoring, a lot of paths still contained the InputSystem folder path that no longer exists. We only have Editor and Runtime folders.
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨🤖 Helpful? Please react with 👍/👎 | Questions❓Please reach out in Slack #ask-u-pr |
Some files were moved to other folders, after merging conflicts arise but since they showed as removed changes didn't land on the moved files. This commit is fixing this
|
|
No merge conflicts were found in the branch – |
|
/crc |
There was a problem hiding this comment.
This review identified several new unique issues, including a potential compilation error in test utility code, missing null-safety in composite editor classes, and a resource path typo in a style sheet. Previously reported critical issues regarding initialization race conditions and native buffer management are currently being tracked in separate discussion threads.
🤖 Helpful? 👍/👎
…tor/PackageResources/InputActionsEditorStyles.uss Co-authored-by: u-pr[bot] <205906871+u-pr[bot]@users.noreply.github.com>
|
/crc |
| @@ -139,7 +142,7 @@ public void Restore() | |||
|
|
|||
| #if UNITY_EDITOR | |||
| InputEditorUserSettings.s_Settings = state.userSettings; | |||
| JsonUtility.FromJsonOverwrite(state.systemObject, InputSystem.domainStateManager); | |||
| JsonUtility.FromJsonOverwrite(state.systemObject, InputSystemEditorInitializer.domainStateManager); | |||
There was a problem hiding this comment.
In test environments where InputSystem.TestHook_InitializeForPlayModeTests is used, InputSystemEditorInitializer.s_DomainStateManager may not be initialized. This causes InputTestStateManager.Restore to throw a NullReferenceException when calling JsonUtility.FromJsonOverwrite because the second argument is null. You may need to ensure a valid state manager is available or handled during state restoration in tests.
🤖 Helpful? 👍/👎
There was a problem hiding this comment.
@u-pr is this guaranteed in the develop branch of this repository or is the problem still there as well?
This comment was marked as off-topic.
This comment was marked as off-topic.
|
Persistent custom_review updated to latest commit 39000ea |
|
@u-pr can you check which review problems you mentioned have been addressed? |
|
I've reviewed the latest changes against the review problems previously mentioned. Here is a status update on those items: ✅ Addressed
|
Copilot triggered some work that committed work we were not completly happy with.
|
@u-pr can you check which review problems you mentioned have been addressed? |
|
I've checked the latest changes against the review problems previously mentioned. Here is the status of those items: ✅ Addressed
|
|
/crc |
| internal static Action<bool> s_SuppressAnalytics; | ||
|
|
||
| // API constants for analytics (matches Editor InputExitPlayModeAnalytic.Api enum) | ||
| internal enum Api |
| @@ -2985,23 +2963,25 @@ internal static bool ShouldDrawWarningIconForBinding(string bindingPath) | |||
| #region Actions | |||
|
|
|||
|
|
|||
| // This is called from InitializeInEditor() and InitializeInPlayer() to make sure | |||
| // This is called to make sure | |||
| // project-wide actions are all active in they are active in all of these MonoBehavior methods: | |||
…alInitialize() Co-authored-by: u-pr[bot] <205906871+u-pr[bot]@users.noreply.github.com>
ekcoh
left a comment
There was a problem hiding this comment.
Adding a first batch of comments and will resume from InputActionReference in the diff when I can review more.
| [TestCase("Keyboard", "Devices/Precompiled/FastKeyboard.cs")] | ||
| [TestCase("Mouse", "Devices/Precompiled/FastMouse.cs")] | ||
| [TestCase("Touchscreen", "Devices/Precompiled/FastTouchscreen.cs")] | ||
| [TestCase("Keyboard", "InputSystem/Runtime/Devices/Precompiled/FastKeyboard.cs")] |
There was a problem hiding this comment.
Why pass the InputSystem/Runtime/ when it seems to always be part of the arg? Either pass the full path or only pass the relevant part IMO since concatenated on line 220. Also would prefer Path.Combine but maybe its irrelevant.
|
|
||
| currentTime = 1; | ||
| InputSystem.OnPlayModeChange(PlayModeStateChange.ExitingEditMode); | ||
| InputSystemEditorInitializer.OnPlayModeChange(PlayModeStateChange.ExitingEditMode); |
There was a problem hiding this comment.
Doesn't have to be addressed by this PR, but I believe we should make sure we have a ticket filed on replacing these "faked play-mode state transitions" with real ones when this already sits in a proper editor test?
| UnityEngine.TestTools.LogAssert.Expect(LogType.Error, "ScriptableSingleton already exists. Did you query the singleton in a constructor?"); | ||
| UnityEngine.TestTools.LogAssert.Expect(LogType.Error, "ScriptableSingleton already exists. Did you query the singleton in a constructor?"); | ||
| // Ensure the singleton is initialized deterministically in editor. | ||
| _ = RemoteInputPlayerConnection.instance; |
There was a problem hiding this comment.
Exactly, most commonly seen in in inline lambdas though. This looks very odd. Why do we need for this "singleton" to instantiate on this row? It seems like it's created below. Is there some brittle design that might need addressing here?
|
|
||
| namespace UnityEngine.InputSystem.Processors | ||
| { | ||
| #if UNITY_EDITOR |
There was a problem hiding this comment.
Shouldn't this #if and matching #endif be enclosing all the content of this file?
|
|
||
| namespace UnityEngine.InputSystem.Processors | ||
| { | ||
| #if UNITY_EDITOR |
There was a problem hiding this comment.
I would recommend enclosing all the content of this file with this #if, and move corresponding #endif to the end as well.
| private CustomOrDefaultSetting m_MinSetting; | ||
| private CustomOrDefaultSetting m_MaxSetting; | ||
| } | ||
| #endif |
There was a problem hiding this comment.
IMO, it would be best to enclose all content, other files do this.
| private CustomOrDefaultSetting m_MinSetting; | ||
| private CustomOrDefaultSetting m_MaxSetting; | ||
| } | ||
| #endif |
There was a problem hiding this comment.
This #endif can terminate the file
| @@ -216,13 +216,13 @@ public static Command DeleteSelectedControlScheme() | |||
| if (indexOfArrayElement > serializedArray.arraySize - 1) | |||
| return state.With( | |||
| selectedControlSchemeIndex: serializedArray.arraySize - 1, | |||
| selectedControlScheme: new InputControlScheme(serializedArray.GetArrayElementAtIndex(serializedArray.arraySize - 1)), selectedDeviceRequirementIndex: -1); | |||
| selectedControlScheme: InputControlSchemeEditorExtensions.FromSerializedProperty(serializedArray.GetArrayElementAtIndex(serializedArray.arraySize - 1)), selectedDeviceRequirementIndex: -1); | |||
There was a problem hiding this comment.
I would suggest making a separate bug ticket on this specific issue and related fix, then fix it directly after landing this.
| @@ -8,31 +8,6 @@ | |||
|
|
|||
| namespace UnityEngine.InputSystem | |||
| { | |||
There was a problem hiding this comment.
I notice this structure was previously included in EITHER editor OR development builds. To me it's not obvious why that would be, is to be able to access remoting or something else? Just want to make sure this won't make a regression and there might be reasoning from your side around this?
| @@ -895,10 +894,14 @@ IEnumerator IEnumerable.GetEnumerator() | |||
| internal void MarkAsDirty() | |||
There was a problem hiding this comment.
Hmmm... who calls this? Given that the function is a no-op outside editor builds I wonder if this should only be tracked in the editor context, e.g. list of InputActionAsset references which are dirty instead of doing it this way.
ekcoh
left a comment
There was a problem hiding this comment.
I think InputActionReference need some work. Will post again when I have reviewed this whole PR.
| // residing as a sub-asset within a .inputactions asset. | ||
| // This is not needed for players since scriptable objects aren't serialized back from within a player. | ||
| if (!CanSetReference(this)) | ||
| if (!CanSetReference()) |
There was a problem hiding this comment.
I would suggest that we do this differently. It seems whole CheckImmutableReference is really only relevant for editor use cases so it could move to editor code. That eliminates the need for those function objects. Instead, pass a single function object instead that is only called (if its set) at line where call to CheckImmutableReference() happens, then this is fully separated between editor and player right?
| { | ||
| #if UNITY_EDITOR | ||
| RegisterApiUsage(UnityEngine.InputSystem.Editor.InputExitPlayModeAnalytic.Api.AddBinding); | ||
| RegisterAnalyticsApi((int)Api.AddBinding); |
There was a problem hiding this comment.
Why are we casting this (and following places to int?)
|
|
||
| namespace UnityEngine.InputSystem | ||
| { | ||
| #if UNITY_EDITOR || DEVELOPMENT_BUILD |
There was a problem hiding this comment.
I wonder if this is all needed, shouldn't this structure be stripped if not referenced in a release build?
Description
Background & Goal
NOTE 🤯: This PR is huge and hard to review, but a lot of the changes are moving files and folders around. I know it's not easy to navigate these huge changes so I tried my best to do a good PR description.
The Unity Input System package historically had
UnityEditor.*references scattered throughout its runtime code, guarded by#if UNITY_EDITORpreprocessor directives, but still in the same files as runtime logic.This was making the codebase hard to port into a Unity module in trunk (
unity/unity), and it was also harder to reason about the Editor vs Standalone player boundary.This PR tries to break the dependency of Editor references in Runtime code to help us migrate to a Unity module and does the following changes:
UnityEditor.*references remain in the runtime source files.Unity.InputSystemassembly is kept . The folder reorganisation (Runtime/andEditor/subfolders) is the externally visible result, making forward-ports and movinggithistory to trunk and eventual module migration easier. We decided not to introduce 2 assemblies as this would duplicate our upgrade path when projects upgrade to a Unity version using the new Input System module.Ideally, we would have liked to also have a Runtime and Editor assembly.
That work was initially done but then we reverted it due to the last point above.
This PR was done with the help of agentic coding as well.
High-Level Changes
InputSystem/Runtime/, all editor source toInputSystem/Editor/. 1,201 files renamed (history preserved viagit mv).Unity.InputSystem.asmdefkept as single monolith. AUnity.InputSystem.Editorasmdef was prototyped and then rolled back — the folder split remains as foundation for a future module migration.UnityEditor.*call in runtime files with internalstaticcallback fields (Action,Func). The Editor registers these at startup via[InitializeOnLoad]. In player builds these fields arenulland all call sites are null-safe (?.Invoke()).InputSystemEditorInitializer.cs[InitializeOnLoad]class inEditor/that owns all editor lifecycle concerns previously scattered across the runtime (play-mode changes, domain reload, asset tracking, analytics, Unity Remote, remoting, etc.).InputSystemState.csInputSystemObjectand editor-specific paths) into its own runtime class to help with the dependency boundary.*Editorclasses (Interaction editors, Composite editors, Processor editors, OnScreen editors) removed from runtime files and placed in dedicated files underEditor/.#if UNITY_EDITORmoved toEditor/(e.g.PlayerInputEditor,UnityRemoteSupport,iOSPostProcessBuild).InputTestRuntime,InputTestStateManagerupdated to reflect the new interface contracts (e.g.onPlayModeChanged: Action<int>instead ofAction<PlayModeStateChange>).Pattern used for these changes
The approach used throughout this PR is maybe worth understanding before reviewing individual files:
This pattern appears in:
InputSystem.cs,InputManager.cs,NativeInputRuntime.cs,InputActionSetupExtensions.cs,InputActionAsset.cs,InputActionReference.cs,EnhancedTouchSupport.cs,RemoteInputPlayerConnection.cs,OnScreenStick.cs,TrackedPoseDriver.cs,InputSystemUIInputModule.cs.Review Guide Suggestions
1.
InputSystem/Runtime/InputSystem.csusing UnityEditor;is gone.s_OnSettingsChanged,s_OnActionsChanging,s_ShouldEnableActions,s_OnPlayModeChangeCallback) are used consistently and null-safely.#if UNITY_EDITORblock forOnPlayModeChangeis intentional — it is a forwarding shim for tests that call it directly.2.
InputSystem/Runtime/NativeInputRuntime.csEditorApplication.isPlaying,EditorApplication.isPaused,InternalEditorUtility.isApplicationActive, andEditorAnalyticscalls.internal boolfields (m_IsInPlayMode,m_IsEditorPaused,m_IsEditorActive) and callbacks (m_SendEditorAnalytic,m_SetUnityRemoteMessageHandler, etc.).UpdateEditorState()method inInputSystemEditorInitializeris pumping those fields onEditorApplication.update.3.
InputSystem/Runtime/InputManager.csEditorApplication.isPaused→m_Runtime.isEditorPaused(fromIInputRuntime).InputSystem.s_SystemObjectreferences replaced with localm_ExitEditModeTime/m_EnterPlayModeTimefields.ProjectWideActionsBuildProvider.actionsToIncludeInPlayerBuildreplaced withs_GetProjectWideActionscallback.4.
InputSystem/Runtime/IInputRuntime.csonPlayModeChangedchanged fromAction<PlayModeStateChange>toAction<int>— removes theUnityEditorenum from the interface.bool isEditorPaused { get; }.5.
InputSystem/Editor/InputSystemEditorInitializer.cs(new file)OnEditorPlayModeStateChanged→ setsm_IsInPlayMode,m_IsEditorPaused, dispatchesDispatchPlayModeChange, etc.InputSystemStateis loaded/restored here.6. Extracted
*Editorclasses (Editor/Actions/Interactions/,Editor/Actions/Composites/,Editor/Controls/Processors/,Editor/Plugins/OnScreen/)7.
InputSystem/Runtime/Actions/InputActionReference.cs,InputActionAsset.cs,EnhancedTouchSupport.csAssetDatabase/AssemblyReloadEventscalls replaced with callback fields.#if UNITY_EDITOR-guarded.8. Test fixtures —
Tests/TestFixture/InputTestRuntime.cs:onPlayModeChangedis nowAction<int>— make sure test call sites cast correctly.InputTestStateManager.cs: there were some naming changes, so something to be aware.9. Assembly /
.asmdeffilesUnity.InputSystem.asmdefshould still reference a single assembly (no Editor split).Unity.InputSystemonly.AssemblyInfo.cs:InternalsVisibleToentries cover test assemblies — verify no entry was accidentally dropped.InputSystemForUI.Editor.asmdef, since the previous folder containingInputSystemForUI.asmdefwas split into Editor and Runtime. This is part of internal API so I don't see any breakages in this area when upgrading.Testing status & QA
Built and run Samples on both Windows and macOS Play-mode and Standalone builds.
I recommend validating all the Samples work and do kind of the sames tests as we would do for a Release since this PR touches a lot of things.
Overall Product Risks
Please rate the potential complexity and halo effect from low to high for the reviewers. Note down potential risks to specific Editor branches if any.
Comments to reviewers
Some sanity check guides:
using UnityEditor;in any file underInputSystem/Runtime/InputSystemEditorInitializerregisters every callback that has a field on the runtime sideInputTestRuntimecompiles and tests pass with the updatedAction<int>signatureUnity.InputSystemwas accidentally wired to a now-deletedUnity.InputSystem.Editorassembly. Hopefully there are not left overs of this initial work.One thing is not in place is a mechanism to guarantee we don't leak UnityEditor references in the Runtime folder. I'll follow up on that in another PR.
Checklist
Before review:
Changed,Fixed,Addedsections.Area_CanDoX,Area_CanDoX_EvenIfYIsTheCase,Area_WhenIDoX_AndYHappens_ThisIsTheResult.During merge:
NEW: ___.FIX: ___.DOCS: ___.CHANGE: ___.RELEASE: 1.1.0-preview.3.