diff --git a/managed/src/SwiftlyS2.Shared/Misc/BitFieldHelper.cs b/managed/src/SwiftlyS2.Shared/Misc/BitFieldHelper.cs
index 502e8a0c8..f7962bedd 100644
--- a/managed/src/SwiftlyS2.Shared/Misc/BitFieldHelper.cs
+++ b/managed/src/SwiftlyS2.Shared/Misc/BitFieldHelper.cs
@@ -1,55 +1,55 @@
-namespace SwiftlyS2.Shared.Misc;
+namespace SwiftlyS2.Shared.Misc;
-static class BitFieldHelper
+internal static class BitFieldHelper
{
- public static int GetBits(ref byte data, int index, int bitCount)
+ public static int GetBits( ref byte data, int index, int bitCount )
{
if (index < 0 || index + bitCount > 8) throw new ArgumentOutOfRangeException();
- int mask = (1 << bitCount) - 1;
+ var mask = (1 << bitCount) - 1;
return (data >> index) & mask;
}
- public static void SetBits(ref byte data, int index, int bitCount, int value)
+ public static void SetBits( ref byte data, int index, int bitCount, int value )
{
if (index < 0 || index + bitCount > 8) throw new ArgumentOutOfRangeException();
- int mask = ((1 << bitCount) - 1) << index;
+ var mask = ((1 << bitCount) - 1) << index;
data = (byte)((data & ~mask) | ((value << index) & mask));
}
- public static int GetBits(ref int data, int index, int bitCount)
+ public static int GetBits( ref int data, int index, int bitCount )
{
if (index < 0 || index + bitCount > 32) throw new ArgumentOutOfRangeException();
- int mask = (1 << bitCount) - 1;
+ var mask = (1 << bitCount) - 1;
return (data >> index) & mask;
}
- public static void SetBits(ref int data, int index, int bitCount, int value)
+ public static void SetBits( ref int data, int index, int bitCount, int value )
{
if (index < 0 || index + bitCount > 32) throw new ArgumentOutOfRangeException();
- int mask = ((1 << bitCount) - 1) << index;
+ var mask = ((1 << bitCount) - 1) << index;
data = (data & ~mask) | ((value << index) & mask);
}
- public static long GetBits(ref long data, int index, int bitCount)
+ public static long GetBits( ref long data, int index, int bitCount )
{
if (index < 0 || index + bitCount > 64) throw new ArgumentOutOfRangeException();
- long mask = (1L << bitCount) - 1;
+ var mask = (1L << bitCount) - 1;
return (data >> index) & mask;
}
- public static void SetBits(ref long data, int index, int bitCount, long value)
+ public static void SetBits( ref long data, int index, int bitCount, long value )
{
if (index < 0 || index + bitCount > 64) throw new ArgumentOutOfRangeException();
- long mask = ((1L << bitCount) - 1) << index;
+ var mask = ((1L << bitCount) - 1) << index;
data = (data & ~mask) | ((value << index) & mask);
}
- public static bool GetBit(ref byte data, int index) => GetBits(ref data, index, 1) != 0;
- public static void SetBit(ref byte data, int index, bool value) => SetBits(ref data, index, 1, value ? 1 : 0);
+ public static bool GetBit( ref byte data, int index ) => GetBits(ref data, index, 1) != 0;
+ public static void SetBit( ref byte data, int index, bool value ) => SetBits(ref data, index, 1, value ? 1 : 0);
- public static bool GetBit(ref int data, int index) => GetBits(ref data, index, 1) != 0;
- public static void SetBit(ref int data, int index, bool value) => SetBits(ref data, index, 1, value ? 1 : 0);
+ public static bool GetBit( ref int data, int index ) => GetBits(ref data, index, 1) != 0;
+ public static void SetBit( ref int data, int index, bool value ) => SetBits(ref data, index, 1, value ? 1 : 0);
- public static bool GetBit(ref long data, int index) => GetBits(ref data, index, 1) != 0;
- public static void SetBit(ref long data, int index, bool value) => SetBits(ref data, index, 1, value ? 1 : 0);
+ public static bool GetBit( ref long data, int index ) => GetBits(ref data, index, 1) != 0;
+ public static void SetBit( ref long data, int index, bool value ) => SetBits(ref data, index, 1, value ? 1 : 0);
}
\ No newline at end of file
diff --git a/managed/src/SwiftlyS2.Shared/Natives/Structs/CMoveData.cs b/managed/src/SwiftlyS2.Shared/Natives/Structs/CMoveData.cs
new file mode 100644
index 000000000..3b81c4c9b
--- /dev/null
+++ b/managed/src/SwiftlyS2.Shared/Natives/Structs/CMoveData.cs
@@ -0,0 +1,36 @@
+// Reference: https://github.com/KZGlobalTeam/cs2kz-metamod/blob/8d4038394173f1c10d763346d45cd3ccbc0091aa/src/sdk/datatypes.h#L252-L278
+
+using System.Runtime.InteropServices;
+
+namespace SwiftlyS2.Shared.Natives;
+
+[StructLayout(LayoutKind.Sequential)]
+public unsafe struct CMoveData
+{
+ public CMoveDataBase Base; // class CMoveData : public CMoveDataBase
+
+ public Vector OutWishVel;
+ public QAngle OldAngles;
+
+ ///
+ /// World space input vector. Used to compare against the movement services' previous rotation for ground movement stuff.
+ ///
+ public Vector InputRotated;
+
+ ///
+ /// Continuous acceleration in units per second squared (u/s²).
+ ///
+ public Vector ContinuousAcceleration;
+
+ ///
+ /// Immediate delta in u/s. Air acceleration bypasses per second acceleration,
+ /// applies up to half of its impulse to the velocity and the rest goes straight into this.
+ ///
+ public Vector FrameVelocityDelta;
+
+ public float MaxSpeed;
+ public float ClientMaxSpeed;
+ public float FrictionDecel;
+ public bool InAir;
+ public bool GameCodeMovedPlayer; // true if usercmd cmd number == (m_nGameCodeHasMovedPlayerAfterCommand + 1)
+}
\ No newline at end of file
diff --git a/managed/src/SwiftlyS2.Shared/Natives/Structs/CMoveDataBase.cs b/managed/src/SwiftlyS2.Shared/Natives/Structs/CMoveDataBase.cs
new file mode 100644
index 000000000..93a5a0e02
--- /dev/null
+++ b/managed/src/SwiftlyS2.Shared/Natives/Structs/CMoveDataBase.cs
@@ -0,0 +1,46 @@
+// Reference: https://github.com/KZGlobalTeam/cs2kz-metamod/blob/8d4038394173f1c10d763346d45cd3ccbc0091aa/src/sdk/datatypes.h#L165-L250
+
+using System.Runtime.InteropServices;
+using SwiftlyS2.Shared.Misc;
+using SwiftlyS2.Shared.SchemaDefinitions;
+
+namespace SwiftlyS2.Shared.Natives;
+
+[StructLayout(LayoutKind.Sequential)]
+public unsafe struct CMoveDataBase
+{
+ private byte _bitfield0; // Bitfield members
+
+ public bool HasZeroFrametime {
+ get => BitFieldHelper.GetBit(ref _bitfield0, 0);
+ set => BitFieldHelper.SetBit(ref _bitfield0, 0, value);
+ }
+
+ public bool IsLateCommand {
+ get => BitFieldHelper.GetBit(ref _bitfield0, 1);
+ set => BitFieldHelper.SetBit(ref _bitfield0, 1, value);
+ }
+
+ public CHandle PlayerHandle;
+ public QAngle AbsViewAngles;
+ public QAngle ViewAngles;
+ public Vector LastMovementImpulses;
+ public float ForwardMove;
+ public float SideMove; // Warning! Flipped compared to CS:GO, moving right gives negative value
+ public float UpMove;
+ public Vector Velocity;
+ public QAngle Angles;
+ public Vector Unknown; // Unused. Probably pulled from engine upstream.
+ public CUtlVector SubtickMoves;
+ public CUtlVector AttackSubtickMoves;
+ public bool HasSubtickInputs;
+ public float UnknownFloat; // Set to 1.0 during SetupMove, never change during gameplay. Is apparently used for weapon services stuff.
+ public CUtlVector TouchList;
+ public Vector CollisionNormal;
+ public Vector GroundNormal;
+ public Vector AbsOrigin;
+ public int TickCount;
+ public int TargetTick;
+ public float SubtickStartFraction;
+ public float SubtickEndFraction;
+}
\ No newline at end of file
diff --git a/managed/src/SwiftlyS2.Shared/Natives/Structs/SubtickMove.cs b/managed/src/SwiftlyS2.Shared/Natives/Structs/SubtickMove.cs
new file mode 100644
index 000000000..0df6e5088
--- /dev/null
+++ b/managed/src/SwiftlyS2.Shared/Natives/Structs/SubtickMove.cs
@@ -0,0 +1,39 @@
+// Reference: https://github.com/KZGlobalTeam/cs2kz-metamod/blob/8d4038394173f1c10d763346d45cd3ccbc0091aa/src/sdk/datatypes.h#L141-L163
+
+using System.Runtime.InteropServices;
+
+namespace SwiftlyS2.Shared.Natives;
+
+[StructLayout(LayoutKind.Explicit, Size = 0x20, Pack = 1)]
+public struct SubtickMove
+{
+ [FieldOffset(0x00)]
+ public float When;
+
+ [FieldOffset(0x04)]
+ private readonly int Padding0;
+
+ [FieldOffset(0x08)]
+ public ulong Button;
+
+ // Union: pressed (bool) or analogMove struct
+ [FieldOffset(0x10)]
+ public bool Pressed;
+
+ [FieldOffset(0x10)]
+ public float AnalogForwardDelta;
+
+ [FieldOffset(0x14)]
+ public float AnalogLeftDelta;
+
+ [FieldOffset(0x18)]
+ public float PitchDelta;
+
+ [FieldOffset(0x1C)]
+ public float YawDelta;
+
+ public readonly bool IsAnalogInput()
+ {
+ return Button == 0;
+ }
+}
\ No newline at end of file
diff --git a/managed/src/SwiftlyS2.Shared/Natives/Structs/TouchListT.cs b/managed/src/SwiftlyS2.Shared/Natives/Structs/TouchListT.cs
new file mode 100644
index 000000000..29086221c
--- /dev/null
+++ b/managed/src/SwiftlyS2.Shared/Natives/Structs/TouchListT.cs
@@ -0,0 +1,12 @@
+// Reference: https://github.com/KZGlobalTeam/cs2kz-metamod/blob/8d4038394173f1c10d763346d45cd3ccbc0091aa/src/sdk/datatypes.h#L135-L139
+
+using System.Runtime.InteropServices;
+
+namespace SwiftlyS2.Shared.Natives;
+
+[StructLayout(LayoutKind.Sequential)]
+public struct TouchListT
+{
+ public Vector DeltaVelocity;
+ public CGameTrace Trace;
+}
\ No newline at end of file
diff --git a/managed/src/TestPlugin/TestPlugin.cs b/managed/src/TestPlugin/TestPlugin.cs
index 9342ee300..6ef31563b 100644
--- a/managed/src/TestPlugin/TestPlugin.cs
+++ b/managed/src/TestPlugin/TestPlugin.cs
@@ -637,6 +637,7 @@ public void GetIpCommand( ICommandContext context )
// Core.Menus.OpenMenu(player, settingsMenu);
// }
+
[Command("ed")]
public void EndRoundCommand( ICommandContext _ )
{
@@ -644,6 +645,23 @@ public void EndRoundCommand( ICommandContext _ )
gameRules.TerminateRound(RoundEndReason.CTsWin, 10.0f);
}
+ [Command("sizecheck")]
+ public void SizeCheckCommand( ICommandContext _ )
+ {
+ unsafe
+ {
+ var moveDataSize = sizeof(CMoveData);
+ var moveDataBaseSize = sizeof(CMoveDataBase);
+ var subtickMoveSize = sizeof(SubtickMove);
+ var touchListSize = sizeof(TouchListT);
+
+ Console.WriteLine($"CMoveData size: {moveDataSize} bytes");
+ Console.WriteLine($"CMoveDataBase size: {moveDataBaseSize} bytes");
+ Console.WriteLine($"SubtickMove size: {subtickMoveSize} bytes");
+ Console.WriteLine($"TouchListT size: {touchListSize} bytes");
+ }
+ }
+
[Command("tm")]
public void TestMenuCommand( ICommandContext context )
{