Skip to content

Commit

Permalink
FIX: Fix InputControls for precompiled layouts (ISXB-551) (Unity-Tech…
Browse files Browse the repository at this point in the history
…nologies#1701)

* Fix input controls and devices that fail to compile in precompiled layouts;

Add a test to catch any types that will not work in a precompiled layout

* Update changelog

* Run format tool

* Update package version

* 1.6.4 -> 1.7.0

* add more exceptions to the APIValidator for new protected properties

* remove PVS Validation Exceptions as they seem unneeded now

---------

Co-authored-by: James McGill <[email protected]>
  • Loading branch information
mtschoen-unity and jamesmcgill authored Aug 1, 2023
1 parent af10098 commit c8c9e8a
Show file tree
Hide file tree
Showing 33 changed files with 362 additions and 213 deletions.
8 changes: 4 additions & 4 deletions Assets/Samples/CustomDevice/CustomDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,10 @@ private static void Initialize()
// for it a little bit. One thing we can do is expose the controls for our
// device directly. While anyone can look up our controls using strings, exposing
// the controls as properties makes it simpler to work with the device in script.
public ButtonControl firstButton { get; private set; }
public ButtonControl secondButton { get; private set; }
public ButtonControl thirdButton { get; private set; }
public StickControl stick { get; private set; }
public ButtonControl firstButton { get; protected set; }
public ButtonControl secondButton { get; protected set; }
public ButtonControl thirdButton { get; protected set; }
public StickControl stick { get; protected set; }

// FinishSetup is where our device setup is finalized. Here we can look up
// the controls that have been created.
Expand Down
2 changes: 1 addition & 1 deletion Assets/Samples/InGameHints/InGameHintsActions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was auto-generated by com.unity.inputsystem:InputActionCodeGenerator
// version 1.6.4
// version 1.7.0
// from Assets/Samples/InGameHints/InGameHintsActions.inputactions
//
// Changes to this file may cause incorrect behavior and will be lost if
Expand Down
2 changes: 1 addition & 1 deletion Assets/Samples/SimpleDemo/SimpleControls.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was auto-generated by com.unity.inputsystem:InputActionCodeGenerator
// version 1.6.4
// version 1.7.0
// from Assets/Samples/SimpleDemo/SimpleControls.inputactions
//
// Changes to this file may cause incorrect behavior and will be lost if
Expand Down
92 changes: 92 additions & 0 deletions Assets/Tests/InputSystem/APIVerificationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,98 @@ public void API_MonoBehavioursHaveHelpUrls()
public ButtonControl tap { get; }
public IntegerControl tapCount { get; }
public IntegerControl touchId { get; }
public UnityEngine.InputSystem.Controls.ButtonControl app { get; }
public UnityEngine.InputSystem.Controls.Vector3Control deviceAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control deviceVelocity { get; }
public UnityEngine.InputSystem.Controls.ButtonControl home { get; }
public UnityEngine.InputSystem.Controls.ButtonControl recentered { get; }
public UnityEngine.InputSystem.Controls.ButtonControl recentering { get; }
public UnityEngine.InputSystem.Controls.Vector2Control touchpad { get; }
public UnityEngine.InputSystem.Controls.ButtonControl touchpadClicked { get; }
public UnityEngine.InputSystem.Controls.ButtonControl touchpadTouched { get; }
public UnityEngine.InputSystem.Controls.ButtonControl volumeDown { get; }
public UnityEngine.InputSystem.Controls.ButtonControl volumeUp { get; }
public UnityEngine.InputSystem.Controls.ButtonControl back { get; }
public UnityEngine.InputSystem.Controls.Vector3Control deviceAngularAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control deviceAngularVelocity { get; }
public UnityEngine.InputSystem.Controls.AxisControl trigger { get; }
public UnityEngine.InputSystem.Controls.ButtonControl triggerPressed { get; }
public UnityEngine.InputSystem.Controls.Vector3Control centerEyeAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control centerEyeAngularAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control centerEyeAngularVelocity { get; }
public UnityEngine.InputSystem.Controls.Vector3Control leftEyeAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control leftEyeAngularAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control leftEyeAngularVelocity { get; }
public UnityEngine.InputSystem.Controls.Vector3Control rightEyeAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control rightEyeAngularAcceleration { get; }
public UnityEngine.InputSystem.Controls.Vector3Control rightEyeAngularVelocity { get; }
public UnityEngine.InputSystem.Controls.ButtonControl userPresence { get; }
public UnityEngine.InputSystem.Controls.ButtonControl start { get; }
public UnityEngine.InputSystem.Controls.AxisControl grip { get; }
public UnityEngine.InputSystem.Controls.ButtonControl gripPressed { get; }
public UnityEngine.InputSystem.Controls.ButtonControl primaryButton { get; }
public UnityEngine.InputSystem.Controls.ButtonControl primaryTouched { get; }
public UnityEngine.InputSystem.Controls.ButtonControl secondaryButton { get; }
public UnityEngine.InputSystem.Controls.ButtonControl secondaryTouched { get; }
public UnityEngine.InputSystem.Controls.Vector2Control thumbstick { get; }
public UnityEngine.InputSystem.Controls.ButtonControl thumbstickClicked { get; }
public UnityEngine.InputSystem.Controls.ButtonControl thumbstickTouched { get; }
public UnityEngine.InputSystem.Controls.AxisControl triggerTouched { get; }
public UnityEngine.InputSystem.Controls.ButtonControl isTracked { get; }
public UnityEngine.InputSystem.Controls.IntegerControl trackingState { get; }
public UnityEngine.InputSystem.Controls.ButtonControl primary { get; }
public UnityEngine.InputSystem.Controls.ButtonControl trackpadPressed { get; }
public UnityEngine.InputSystem.Controls.Vector2Control joystick { get; }
public UnityEngine.InputSystem.Controls.ButtonControl menu { get; }
public UnityEngine.InputSystem.Controls.ButtonControl touchpadClick { get; }
public UnityEngine.InputSystem.Controls.ButtonControl touchpadTouch { get; }
public UnityEngine.InputSystem.Controls.Vector3Control centerEyeVelocity { get; }
public UnityEngine.InputSystem.Controls.Vector3Control leftEyeVelocity { get; }
public UnityEngine.InputSystem.Controls.Vector3Control rightEyeVelocity { get; }
public UnityEngine.InputSystem.Controls.Vector2Control trackpad { get; }
public UnityEngine.InputSystem.Controls.ButtonControl trackpadTouched { get; }
public Controls.Vector3Control acceleration { get; }
public Controls.AxisControl ambientTemperature { get; }
public Controls.QuaternionControl attitude { get; }
public Controls.Vector3Control gravity { get; }
public Controls.Vector3Control angularVelocity { get; }
public Controls.AxisControl relativeHumidity { get; }
public Controls.AxisControl lightLevel { get; }
public Controls.Vector3Control magneticField { get; }
public Controls.AxisControl atmosphericPressure { get; }
public Controls.AxisControl distance { get; }
public Controls.IntegerControl stepCounter { get; }
public Controls.Vector3Control devicePosition { get; }
public Controls.QuaternionControl deviceRotation { get; }
public Controls.ButtonControl isTracked { get; }
public Controls.IntegerControl trackingState { get; }
public AxisControl w { get; }
public AxisControl x { get; }
public AxisControl y { get; }
public AxisControl z { get; }
public UnityEngine.InputSystem.Controls.ButtonControl leftTriggerButton { get; }
public UnityEngine.InputSystem.Controls.ButtonControl playStationButton { get; }
public UnityEngine.InputSystem.Controls.ButtonControl rightTriggerButton { get; }
public UnityEngine.InputSystem.Controls.ButtonControl view { get; }
public UnityEngine.InputSystem.Controls.IntegerControl parentBoneIndex { get; }
public UnityEngine.InputSystem.Controls.Vector3Control position { get; }
public UnityEngine.InputSystem.Controls.QuaternionControl rotation { get; }
public UnityEngine.InputSystem.Controls.Vector3Control fixationPoint { get; }
public UnityEngine.InputSystem.Controls.AxisControl leftEyeOpenAmount { get; }
public UnityEngine.InputSystem.Controls.Vector3Control leftEyePosition { get; }
public UnityEngine.InputSystem.Controls.QuaternionControl leftEyeRotation { get; }
public UnityEngine.InputSystem.Controls.AxisControl rightEyeOpenAmount { get; }
public UnityEngine.InputSystem.Controls.Vector3Control rightEyePosition { get; }
public UnityEngine.InputSystem.Controls.QuaternionControl rightEyeRotation { get; }
public UnityEngine.InputSystem.Controls.Vector3Control centerEyePosition { get; }
public UnityEngine.InputSystem.Controls.QuaternionControl centerEyeRotation { get; }
public UnityEngine.InputSystem.Controls.ButtonControl airTap { get; }
public UnityEngine.InputSystem.Controls.Vector3Control sourceLossMitigationDirection { get; }
public UnityEngine.InputSystem.Controls.AxisControl sourceLossRisk { get; }
public UnityEngine.InputSystem.Controls.AxisControl batteryLevel { get; }
public UnityEngine.InputSystem.Controls.ButtonControl joystickClicked { get; }
public UnityEngine.InputSystem.Controls.Vector3Control pointerPosition { get; }
public UnityEngine.InputSystem.Controls.QuaternionControl pointerRotation { get; }
")]
// InputActionAsset and InputActionMap changed from IInputActionCollection to IInputActionCollection2 with
// the latter just being based on the former.
Expand Down
66 changes: 66 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Controls.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using NUnit.Framework;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Processors;
using UnityEngine.InputSystem.Utilities;
Expand Down Expand Up @@ -1524,4 +1527,67 @@ public void Controls_OptimizedControls_ParentChangesOptimization_IfChildIsNoLong
Assert.That(mouse.position.y.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatFloat));
Assert.That(mouse.position.optimizedControlDataType, Is.EqualTo(InputStateBlock.FormatInvalid));
}

[Test]
[Category("Controls")]
public void Controls_PrecompiledLayouts_AllChildControlPropertiesHaveSetters()
{
var inputDevice = typeof(InputDevice);
var inputControlType = typeof(InputControl);
var checkedTypes = new HashSet<Type>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
foreach (var type in assembly.GetTypes())
{
// Skip base types
if (type == inputControlType || type == inputDevice)
continue;

if (!inputControlType.IsAssignableFrom(type))
continue;

CheckChildControls(type, checkedTypes);
}
}
catch (ReflectionTypeLoadException)
{
// Suppress type load exceptions
}
}
}

static void CheckChildControls(Type type, HashSet<Type> checkedTypes)
{
if (!checkedTypes.Add(type))
return;

foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
if (!typeof(InputControl).IsAssignableFrom(property.PropertyType))
continue;

// Note: This will miss InputDevice controls that don't have an InputControlAttribute, but is necessary
// because not all InputControl properties are actually controls. We would need to build the device to know
// for sure if a given property is a control
if (!property.GetCustomAttributes<InputControlAttribute>().Any())
continue;

var setMethod = property.SetMethod;
if (typeof(InputDevice).IsAssignableFrom(type))
{
// Properties on an InputDevice can be protected, since the precompiled layout will be an inherited class
var inputDeviceMessage = $"A public or protected setter is required on {type.FullName}.{property.Name} in order to support precompiled layouts";
Assert.That(setMethod, Is.Not.Null, inputDeviceMessage);
Assert.That(setMethod.IsPrivate, Is.Not.True, inputDeviceMessage);
Assert.That(setMethod.IsAssembly, Is.Not.True, inputDeviceMessage);
continue;
}

var inputControlMessage = $"A public setter is required on {type.FullName}.{property.Name} in order to support precompiled layouts";
Assert.That(setMethod, Is.Not.Null, inputControlMessage);
Assert.That(setMethod.IsPublic, Is.True, inputControlMessage);
}
}
}
8 changes: 4 additions & 4 deletions Assets/Tests/InputSystem/CoreTests_Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ public void Devices_ChangingStateOfDevice_TriggersNotification()
private class TestDeviceThatResetsStateInCallback : InputDevice, IInputStateCallbackReceiver
{
[InputControl(format = "FLT")]
public ButtonControl button { get; private set; }
public ButtonControl button { get; protected set; }

protected override void FinishSetup()
{
Expand Down Expand Up @@ -2029,7 +2029,7 @@ long DeviceCallback(int deviceId, InputDeviceCommand* command, ref bool received
class DeviceWithCustomReset : InputDevice, ICustomDeviceReset
{
[InputControl]
public AxisControl axis { get; private set; }
public AxisControl axis { get; protected set; }

protected override void FinishSetup()
{
Expand Down Expand Up @@ -5630,8 +5630,8 @@ public enum Behavior

public Behavior behavior = Behavior.PreserveEventsAsIs;

public IntegerControl value1 { get; private set; }
public IntegerControl value2 { get; private set; }
public IntegerControl value1 { get; protected set; }
public IntegerControl value2 { get; protected set; }

protected override void FinishSetup()
{
Expand Down
4 changes: 2 additions & 2 deletions Assets/Tests/InputSystem/CoreTests_Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2081,7 +2081,7 @@ private struct CustomDeviceState : IInputStateTypeInfo
[InputControlLayout(stateType = typeof(CustomDeviceState))]
private class CustomDevice : InputDevice
{
public AxisControl axis { get; private set; }
public AxisControl axis { get; protected set; }

protected override void FinishSetup()
{
Expand Down Expand Up @@ -2549,7 +2549,7 @@ public class TestException : Exception
}

public bool throwExceptionOnState = true;
public AxisControl axis { get; private set; }
public AxisControl axis { get; protected set; }

protected override void FinishSetup()
{
Expand Down
2 changes: 1 addition & 1 deletion Assets/Tests/InputSystem/CoreTests_Remoting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ public void Dispose()

private class MyDevice : InputDevice
{
public ButtonControl myControl { get; private set; }
public ButtonControl myControl { get; protected set; }

protected override void FinishSetup()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was auto-generated by com.unity.inputsystem:InputActionCodeGenerator
// version 1.6.4
// version 1.7.0
// from Assets/Tests/InputSystem/InputActionCodeGeneratorActions.inputactions
//
// Changes to this file may cause incorrect behavior and will be lost if
Expand Down
2 changes: 1 addition & 1 deletion Assets/Tests/InputSystem/Plugins/OnScreenTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ public void Devices_CanUseOnScreenButtonWithCustomDevice()
public class CustomDevice : InputDevice
{
[InputControl]
public ButtonControl button { get; private set; }
public ButtonControl button { get; protected set; }

protected override void FinishSetup()
{
Expand Down
4 changes: 2 additions & 2 deletions Assets/Tests/InputSystem/Plugins/SteamTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ public FourCC format
[InputControlLayout(stateType = typeof(TestControllerState))]
class TestController : SteamController
{
public ButtonControl fire { get; private set; }
public StickControl look { get; private set; }
public ButtonControl fire { get; protected set; }
public StickControl look { get; protected set; }

public int updateCount;
public int resolveActionsCount;
Expand Down
10 changes: 5 additions & 5 deletions Assets/Tests/InputSystem/Plugins/XRTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,11 @@ public void Layouts_ButtonsArePackedByTheByte_WhileLargerStructuresAreFourByteAl
class TestHMD : UnityEngine.InputSystem.InputDevice
{
[InputControl]
public QuaternionControl rotation { get; private set; }
public QuaternionControl rotation { get; protected set; }
[InputControl]
public Vector3Control position { get; private set; }
public Vector3Control position { get; protected set; }
[InputControl]
public IntegerControl trackingState { get; private set; }
public IntegerControl trackingState { get; protected set; }
protected override void FinishSetup()
{
base.FinishSetup();
Expand All @@ -351,9 +351,9 @@ protected override void FinishSetup()
class TestHMDWithoutTrackingState : UnityEngine.InputSystem.InputDevice
{
[InputControl]
public QuaternionControl rotation { get; private set; }
public QuaternionControl rotation { get; protected set; }
[InputControl]
public Vector3Control position { get; private set; }
public Vector3Control position { get; protected set; }
protected override void FinishSetup()
{
base.FinishSetup();
Expand Down
1 change: 1 addition & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ however, it has to be formatted properly to pass verification tests.
- Fixed the `Clone` methods of `InputAction` and `InputActionMap` so it copies the Initial State Check flag (`InputAction.wantsInitialStateCheck`) of input actions.
- Fixed the "Release tests throws exception in InputSystem" bug ([case ISXB-581](https://issuetracker.unity3d.com/issues/release-tests-fail-when-input-system-package-is-installed)).
- Fixed issues with generating Precompiled Layouts for devices which are not defined in a namespace
- Fixed an issue where some controls like `QuaternionControl` could not be included in a Precompiled Layout because the generated code could not access a setter on child control properties.

## [1.6.3] - 2023-07-11

Expand Down
4 changes: 2 additions & 2 deletions Packages/com.unity.inputsystem/InputSystem/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static partial class InputSystem
// Keep this in sync with "Packages/com.unity.inputsystem/package.json".
// NOTE: Unfortunately, System.Version doesn't use semantic versioning so we can't include
// "-preview" suffixes here.
internal const string kAssemblyVersion = "1.6.4";
internal const string kDocUrl = "https://docs.unity3d.com/Packages/com.unity.inputsystem@1.6";
internal const string kAssemblyVersion = "1.7.0";
internal const string kDocUrl = "https://docs.unity3d.com/Packages/com.unity.inputsystem@1.7";
}
}
Loading

0 comments on commit c8c9e8a

Please sign in to comment.