From 9ddca67cb50950b0103855a888f1737ccc6e6242 Mon Sep 17 00:00:00 2001 From: Lyndon Homewood Date: Wed, 4 Dec 2024 16:01:40 +0000 Subject: [PATCH 1/5] Documented InputStateHistory --- .../InputSystem/State/InputStateHistory.cs | 506 +++++++++++++++++- 1 file changed, 497 insertions(+), 9 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs index e98443475f..2083b0842b 100644 --- a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs +++ b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs @@ -29,7 +29,7 @@ namespace UnityEngine.InputSystem.LowLevel /// /// The class listens to changes on the given controls by adding change monitors () /// to each control. - /// + /// /// /// /// // Track all stick controls in the system. @@ -54,7 +54,7 @@ namespace UnityEngine.InputSystem.LowLevel /// history.Dispose(); /// /// - /// + /// public class InputStateHistory : IDisposable, IEnumerable, IInputStateChangeMonitor { private const int kDefaultHistorySize = 128; @@ -62,30 +62,34 @@ public class InputStateHistory : IDisposable, IEnumerable /// Total number of state records currently captured in the history. /// - /// Number of records in the collection. /// + /// Number of records in the collection. + /// /// This will always be at most . + /// To record a change use . /// - /// - /// public int Count => m_RecordCount; /// /// Current version stamp. Every time a record is stored in the history, /// this is incremented by one. /// - /// Version stamp that indicates the number of mutations. - /// + /// + /// Version stamp that indicates the number of mutations. + /// To record a change use . + /// public uint version => m_CurrentVersion; /// /// Maximum number of records that can be recorded in the history. /// - /// Upper limit on number of records. /// is negative. /// + /// Upper limit on number of records. /// A fixed size memory block of unmanaged memory will be allocated to store history - /// records. This property determines TODO + /// records. + /// When the history is full, it will start overwriting the oldest + /// entry each time a new history record is received. /// public int historyDepth { @@ -100,6 +104,15 @@ public int historyDepth } } + /// + /// Size of additional data storage to allocate per record. + /// + /// is negative. + /// + /// Additional custom data can be stored per record up to the size of this value. + /// To retrieve a pointer to this memory use + /// Used by + /// public int extraMemoryPerRecord { get => m_ExtraMemoryPerRecord; @@ -113,6 +126,14 @@ public int extraMemoryPerRecord } } + /// + /// Specify which player loop positions the state history will be monitored for. + /// + /// When an invalid mask is provided (e.g. ). + /// + /// The state history will only be monitored for the specified player loop positions. + /// is excluded from this list + /// public InputUpdateType updateMask { get => m_UpdateMask ?? InputSystem.s_Manager.updateMask & ~InputUpdateType.Editor; @@ -124,8 +145,22 @@ public InputUpdateType updateMask } } + /// + /// List of input controls the state history will be recording for. + /// + /// + /// The list of input controls the state history will be recording for is specified on construction of the + /// public ReadOnlyArray controls => new ReadOnlyArray(m_Controls, 0, m_ControlCount); + /// + /// Returns an entry in the state history at the given index. + /// + /// Index into the array. + /// + /// Returns a entry from the state history at the given index. + /// + /// is less than 0 or greater than . public unsafe Record this[int index] { get @@ -148,9 +183,34 @@ public unsafe Record this[int index] } } + /// + /// Optional delegate to perform when a record is added to the history array. + /// + /// + /// Can be used to fill in the extra memory with custom data using + /// public Action onRecordAdded { get; set; } + + /// + /// Optional delegate to decide whether the state change should be stored in the history. + /// + /// + /// Can be used to filter out some events to focus on recording the ones you are most interested in. + /// + /// If the callback returns true, a record will be added to the history + /// If the callback returns false, the event will be ignored and not recorded. + /// public Func onShouldRecordStateChange { get; set; } + /// + /// Creates a new InputStateHistory class to record all control state changes. + /// + /// Maximum size of control state in the record entries. Controls with larger state will not be recorded. + /// + /// Creates a new InputStateHistory to record a history of control state changes. + /// + /// New controls are automatically added into the state history if there state is smaller than the threshold. + /// public InputStateHistory(int maxStateSizeInBytes) { if (maxStateSizeInBytes <= 0) @@ -160,6 +220,19 @@ public InputStateHistory(int maxStateSizeInBytes) m_StateSizeInBytes = maxStateSizeInBytes.AlignToMultipleOf(4); } + /// + /// Creates a new InputStateHistory class to record state changes for a specified control. + /// + /// Control path to identify which controls to monitor. + /// + /// Creates a new InputStateHistory to record a history of state changes for the specified controls. + /// + /// + /// + /// // Track all stick controls in the system. + /// var history = new InputStateHistory("*/<Stick>"); + /// + /// public InputStateHistory(string path) { using (var controls = InputSystem.FindControls(path)) @@ -169,6 +242,13 @@ public InputStateHistory(string path) } } + /// + /// Creates a new InputStateHistory class to record state changes for a specified control. + /// + /// Control to monitor. + /// + /// Creates a new InputStateHistory to record a history of state changes for the specified control. + /// public InputStateHistory(InputControl control) { if (control == null) @@ -178,6 +258,13 @@ public InputStateHistory(InputControl control) m_ControlCount = 1; } + /// + /// Creates a new InputStateHistory class to record state changes for a specified controls. + /// + /// Controls to monitor. + /// + /// Creates a new InputStateHistory to record a history of state changes for the specified controls. + /// public InputStateHistory(IEnumerable controls) { if (controls != null) @@ -187,11 +274,22 @@ public InputStateHistory(IEnumerable controls) } } + /// + /// InputStateHistory destructor. + /// ~InputStateHistory() { Dispose(); } + /// + /// Clear the history record. + /// + /// + /// Clear the history record. Resetting the list to empty. + /// + /// This won't clear controls that have been added on the fly. + /// public void Clear() { m_HeadIndex = 0; @@ -201,6 +299,15 @@ public void Clear() // NOTE: Won't clear controls that have been added on the fly. } + /// + /// Add a record to the input state history. + /// + /// Record to add. + /// The newly added record from the history array (as a copy is made). + /// + /// Add a record to the input state history. + /// Allocates an entry in the history array and returns this copy of the original data passed to the function. + /// public unsafe Record AddRecord(Record record) { var recordPtr = AllocateRecord(out var index); @@ -209,6 +316,21 @@ public unsafe Record AddRecord(Record record) return newRecord; } + /// + /// Start recording state history for the specified controls. + /// + /// + /// Start recording state history for the controls specified in the constructor. + /// + /// + /// + /// using (var allTouchTaps = new InputStateHistory("<Touchscreen>/touch*/tap")) + /// { + /// allTouchTaps.StartRecording(); + /// allTouchTaps.StopRecording(); + /// } + /// + /// public void StartRecording() { // We defer allocation until we actually get values on a control. @@ -217,12 +339,38 @@ public void StartRecording() InputState.AddChangeMonitor(control, this); } + /// + /// Stop recording state history for the specified controls. + /// + /// + /// Stop recording state history for the controls specified in the constructor. + /// + /// + /// + /// using (var allTouchTaps = new InputStateHistory("<Touchscreen>/touch*/tap")) + /// { + /// allTouchTaps.StartRecording(); + /// allTouchTaps.StopRecording(); + /// } + /// + /// public void StopRecording() { foreach (var control in controls) InputState.RemoveChangeMonitor(control, this); } + /// + /// Record a state change for a specific control. + /// + /// The control to record the state change for. + /// The current event data to record. + /// The newly added record. + /// + /// Record a state change for a specific control. + /// Will call the delegate after adding the record. + /// Note this does not call the delegate. + /// public unsafe Record RecordStateChange(InputControl control, InputEventPtr eventPtr) { if (eventPtr.IsA()) @@ -236,6 +384,18 @@ public unsafe Record RecordStateChange(InputControl control, InputEventPtr event return RecordStateChange(control, statePtr, eventPtr.time); } + /// + /// Record a state change for a specific control. + /// + /// The control to record the state change for. + /// The current event data to record. + /// Time stamp to apply (overriding the event timestamp) + /// The newly added record. + /// + /// Record a state change for a specific control. + /// Will call the delegate after adding the record. + /// Note this does not call the delegate. + /// public unsafe Record RecordStateChange(InputControl control, void* statePtr, double time) { var controlIndex = ArrayHelpers.IndexOfReference(m_Controls, control, m_ControlCount); @@ -277,16 +437,37 @@ public unsafe Record RecordStateChange(InputControl control, void* statePtr, dou return record; } + /// + /// Enumerate all state history records. + /// + /// An enumerator going over the state history records. + /// + /// Enumerate all state history records. + /// + /// public IEnumerator GetEnumerator() { return new Enumerator(this); } + /// + /// Enumerate all state history records. + /// + /// An enumerator going over the state history records. + /// + /// Enumerate all state history records. + /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + /// + /// Dispose of the state history records. + /// + /// + /// Stops recording and cleans up the state history + /// public void Dispose() { StopRecording(); @@ -399,6 +580,18 @@ protected unsafe object ReadValueAsObject(RecordHeader* data) return control.ReadValueFromStateAsObject(statePtr); } + /// + /// Delegate to list to control state change notifications. + /// + /// Control that is being monitored by the state change monitor and that had its state memory changed. + /// Time on the timeline at which the control state change was received. + /// If the state change was initiated by a state event (either a + /// or ), this is the pointer to that event. Otherwise, it is pointer that is still + /// , but refers a "dummy" event that is not a or . + /// Index of the monitor as passed to + /// + /// Records a state change after checking the and the callback. + /// unsafe void IInputStateChangeMonitor.NotifyControlStateChanged(InputControl control, double time, InputEventPtr eventPtr, long monitorIndex) { @@ -416,6 +609,15 @@ unsafe void IInputStateChangeMonitor.NotifyControlStateChanged(InputControl cont } // Unused. + /// + /// Called when a timeout set on a state change monitor has expired. + /// + /// Control on which the timeout expired. + /// Input time at which the timer expired. This is the time at which an is being + /// run whose is past the time of expiration. + /// Index of the monitor as given to . + /// Index of the timer as given to . + /// void IInputStateChangeMonitor.NotifyTimerExpired(InputControl control, double time, long monitorIndex, int timerIndex) { @@ -505,6 +707,9 @@ public byte* statePtrWithoutControlIndex public const int kSizeWithoutControlIndex = 12; } + /// State change record + /// Input State change record stored in the + /// public unsafe struct Record : IEquatable { // We store an index rather than a direct pointer to make this struct safer to use. @@ -516,10 +721,31 @@ public unsafe struct Record : IEquatable internal int recordIndex => m_IndexPlusOne - 1; internal uint version => m_Version; + /// + /// Identifies if the record is valid. + /// + /// True if the record is a valid entry. False if invalid. + /// + /// When the history is cleared with the entries become invalid. + /// public bool valid => m_Owner != default && m_IndexPlusOne != default && header->version == m_Version; + /// + /// Identifies the owning container for the record. + /// + /// The owning container for the record. + /// + /// Identifies the owning container for the record. + /// public InputStateHistory owner => m_Owner; + /// + /// The index of the input state record in the owning container. + /// + /// + /// The index of the input state record in the owning container. + /// + /// When the record is no longer value. public int index { get @@ -529,6 +755,14 @@ public int index } } + /// + /// The time stamp of the input state record. + /// + /// + /// The time stamp of the input state record in the owning container. + /// + /// + /// When the record is no longer value. public double time { get @@ -538,6 +772,13 @@ public double time } } + /// + /// The control associated with the input state record. + /// + /// + /// The control associated with the input state record. + /// + /// When the record is no longer value. public InputControl control { get @@ -550,6 +791,13 @@ public InputControl control } } + /// + /// The next input state record in the owning container. + /// + /// + /// The next input state record in the owning container. + /// + /// When the record is no longer value. public Record next { get @@ -563,6 +811,13 @@ public Record next } } + /// + /// The previous input state record in the owning container. + /// + /// + /// The previous input state record in the owning container. + /// + /// When the record is no longer value. public Record previous { get @@ -583,6 +838,11 @@ internal Record(InputStateHistory owner, int index, RecordHeader* header) m_Version = header->version; } + /// + /// Returns value from the control in the Record. + /// + /// Returns value from the Record. + /// When the record is no longer value or the specified type is not present. public TValue ReadValue() where TValue : struct { @@ -590,12 +850,26 @@ public TValue ReadValue() return m_Owner.ReadValue(header); } + /// + /// Read the control's final, processed value from the given state and return the value as an object. + /// + /// The value of the control associated with the record. + /// + /// This method allocates GC memory and should not be used during normal gameplay operation. + /// + /// When the specified value is not present. public object ReadValueAsObject() { CheckValid(); return m_Owner.ReadValueAsObject(header); } + /// + /// Read the state memory for the record. + /// + /// The state memory for the record. + /// + /// public void* GetUnsafeMemoryPtr() { CheckValid(); @@ -609,6 +883,14 @@ public object ReadValueAsObject() return header->statePtrWithControlIndex; } + /// + /// Read the extra memory for the record. + /// + /// The extra memory for the record. + /// + /// Additional date can be stored in a record in the extra memory section. + /// + /// public void* GetUnsafeExtraMemoryPtr() { CheckValid(); @@ -622,6 +904,13 @@ public object ReadValueAsObject() return (byte*)header + m_Owner.bytesPerRecord - m_Owner.extraMemoryPerRecord; } + /// Copy data from one record to another. + /// Source Record to copy from. + /// + /// Copy data from one record to another. + /// + /// When the source record history is not valid. + /// When the control is not tracked by the owning container. public void CopyFrom(Record record) { if (!record.valid) @@ -686,16 +975,27 @@ internal void CheckValid() throw new InvalidOperationException("Record is no longer valid"); } + /// Compare two records. + /// Compare two records. + /// The record to compare with. + /// True if the records are the same, False if they differ. public bool Equals(Record other) { return ReferenceEquals(m_Owner, other.m_Owner) && m_IndexPlusOne == other.m_IndexPlusOne && m_Version == other.m_Version; } + /// Compare two records. + /// Compare two records. + /// The record to compare with. + /// True if the records are the same, False if they differ. public override bool Equals(object obj) { return obj is Record other && Equals(other); } + /// Return the hash code of the record. + /// Return the hash code of the record. + /// The hash code of the record. public override int GetHashCode() { unchecked @@ -707,6 +1007,9 @@ public override int GetHashCode() } } + /// Return the string representation of the record. + /// Includes the control, value and time of the record (or <Invalid> if not valid). + /// The string representation of the record. public override string ToString() { if (!valid) @@ -720,10 +1023,27 @@ public override string ToString() /// /// Records value changes of a given control over time. /// + /// + /// This class makes it easy to track input values over time. It will automatically retain input state up to a given + /// maximum history depth (). When the history is full, it will start overwriting the oldest + /// entry each time a new history record is received. + /// + /// The class listens to changes on the given controls by adding change monitors () + /// to each control. + /// /// public class InputStateHistory : InputStateHistory, IReadOnlyList.Record> where TValue : struct { + /// + /// Creates a new InputStateHistory class to record all control state changes. + /// + /// Maximum size of control state in the record entries. Controls with larger state will not be recorded. + /// + /// Creates a new InputStateHistory to record a history of control state changes. + /// + /// New controls are automatically added into the state history if there state is smaller than the threshold. + /// public InputStateHistory(int? maxStateSizeInBytes = null) // Using the size of the value here isn't quite correct but the value is used as an upper // bound on stored state size for which the size of the value should be a reasonable guess. @@ -733,11 +1053,31 @@ public InputStateHistory(int? maxStateSizeInBytes = null) throw new ArgumentException("Max state size cannot be smaller than sizeof(TValue)", nameof(maxStateSizeInBytes)); } + /// + /// Creates a new InputStateHistory class to record state changes for a specified control. + /// + /// Control to monitor. + /// + /// Creates a new InputStateHistory to record a history of state changes for the specified control. + /// public InputStateHistory(InputControl control) : base(control) { } + /// + /// Creates a new InputStateHistory class to record state changes for a specified control. + /// + /// Control path to identify which controls to monitor. + /// + /// Creates a new InputStateHistory to record a history of state changes for the specified controls. + /// + /// + /// + /// // Track all stick controls in the system. + /// var history = new InputStateHistory<Vector2>("*/<Stick>"); + /// + /// public InputStateHistory(string path) : base(path) { @@ -748,11 +1088,23 @@ public InputStateHistory(string path) $"Control '{control}' matched by '{path}' has value type '{TypeHelpers.GetNiceTypeName(control.valueType)}' which is incompatible with '{TypeHelpers.GetNiceTypeName(typeof(TValue))}'"); } + /// + /// InputStateHistory destructor. + /// ~InputStateHistory() { Destroy(); } + /// + /// Add a record to the input state history. + /// + /// Record to add. + /// The newly added record from the history array (as a copy is made). + /// + /// Add a record to the input state history. + /// Allocates an entry in the history array and returns this copy of the original data passed to the function. + /// public unsafe Record AddRecord(Record record) { var recordPtr = AllocateRecord(out var index); @@ -761,6 +1113,26 @@ public unsafe Record AddRecord(Record record) return newRecord; } + /// + /// Record a state change for a specific control. + /// + /// The control to record the state change for. + /// The current event data to record. + /// Time stamp to apply (overriding the event timestamp) + /// The newly added record. + /// + /// Record a state change for a specific control. + /// Will call the delegate after adding the record. + /// Note this does not call the delegate. + /// + /// + /// + /// using (var allTouchTaps = new InputStateHistory<float>(Gamepad.current.leftTrigger)) + /// { + /// history.RecordStateChange(Gamepad.current.leftTrigger, 0.234f); + /// } + /// + /// public unsafe Record RecordStateChange(InputControl control, TValue value, double time = -1) { using (StateEvent.From(control.device, out var eventPtr)) @@ -774,16 +1146,39 @@ public unsafe Record RecordStateChange(InputControl control, TValue valu } } + /// + /// Enumerate all state history records. + /// + /// An enumerator going over the state history records. + /// + /// Enumerate all state history records. + /// + /// public new IEnumerator GetEnumerator() { return new Enumerator(this); } + /// + /// Enumerate all state history records. + /// + /// An enumerator going over the state history records. + /// + /// Enumerate all state history records. + /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + /// + /// Returns an entry in the state history at the given index. + /// + /// Index into the array. + /// + /// Returns a entry from the state history at the given index. + /// + /// is less than 0 or greater than . public new unsafe Record this[int index] { get @@ -838,6 +1233,9 @@ public void Dispose() } } + /// State change record + /// Input State change record stored in the + /// public new unsafe struct Record : IEquatable { private readonly InputStateHistory m_Owner; @@ -847,10 +1245,31 @@ public void Dispose() internal RecordHeader* header => m_Owner.GetRecord(recordIndex); internal int recordIndex => m_IndexPlusOne - 1; + /// + /// Identifies if the record is valid. + /// + /// True if the record is a valid entry. False if invalid. + /// + /// When the history is cleared with the entries become invalid. + /// public bool valid => m_Owner != default && m_IndexPlusOne != default && header->version == m_Version; + /// + /// Identifies the owning container for the record. + /// + /// The owning container for the record. + /// + /// Identifies the owning container for the record. + /// public InputStateHistory owner => m_Owner; + /// + /// The index of the input state record in the owning container. + /// + /// + /// The index of the input state record in the owning container. + /// + /// When the record is no longer value. public int index { get @@ -860,6 +1279,14 @@ public int index } } + /// + /// The time stamp of the input state record. + /// + /// + /// The time stamp of the input state record in the owning container. + /// + /// + /// When the record is no longer value. public double time { get @@ -869,6 +1296,13 @@ public double time } } + /// + /// The control associated with the input state record. + /// + /// + /// The control associated with the input state record. + /// + /// When the record is no longer value. public InputControl control { get @@ -881,6 +1315,13 @@ public InputControl control } } + /// + /// The next input state record in the owning container. + /// + /// + /// The next input state record in the owning container. + /// + /// When the record is no longer value. public Record next { get @@ -894,6 +1335,13 @@ public Record next } } + /// + /// The previous input state record in the owning container. + /// + /// + /// The previous input state record in the owning container. + /// + /// When the record is no longer value. public Record previous { get @@ -921,12 +1369,23 @@ internal Record(InputStateHistory owner, int index) m_Version = default; } + /// + /// Returns value from the control in the Record. + /// + /// Returns value from the Record. + /// When the record is no longer value or the specified type is not present. public TValue ReadValue() { CheckValid(); return m_Owner.ReadValue(header); } + /// + /// Read the state memory for the record. + /// + /// The state memory for the record. + /// + /// public void* GetUnsafeMemoryPtr() { CheckValid(); @@ -940,6 +1399,14 @@ public TValue ReadValue() return header->statePtrWithControlIndex; } + /// + /// Read the extra memory for the record. + /// + /// The extra memory for the record. + /// + /// Additional date can be stored in a record in the extra memory section. + /// + /// public void* GetUnsafeExtraMemoryPtr() { CheckValid(); @@ -953,6 +1420,13 @@ public TValue ReadValue() return (byte*)header + m_Owner.bytesPerRecord - m_Owner.extraMemoryPerRecord; } + /// Copy data from one record to another. + /// Source Record to copy from. + /// + /// Copy data from one record to another. + /// + /// When the source record history is not valid. + /// When the control is not tracked by the owning container. public void CopyFrom(Record record) { CheckValid(); @@ -971,16 +1445,27 @@ private void CheckValid() throw new InvalidOperationException("Record is no longer valid"); } + /// Compare two records. + /// Compare two records. + /// The record to compare with. + /// True if the records are the same, False if they differ. public bool Equals(Record other) { return ReferenceEquals(m_Owner, other.m_Owner) && m_IndexPlusOne == other.m_IndexPlusOne && m_Version == other.m_Version; } + /// Compare two records. + /// Compare two records. + /// The record to compare with. + /// True if the records are the same, False if they differ. public override bool Equals(object obj) { return obj is Record other && Equals(other); } + /// Return the hash code of the record. + /// Return the hash code of the record. + /// The hash code of the record. public override int GetHashCode() { unchecked @@ -992,6 +1477,9 @@ public override int GetHashCode() } } + /// Return the string representation of the record. + /// Includes the control, value and time of the record (or <Invalid> if not valid). + /// The string representation of the record. public override string ToString() { if (!valid) From 62e025a05f3b318f3cbd9c706048297604fdbaea Mon Sep 17 00:00:00 2001 From: Lyndon Homewood Date: Wed, 4 Dec 2024 18:08:01 +0000 Subject: [PATCH 2/5] Fixing failing documentation tests from CI --- .../InputSystem/State/InputStateHistory.cs | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs index 2083b0842b..12c0f27924 100644 --- a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs +++ b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs @@ -724,7 +724,7 @@ public unsafe struct Record : IEquatable /// /// Identifies if the record is valid. /// - /// True if the record is a valid entry. False if invalid. + /// True if the record is a valid entry. False if invalid. /// /// When the history is cleared with the entries become invalid. /// @@ -733,7 +733,7 @@ public unsafe struct Record : IEquatable /// /// Identifies the owning container for the record. /// - /// The owning container for the record. + /// The owning container for the record. /// /// Identifies the owning container for the record. /// @@ -742,9 +742,9 @@ public unsafe struct Record : IEquatable /// /// The index of the input state record in the owning container. /// - /// + /// /// The index of the input state record in the owning container. - /// + /// /// When the record is no longer value. public int index { @@ -758,10 +758,10 @@ public int index /// /// The time stamp of the input state record. /// - /// + /// /// The time stamp of the input state record in the owning container. /// - /// + /// /// When the record is no longer value. public double time { @@ -775,9 +775,9 @@ public double time /// /// The control associated with the input state record. /// - /// + /// /// The control associated with the input state record. - /// + /// /// When the record is no longer value. public InputControl control { @@ -794,9 +794,9 @@ public InputControl control /// /// The next input state record in the owning container. /// - /// + /// /// The next input state record in the owning container. - /// + /// /// When the record is no longer value. public Record next { @@ -814,9 +814,9 @@ public Record next /// /// The previous input state record in the owning container. /// - /// + /// /// The previous input state record in the owning container. - /// + /// /// When the record is no longer value. public Record previous { @@ -841,6 +841,7 @@ internal Record(InputStateHistory owner, int index, RecordHeader* header) /// /// Returns value from the control in the Record. /// + /// /// Returns value from the Record. /// When the record is no longer value or the specified type is not present. public TValue ReadValue() @@ -869,6 +870,7 @@ public object ReadValueAsObject() /// /// The state memory for the record. /// + /// Read the state memory for the record. /// public void* GetUnsafeMemoryPtr() { @@ -890,7 +892,7 @@ public object ReadValueAsObject() /// /// Additional date can be stored in a record in the extra memory section. /// - /// + /// public void* GetUnsafeExtraMemoryPtr() { CheckValid(); @@ -1117,7 +1119,7 @@ public unsafe Record AddRecord(Record record) /// Record a state change for a specific control. /// /// The control to record the state change for. - /// The current event data to record. + /// The value to record. /// Time stamp to apply (overriding the event timestamp) /// The newly added record. /// @@ -1248,7 +1250,7 @@ public void Dispose() /// /// Identifies if the record is valid. /// - /// True if the record is a valid entry. False if invalid. + /// True if the record is a valid entry. False if invalid. /// /// When the history is cleared with the entries become invalid. /// @@ -1257,7 +1259,7 @@ public void Dispose() /// /// Identifies the owning container for the record. /// - /// The owning container for the record. + /// The owning container for the record. /// /// Identifies the owning container for the record. /// @@ -1266,9 +1268,9 @@ public void Dispose() /// /// The index of the input state record in the owning container. /// - /// + /// /// The index of the input state record in the owning container. - /// + /// /// When the record is no longer value. public int index { @@ -1282,10 +1284,10 @@ public int index /// /// The time stamp of the input state record. /// - /// + /// /// The time stamp of the input state record in the owning container. /// - /// + /// /// When the record is no longer value. public double time { @@ -1299,9 +1301,9 @@ public double time /// /// The control associated with the input state record. /// - /// + /// /// The control associated with the input state record. - /// + /// /// When the record is no longer value. public InputControl control { @@ -1318,9 +1320,9 @@ public InputControl control /// /// The next input state record in the owning container. /// - /// + /// /// The next input state record in the owning container. - /// + /// /// When the record is no longer value. public Record next { @@ -1338,9 +1340,9 @@ public Record next /// /// The previous input state record in the owning container. /// - /// + /// /// The previous input state record in the owning container. - /// + /// /// When the record is no longer value. public Record previous { @@ -1385,6 +1387,7 @@ public TValue ReadValue() /// /// The state memory for the record. /// + /// Read the state memory for the record. /// public void* GetUnsafeMemoryPtr() { @@ -1406,7 +1409,7 @@ public TValue ReadValue() /// /// Additional date can be stored in a record in the extra memory section. /// - /// + /// public void* GetUnsafeExtraMemoryPtr() { CheckValid(); From 1c08e0316c8c2c91ff3032ff52d2232fa73da196 Mon Sep 17 00:00:00 2001 From: Lyndon Homewood Date: Thu, 5 Dec 2024 08:24:12 +0000 Subject: [PATCH 3/5] Corrected RecordStateChange parameter and missing typename explanation --- .../InputSystem/State/InputStateHistory.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs index 12c0f27924..e22515fb91 100644 --- a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs +++ b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs @@ -388,7 +388,7 @@ public unsafe Record RecordStateChange(InputControl control, InputEventPtr event /// Record a state change for a specific control. /// /// The control to record the state change for. - /// The current event data to record. + /// The current state data to record. /// Time stamp to apply (overriding the event timestamp) /// The newly added record. /// @@ -841,7 +841,7 @@ internal Record(InputStateHistory owner, int index, RecordHeader* header) /// /// Returns value from the control in the Record. /// - /// + /// The type of the value being read /// Returns value from the Record. /// When the record is no longer value or the specified type is not present. public TValue ReadValue() @@ -1025,6 +1025,7 @@ public override string ToString() /// /// Records value changes of a given control over time. /// + /// The type of the record being stored /// /// This class makes it easy to track input values over time. It will automatically retain input state up to a given /// maximum history depth (). When the history is full, it will start overwriting the oldest @@ -1033,7 +1034,6 @@ public override string ToString() /// The class listens to changes on the given controls by adding change monitors () /// to each control. /// - /// public class InputStateHistory : InputStateHistory, IReadOnlyList.Record> where TValue : struct { From 4413a001ac6e760b48b199b60c2de7f54ed17fb2 Mon Sep 17 00:00:00 2001 From: Lyndon Homewood Date: Thu, 5 Dec 2024 12:47:49 +0000 Subject: [PATCH 4/5] Documented protected functions And removed some upper case on Record references in documentation --- .../InputSystem/State/InputStateHistory.cs | 127 +++++++++++++++++- 1 file changed, 123 insertions(+), 4 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs index e22515fb91..6cae98c7bd 100644 --- a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs +++ b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs @@ -475,6 +475,12 @@ public void Dispose() GC.SuppressFinalize(this); } + /// + /// Destroy the state history records. + /// + /// + /// Deletes the state history records. + /// protected void Destroy() { if (m_RecordBuffer.IsCreated) @@ -506,6 +512,15 @@ private void Allocate() NativeArrayOptions.UninitializedMemory); } + /// + /// Remap a records internal index to an index from the start of the recording in the circular buffer. + /// + /// + /// Remap a records internal index, which is relative to the start of the record buffer, + /// to an index relative to the start of the recording in the circular buffer. + /// + /// Record index (from the start of the record array). + /// An index relative to the start of the recording in the circular buffer. protected internal int RecordIndexToUserIndex(int index) { if (index < m_HeadIndex) @@ -513,11 +528,30 @@ protected internal int RecordIndexToUserIndex(int index) return index - m_HeadIndex; } + /// + /// Remap an index from the start of the recording in the circular buffer to a records internal index. + /// + /// + /// Remap an index relative to the start of the recording in the circular buffer, + /// to a records internal index, which is relative to the start of the record buffer. + /// + /// An index relative to the start of the recording in the circular buffer. + /// Record index (from the start of the record array). protected internal int UserIndexToRecordIndex(int index) { return (m_HeadIndex + index) % m_HistoryDepth; } + /// + /// Retrieve a record from the input state history. + /// + /// + /// Retrieve a record from the input state history by Record index. + /// + /// Record index into the input state history records buffer. + /// The record header for the specified index + /// When the buffer is no longer valid as it has been disposed. + /// If the index is out of range of the history depth. protected internal unsafe RecordHeader* GetRecord(int index) { if (!m_RecordBuffer.IsCreated) @@ -527,11 +561,27 @@ protected internal int UserIndexToRecordIndex(int index) return GetRecordUnchecked(index); } + /// + /// Retrieve a record from the input state history, without any bounds check. + /// + /// + /// Retrieve a record from the input state history by record index, without any bounds check + /// + /// Record index into the input state history records buffer. + /// The record header for the specified index internal unsafe RecordHeader* GetRecordUnchecked(int index) { return (RecordHeader*)((byte*)m_RecordBuffer.GetUnsafePtr() + index * bytesPerRecord); } + /// + /// Allocate a new record in the input state history. + /// + /// + /// Allocate a new record in the input state history. + /// + /// The index of the newly created record + /// The header of the newly created record protected internal unsafe RecordHeader* AllocateRecord(out int index) { if (!m_RecordBuffer.IsCreated) @@ -552,6 +602,13 @@ protected internal int UserIndexToRecordIndex(int index) return (RecordHeader*)((byte*)m_RecordBuffer.GetUnsafePtr() + bytesPerRecord * index); } + /// + /// Returns value from the control in the specified record header. + /// + /// The record header to query. + /// The type of the value being read + /// The value from the record. + /// When the record is no longer value or the specified type is not present. protected unsafe TValue ReadValue(RecordHeader* data) where TValue : struct { @@ -568,6 +625,15 @@ protected unsafe TValue ReadValue(RecordHeader* data) return controlOfType.ReadValueFromState(statePtr); } + /// + /// Read the control's final, processed value from the given state and return the value as an object. + /// + /// The record header to query. + /// The value of the control associated with the record header. + /// + /// This method allocates GC memory and should not be used during normal gameplay operation. + /// + /// When the specified value is not present. protected unsafe object ReadValueAsObject(RecordHeader* data) { // Get control. If we only have a single one, the index isn't stored on the data. @@ -675,16 +741,50 @@ public void Dispose() } } + /// State change record header + /// + /// Input State change record header containing the timestamp and other common record data. + /// Stored in the . + /// + /// [StructLayout(LayoutKind.Explicit)] protected internal unsafe struct RecordHeader { + /// + /// The time stamp of the input state record. + /// + /// + /// The time stamp of the input state record in the owning container. + /// + /// [FieldOffset(0)] public double time; + + /// + /// The version of the input state record. + /// + /// + /// Current version stamp. See . + /// [FieldOffset(8)] public uint version; + + /// + /// The index of the record. + /// + /// + /// The index of the record relative to the start of the buffer. + /// See to remap this record index to a user index. + /// [FieldOffset(12)] public int controlIndex; [FieldOffset(12)] private fixed byte m_StateWithoutControlIndex[1]; [FieldOffset(16)] private fixed byte m_StateWithControlIndex[1]; + /// + /// The state data including the control index. + /// + /// + /// The state data including the control index. + /// public byte* statePtrWithControlIndex { get @@ -694,6 +794,12 @@ public byte* statePtrWithControlIndex } } + /// + /// The state data excluding the control index. + /// + /// + /// The state data excluding the control index. + /// public byte* statePtrWithoutControlIndex { get @@ -703,12 +809,25 @@ public byte* statePtrWithoutControlIndex } } + /// + /// Size of the state data including the control index. + /// + /// + /// Size of the data including the control index. + /// public const int kSizeWithControlIndex = 16; + + /// + /// Size of the state data excluding the control index. + /// + /// + /// Size of the data excluding the control index. + /// public const int kSizeWithoutControlIndex = 12; } /// State change record - /// Input State change record stored in the + /// Input State change record stored in the . /// public unsafe struct Record : IEquatable { @@ -839,10 +958,10 @@ internal Record(InputStateHistory owner, int index, RecordHeader* header) } /// - /// Returns value from the control in the Record. + /// Returns value from the control in the record. /// /// The type of the value being read - /// Returns value from the Record. + /// Returns the value from the record. /// When the record is no longer value or the specified type is not present. public TValue ReadValue() where TValue : struct @@ -907,7 +1026,7 @@ public object ReadValueAsObject() } /// Copy data from one record to another. - /// Source Record to copy from. + /// Source record to copy from. /// /// Copy data from one record to another. /// From f2a52dacee1022c1f0bd624d2a741994b788ce7f Mon Sep 17 00:00:00 2001 From: Ben Pitt Date: Mon, 9 Dec 2024 09:50:09 +0000 Subject: [PATCH 5/5] fixed typo --- .../InputSystem/State/InputStateHistory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs index 6cae98c7bd..1cd3f4a620 100644 --- a/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs +++ b/Packages/com.unity.inputsystem/InputSystem/State/InputStateHistory.cs @@ -209,7 +209,7 @@ public unsafe Record this[int index] /// /// Creates a new InputStateHistory to record a history of control state changes. /// - /// New controls are automatically added into the state history if there state is smaller than the threshold. + /// New controls are automatically added into the state history if their state is smaller than the threshold. /// public InputStateHistory(int maxStateSizeInBytes) {