A game about forced loneliness, made by TACStudios
1using System; 2using System.Runtime.InteropServices; 3using Unity.Collections; 4using Unity.Collections.LowLevel.Unsafe; 5using UnityEngine.InputSystem.Utilities; 6 7namespace UnityEngine.InputSystem.LowLevel 8{ 9 /// <summary> 10 /// Partial state update for an input device. 11 /// </summary> 12 /// <remarks> 13 /// Avoids having to send a full state memory snapshot when only a small 14 /// part of the state has changed. 15 /// </remarks> 16 [StructLayout(LayoutKind.Explicit, Pack = 1, Size = InputEvent.kBaseEventSize + 9)] 17 public unsafe struct DeltaStateEvent : IInputEventTypeInfo 18 { 19 public const int Type = 0x444C5441; // 'DLTA' 20 21 [FieldOffset(0)] 22 public InputEvent baseEvent; 23 24 [FieldOffset(InputEvent.kBaseEventSize)] 25 public FourCC stateFormat; 26 27 [FieldOffset(InputEvent.kBaseEventSize + 4)] 28 public uint stateOffset; 29 30 [FieldOffset(InputEvent.kBaseEventSize + 8)] 31 internal fixed byte stateData[1]; // Variable-sized. 32 33 public uint deltaStateSizeInBytes => baseEvent.sizeInBytes - (InputEvent.kBaseEventSize + 8); 34 35 public void* deltaState 36 { 37 get 38 { 39 fixed(byte* data = stateData) 40 { 41 return data; 42 } 43 } 44 } 45 46 public FourCC typeStatic => Type; 47 48 public InputEventPtr ToEventPtr() 49 { 50 fixed(DeltaStateEvent * ptr = &this) 51 { 52 return new InputEventPtr((InputEvent*)ptr); 53 } 54 } 55 56 public static DeltaStateEvent* From(InputEventPtr ptr) 57 { 58 if (!ptr.valid) 59 throw new ArgumentNullException(nameof(ptr)); 60 if (!ptr.IsA<DeltaStateEvent>()) 61 throw new InvalidCastException($"Cannot cast event with type '{ptr.type}' into DeltaStateEvent"); 62 63 return FromUnchecked(ptr); 64 } 65 66 internal static DeltaStateEvent* FromUnchecked(InputEventPtr ptr) 67 { 68 return (DeltaStateEvent*)ptr.data; 69 } 70 71 public static NativeArray<byte> From(InputControl control, out InputEventPtr eventPtr, Allocator allocator = Allocator.Temp) 72 { 73 if (control == null) 74 throw new ArgumentNullException(nameof(control)); 75 var device = control.device; 76 if (!device.added) 77 throw new ArgumentException($"Device for control '{control}' has not been added to system", 78 nameof(control)); 79 80 ref var deviceStateBlock = ref device.m_StateBlock; 81 ref var controlStateBlock = ref control.m_StateBlock; 82 83 var stateFormat = deviceStateBlock.format; // The event is sent against the *device* so that's the state format we use. 84 var stateSize = 0u; 85 if (controlStateBlock.bitOffset != 0) 86 stateSize = (controlStateBlock.bitOffset + controlStateBlock.sizeInBits + 7) / 8; 87 else 88 stateSize = controlStateBlock.alignedSizeInBytes; 89 var stateOffset = controlStateBlock.byteOffset; 90 var statePtr = (byte*)control.currentStatePtr + (int)stateOffset; 91 var eventSize = InputEvent.kBaseEventSize + sizeof(int) * 2 + stateSize; 92 93 var buffer = new NativeArray<byte>((int)eventSize.AlignToMultipleOf(4), allocator); 94 var stateEventPtr = (DeltaStateEvent*)buffer.GetUnsafePtr(); 95 96 stateEventPtr->baseEvent = new InputEvent(Type, (int)eventSize, device.deviceId, InputRuntime.s_Instance.currentTime); 97 stateEventPtr->stateFormat = stateFormat; 98 stateEventPtr->stateOffset = controlStateBlock.byteOffset - deviceStateBlock.byteOffset; // Make offset relative to device. 99 UnsafeUtility.MemCpy(stateEventPtr->deltaState, statePtr, stateSize); 100 101 eventPtr = stateEventPtr->ToEventPtr(); 102 return buffer; 103 } 104 } 105}