Skip to content

Commit 3fb97b4

Browse files
authored
Fix issue with queuing input events that stomp on others. (#5034)
1 parent cedc75c commit 3fb97b4

21 files changed

+240
-50
lines changed

DevProject/Packages/packages-lock.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"url": "https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-candidates"
3232
},
3333
"com.unity.barracuda": {
34-
"version": "1.3.0-preview",
34+
"version": "1.3.1-preview",
3535
"depth": 1,
3636
"source": "registry",
3737
"dependencies": {
@@ -108,7 +108,7 @@
108108
"depth": 0,
109109
"source": "local",
110110
"dependencies": {
111-
"com.unity.barracuda": "1.3.0-preview",
111+
"com.unity.barracuda": "1.3.1-preview",
112112
"com.unity.modules.imageconversion": "1.0.0",
113113
"com.unity.modules.jsonserialize": "1.0.0",
114114
"com.unity.modules.physics": "1.0.0",
@@ -121,7 +121,7 @@
121121
"depth": 0,
122122
"source": "local",
123123
"dependencies": {
124-
"com.unity.ml-agents": "1.7.2-preview"
124+
"com.unity.ml-agents": "1.8.0-preview"
125125
}
126126
},
127127
"com.unity.multiplayer-hlapi": {

com.unity.ml-agents.extensions/Runtime/Input/Adaptors/ButtonInputActionAdaptor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Unity.MLAgents.Actuators;
33
using UnityEngine;
44
using UnityEngine.InputSystem;
5+
using UnityEngine.InputSystem.Controls;
56
using UnityEngine.InputSystem.LowLevel;
67

78
namespace Unity.MLAgents.Extensions.Input
@@ -26,11 +27,11 @@ public ActionSpec GetActionSpecForInputAction(InputAction action)
2627
}
2728

2829
/// TODO again this might need to be more nuanced for things like continuous buttons.
29-
/// <inheritdoc cref="IRLActionInputAdaptor.QueueInputEventForAction"/>
30-
public void QueueInputEventForAction(InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
30+
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToInputEventForAction"/>
31+
public void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
3132
{
3233
var val = actionBuffers.DiscreteActions[0];
33-
InputSystem.QueueDeltaStateEvent(control, (byte)val);
34+
((ButtonControl)control).WriteValueIntoEvent((float)val, eventPtr);
3435
}
3536

3637
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToHeuristic"/>>

com.unity.ml-agents.extensions/Runtime/Input/Adaptors/DoubleInputActionAdaptor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#if MLA_INPUT_SYSTEM && UNITY_2019_4_OR_NEWER
22
using Unity.MLAgents.Actuators;
33
using UnityEngine.InputSystem;
4+
using UnityEngine.InputSystem.Controls;
45
using UnityEngine.InputSystem.LowLevel;
56

67
namespace Unity.MLAgents.Extensions.Input
@@ -16,11 +17,11 @@ public ActionSpec GetActionSpecForInputAction(InputAction action)
1617
return ActionSpec.MakeContinuous(1);
1718
}
1819

19-
/// <inheritdoc cref="IRLActionInputAdaptor.QueueInputEventForAction"/>
20-
public void QueueInputEventForAction(InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
20+
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToInputEventForAction"/>
21+
public void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
2122
{
2223
var val = actionBuffers.ContinuousActions[0];
23-
InputSystem.QueueDeltaStateEvent(control,(double)val);
24+
((DoubleControl)control).WriteValueIntoEvent((double)val, eventPtr);
2425
}
2526

2627
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToHeuristic"/>

com.unity.ml-agents.extensions/Runtime/Input/Adaptors/FloatInputActionAdaptor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ public ActionSpec GetActionSpecForInputAction(InputAction action)
1616
return ActionSpec.MakeContinuous(1);
1717
}
1818

19-
/// <inheritdoc cref="IRLActionInputAdaptor.QueueInputEventForAction"/>
20-
public void QueueInputEventForAction(InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
19+
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToInputEventForAction"/>
20+
public void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
2121
{
2222
var val = actionBuffers.ContinuousActions[0];
23-
InputSystem.QueueDeltaStateEvent(control, val);
23+
control.WriteValueIntoEvent(val, eventPtr);
2424
}
2525

2626
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToHeuristic"/>

com.unity.ml-agents.extensions/Runtime/Input/Adaptors/IntegerInputActionAdaptor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ public ActionSpec GetActionSpecForInputAction(InputAction action)
1717
return ActionSpec.MakeDiscrete(2);
1818
}
1919

20-
/// <inheritdoc cref="IRLActionInputAdaptor.QueueInputEventForAction"/>
21-
public void QueueInputEventForAction(InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
20+
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToInputEventForAction"/>
21+
public void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers)
2222
{
2323
var val = actionBuffers.DiscreteActions[0];
24-
InputSystem.QueueDeltaStateEvent(control, val);
24+
control.WriteValueIntoEvent(val, eventPtr);
2525
}
2626

2727
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToHeuristic"/>

com.unity.ml-agents.extensions/Runtime/Input/Adaptors/Vector2InputActionAdaptor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Unity.MLAgents.Actuators;
44
using UnityEngine;
55
using UnityEngine.InputSystem;
6+
using UnityEngine.InputSystem.Controls;
67
using UnityEngine.InputSystem.LowLevel;
78

89
namespace Unity.MLAgents.Extensions.Input
@@ -19,15 +20,15 @@ public ActionSpec GetActionSpecForInputAction(InputAction action)
1920
return ActionSpec.MakeContinuous(2);
2021
}
2122

22-
/// <inheritdoc cref="IRLActionInputAdaptor.QueueInputEventForAction"/>
23-
public void QueueInputEventForAction(InputAction action,
23+
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToInputEventForAction"/>
24+
public void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action,
2425
InputControl control,
2526
ActionSpec actionSpec,
2627
in ActionBuffers actionBuffers)
2728
{
2829
var x = actionBuffers.ContinuousActions[0];
2930
var y = actionBuffers.ContinuousActions[1];
30-
InputSystem.QueueDeltaStateEvent(control, new Vector2(x, y));
31+
control.WriteValueIntoEvent(new Vector2(x, y), eventPtr);
3132
}
3233

3334
/// <inheritdoc cref="IRLActionInputAdaptor.WriteToHeuristic"/>

com.unity.ml-agents.extensions/Runtime/Input/IRLActionInputAdaptor.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using Unity.MLAgents.Actuators;
44
using UnityEngine.InputSystem;
5+
using UnityEngine.InputSystem.LowLevel;
56

67
namespace Unity.MLAgents.Extensions.Input
78
{
@@ -22,11 +23,12 @@ public interface IRLActionInputAdaptor
2223
/// <summary>
2324
/// Translates data from the <see cref="ActionBuffers"/> object to the <see cref="InputSystem"/>.
2425
/// </summary>
26+
/// <param name="eventPtr">The Event pointer to write to.</param>
2527
/// <param name="action">The action associated with this adaptor.</param>
2628
/// <param name="control">The control which will write the event to the <see cref="InputSystem"/>.</param>
2729
/// <param name="actionSpec">The <see cref="ActionSpec"/> associated with this action and adaptor pair.</param>
2830
/// <param name="actionBuffers">The <see cref="ActionBuffers"/> object to read from.</param>
29-
void QueueInputEventForAction(InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers);
31+
void WriteToInputEventForAction(InputEventPtr eventPtr, InputAction action, InputControl control, ActionSpec actionSpec, in ActionBuffers actionBuffers);
3032

3133
/// <summary>
3234
/// Writes data from the <paramref name="action"/> to the <paramref name="actionBuffers"/>.

com.unity.ml-agents.extensions/Runtime/Input/InputActionActuator.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class InputActionActuator : IActuator, IHeuristicProvider, IBuiltInActuat
1919
readonly BehaviorParameters m_BehaviorParameters;
2020
readonly InputAction m_Action;
2121
readonly IRLActionInputAdaptor m_InputAdaptor;
22+
InputActuatorEventContext m_InputActuatorEventContext;
2223
InputDevice m_Device;
2324
InputControl m_Control;
2425

@@ -34,14 +35,17 @@ public class InputActionActuator : IActuator, IHeuristicProvider, IBuiltInActuat
3435
/// via the <see cref="IRLActionInputAdaptor"/>.</param>
3536
/// <param name="adaptor">The <see cref="IRLActionInputAdaptor"/> that will convert data between ML-Agents
3637
/// and the <see cref="InputSystem"/>.</param>
38+
/// <param name="inputActuatorEventContext">The object that will provide the event ptr to write to.</param>
3739
public InputActionActuator(InputDevice inputDevice, BehaviorParameters behaviorParameters,
3840
InputAction action,
39-
IRLActionInputAdaptor adaptor)
41+
IRLActionInputAdaptor adaptor,
42+
InputActuatorEventContext inputActuatorEventContext)
4043
{
4144
m_BehaviorParameters = behaviorParameters;
4245
Name = $"InputActionActuator-{action.name}";
4346
m_Action = action;
4447
m_InputAdaptor = adaptor;
48+
m_InputActuatorEventContext = inputActuatorEventContext;
4549
ActionSpec = adaptor.GetActionSpecForInputAction(m_Action);
4650
m_Device = inputDevice;
4751
m_Control = m_Device?.GetChildControl(m_Action.name);
@@ -53,7 +57,11 @@ public void OnActionReceived(ActionBuffers actionBuffers)
5357
Profiler.BeginSample("InputActionActuator.OnActionReceived");
5458
if (!m_BehaviorParameters.IsInHeuristicMode())
5559
{
56-
m_InputAdaptor.QueueInputEventForAction(m_Action, m_Control, ActionSpec, actionBuffers);
60+
using (m_InputActuatorEventContext.GetEventForFrame(out var eventPtr))
61+
{
62+
m_InputAdaptor.WriteToInputEventForAction(eventPtr, m_Action, m_Control, ActionSpec, actionBuffers);
63+
}
64+
5765
}
5866
Profiler.EndSample();
5967
}

com.unity.ml-agents.extensions/Runtime/Input/InputActuatorComponent.cs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#if MLA_INPUT_SYSTEM && UNITY_2019_4_OR_NEWER
22
using System;
33
using System.Collections.Generic;
4+
using Unity.Collections;
45
using Unity.MLAgents.Actuators;
56
using Unity.MLAgents.Policies;
67
using UnityEngine;
78
using UnityEngine.Assertions;
89
using UnityEngine.InputSystem;
910
using UnityEngine.InputSystem.Controls;
11+
using UnityEngine.InputSystem.LowLevel;
1012
using UnityEngine.InputSystem.Layouts;
1113
using UnityEngine.InputSystem.Utilities;
1214
#if UNITY_EDITOR
@@ -57,9 +59,18 @@ public override ActionSpec ActionSpec
5759
get
5860
{
5961
#if UNITY_EDITOR
60-
FindNeededComponents();
61-
var actuators = CreateActuatorsFromMap(m_InputAsset.FindActionMap(m_PlayerInput.defaultActionMap), m_BehaviorParameters, null);
62-
m_ActionSpec = CombineActuatorActionSpecs(actuators);
62+
if (!EditorApplication.isPlaying && m_ActionSpec.NumContinuousActions == 0
63+
&& m_ActionSpec.BranchSizes == null
64+
|| m_ActionSpec.BranchSizes.Length == 0)
65+
{
66+
FindNeededComponents();
67+
var actuators = CreateActuatorsFromMap(m_InputAsset.FindActionMap(m_PlayerInput.defaultActionMap),
68+
m_BehaviorParameters,
69+
null,
70+
InputActuatorEventContext.s_EditorContext);
71+
m_ActionSpec = CombineActuatorActionSpecs(actuators);
72+
73+
}
6374
#endif
6475
return m_ActionSpec;
6576
}
@@ -119,7 +130,8 @@ public override IActuator[] CreateActuators()
119130
RegisterLayoutBuilder(inputActionMap, m_LayoutName);
120131
m_Device = InputSystem.AddDevice(m_LayoutName);
121132

122-
m_Actuators = CreateActuatorsFromMap(inputActionMap, m_BehaviorParameters, m_Device);
133+
var context = new InputActuatorEventContext(inputActionMap.actions.Count, m_Device);
134+
m_Actuators = CreateActuatorsFromMap(inputActionMap, m_BehaviorParameters, m_Device, context);
123135

124136
UpdateDeviceBinding(m_BehaviorParameters.IsInHeuristicMode());
125137
inputActionMap.Enable();
@@ -141,15 +153,16 @@ static ActionSpec CombineActuatorActionSpecs(IActuator[] actuators)
141153

142154
internal static IActuator[] CreateActuatorsFromMap(InputActionMap inputActionMap,
143155
BehaviorParameters behaviorParameters,
144-
InputDevice inputDevice)
156+
InputDevice inputDevice,
157+
InputActuatorEventContext context)
145158
{
146159
var actuators = new IActuator[inputActionMap.actions.Count];
147160
for (var i = 0; i < inputActionMap.actions.Count; i++)
148161
{
149162
var action = inputActionMap.actions[i];
150163
var actionLayout = InputSystem.LoadLayout(action.expectedControlType);
151164
var adaptor = (IRLActionInputAdaptor)Activator.CreateInstance(controlTypeToAdaptorType[actionLayout.type]);
152-
actuators[i] = new InputActionActuator(inputDevice, behaviorParameters, action, adaptor);
165+
actuators[i] = new InputActionActuator(inputDevice, behaviorParameters, action, adaptor, context);
153166

154167
// Reasonably, the input system starts adding numbers after the first none numbered name
155168
// is added. So for device ID of 0, we use the empty string in the path.
@@ -158,6 +171,7 @@ internal static IActuator[] CreateActuatorsFromMap(InputActionMap inputActionMap
158171
action.interactions,
159172
action.processors,
160173
mlAgentsControlSchemeName);
174+
action.bindingMask = InputBinding.MaskByGroup(mlAgentsControlSchemeName);
161175
}
162176
return actuators;
163177
}
@@ -326,6 +340,43 @@ internal void CleanupActionAsset()
326340
m_BehaviorParameters = null;
327341
m_Device = null;
328342
}
343+
344+
int m_ActuatorsWrittenToEvent;
345+
NativeArray<byte> m_InputBufferForFrame;
346+
InputEventPtr m_InputEventPtrForFrame;
347+
public InputEventPtr GetEventForFrame()
348+
{
349+
#if UNITY_EDITOR
350+
if (!EditorApplication.isPlaying)
351+
{
352+
return new InputEventPtr();
353+
}
354+
#endif
355+
if (m_ActuatorsWrittenToEvent % m_Actuators.Length == 0 || !m_InputEventPtrForFrame.valid)
356+
{
357+
m_ActuatorsWrittenToEvent = 0;
358+
m_InputEventPtrForFrame = new InputEventPtr();
359+
m_InputBufferForFrame = StateEvent.From(m_Device, out m_InputEventPtrForFrame);
360+
}
361+
362+
return m_InputEventPtrForFrame;
363+
}
364+
365+
public void EventProcessedInFrame()
366+
{
367+
#if UNITY_EDITOR
368+
if (!EditorApplication.isPlaying)
369+
{
370+
return;
371+
}
372+
#endif
373+
m_ActuatorsWrittenToEvent++;
374+
if (m_ActuatorsWrittenToEvent == m_Actuators.Length && m_InputEventPtrForFrame.valid)
375+
{
376+
InputSystem.QueueEvent(m_InputEventPtrForFrame);
377+
m_InputBufferForFrame.Dispose();
378+
}
379+
}
329380
}
330381
}
331382
#endif // MLA_INPUT_SYSTEM && UNITY_2019_4_OR_NEWER
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#if MLA_INPUT_SYSTEM && UNITY_2019_4_OR_NEWER
2+
using System;
3+
using Unity.Collections;
4+
using UnityEngine.InputSystem;
5+
using UnityEngine.InputSystem.LowLevel;
6+
#if UNITY_EDITOR
7+
using UnityEditor;
8+
#endif
9+
10+
namespace Unity.MLAgents.Extensions.Input
11+
{
12+
/// <summary>
13+
/// This interface is passed to InputActionActuators to allow them to write to InputEvents.
14+
/// The way this interface should be used is to request the <see cref="InputEventPtr"/> by calling
15+
/// <see cref="GetEventForFrame"/> then call <see cref="EventProcessedInFrame"/> before returning from
16+
/// </summary>
17+
public class InputActuatorEventContext : IDisposable
18+
{
19+
20+
/// <summary>
21+
/// The number of times to allow the use of an event before queuing it in the InputSystem.
22+
/// </summary>
23+
public readonly int NumTimesToProcess;
24+
public readonly InputDevice InputDevice;
25+
NativeArray<byte> m_EventBuffer;
26+
InputEventPtr m_Ptr;
27+
int m_Count;
28+
29+
#if UNITY_EDITOR
30+
public static InputActuatorEventContext s_EditorContext = new InputActuatorEventContext();
31+
#endif
32+
33+
public InputActuatorEventContext(int numTimesToProcess = 1, InputDevice device = null)
34+
{
35+
NumTimesToProcess = numTimesToProcess;
36+
InputDevice = device;
37+
m_Count = 0;
38+
m_Ptr = new InputEventPtr();
39+
m_EventBuffer = new NativeArray<byte>();
40+
}
41+
42+
/// <summary>
43+
/// Returns the <see cref="InputEventPtr"/> to write to for the current frame.
44+
/// </summary>
45+
/// <returns>The <see cref="InputEventPtr"/> to write to for the current frame.</returns>
46+
public IDisposable GetEventForFrame(out InputEventPtr eventPtr)
47+
{
48+
#if UNITY_EDITOR
49+
if (!EditorApplication.isPlaying)
50+
{
51+
eventPtr = new InputEventPtr();
52+
}
53+
#endif
54+
if (m_Count % NumTimesToProcess == 0)
55+
{
56+
m_Count = 0;
57+
m_EventBuffer = StateEvent.From(InputDevice, out m_Ptr);
58+
}
59+
eventPtr = m_Ptr;
60+
return this;
61+
}
62+
63+
public void Dispose()
64+
{
65+
#if UNITY_EDITOR
66+
if (!EditorApplication.isPlaying)
67+
{
68+
return;
69+
}
70+
#endif
71+
m_Count++;
72+
if (m_Count == NumTimesToProcess && m_Ptr.valid)
73+
{
74+
InputSystem.QueueEvent(m_Ptr);
75+
m_EventBuffer.Dispose();
76+
}
77+
78+
}
79+
}
80+
}
81+
#endif // MLA_INPUT_SYSTEM && UNITY_2019_4_OR_NEWER

com.unity.ml-agents.extensions/Runtime/Input/InputActuatorEventContext.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)