Code:
using System;
using System.Runtime.InteropServices;
using System.Text;
using ClassicWowHack.Game.Objects;
using ClassicWowHack.Misc;
using ClassicWowHack.Native;
namespace ClassicWowHack.Packet
{
class CDataStore
{
#region Properties
public readonly bool Complete = true;
public readonly IntPtr UnmanagedPtr;
private readonly bool _deallocate;
public IntPtr Data
{
get { return Marshal.ReadIntPtr(UnmanagedPtr, 0x4); }
protected set { Marshal.WriteIntPtr(UnmanagedPtr, 0x4, value); }
}
public int Base
{
get { return Marshal.ReadInt32(UnmanagedPtr, 0x8); }
protected set { Marshal.WriteInt32(UnmanagedPtr, 0x8, value); }
}
public int Capacity
{
get { return Marshal.ReadInt32(UnmanagedPtr, 0xC); }
protected set { Marshal.WriteInt32(UnmanagedPtr, 0xC, value); }
}
public int BytesWritten
{
get { return Marshal.ReadInt32(UnmanagedPtr, 0x10); }
protected set { Marshal.WriteInt32(UnmanagedPtr, 0x10, value); }
}
public int BytesRead
{
get { return Marshal.ReadInt32(UnmanagedPtr, 0x14); }
protected set { Marshal.WriteInt32(UnmanagedPtr, 0x14, value); }
}
public OpCode OpCode
{
get { return (OpCode)Marshal.ReadInt16(Data); }
set { Marshal.WriteInt32(Data, (short) value); }
}
#endregion
public CDataStore(IntPtr unmanagedPtr)
{
UnmanagedPtr = unmanagedPtr;
_deallocate = false;
}
private const int StructSize = 0x18;
public CDataStore(int bytesRequested)
{
UnmanagedPtr = Marshal.AllocHGlobal(StructSize);
Data = Marshal.AllocHGlobal(bytesRequested);
OpCode = OpCode.MSG_NULL_ACTION;
Capacity = bytesRequested;
BytesRead = Base = 0;
BytesWritten = 4;
_deallocate = true;
}
public static CDataStore Copy(IntPtr dataStorePtr, bool resetRead = true)
{
return Copy(new CDataStore(dataStorePtr), resetRead);
}
public static CDataStore Copy(CDataStore dataStore, bool resetRead = true)
{
var ret = new CDataStore(dataStore.Capacity == -1 ? dataStore.BytesWritten : dataStore.Capacity);
var data = new byte[ret.Capacity];
if (dataStore.Data != IntPtr.Zero)
Marshal.Copy(dataStore.Data, data, 0, dataStore.BytesWritten);
Marshal.Copy(data, 0, ret.Data, data.Length);
ret.Base = dataStore.Base;
ret.BytesRead = resetRead ? 0 : dataStore.BytesRead;
ret.BytesWritten = dataStore.BytesWritten;
return ret;
}
~CDataStore()
{
if (!_deallocate)
return;
Marshal.FreeHGlobal(Data);
Data = IntPtr.Zero;
Marshal.FreeHGlobal(UnmanagedPtr);
}
#region Write Functions
public void Write(byte val)
{
Marshal.WriteByte(Data, BytesWritten, val);
BytesWritten += 1;
}
public void Write(short val)
{
Marshal.WriteInt16(Data, BytesWritten, val);
BytesWritten += 2;
}
public void Write(ushort val)
{
Write((short) val);
}
public void Write(int val)
{
Marshal.WriteInt32(Data, BytesWritten, val);
BytesWritten += 4;
}
public void Write(uint val)
{
Write((int) val);
}
public void Write(long val)
{
Marshal.WriteInt64(Data, BytesWritten, val);
BytesWritten += 8;
}
public void Write(ulong val)
{
Write((long)val);
}
public void Write(float val)
{
var destination = new IntPtr(Data.ToInt32() + BytesWritten);
var tmp = new[] {val};
Marshal.Copy(tmp, 0, destination, 1);
BytesWritten += 4;
}
public void Write(double val)
{
var destination = new IntPtr(Data.ToInt32() + BytesWritten);
var tmp = new[] {val};
Marshal.Copy(tmp, 0, destination, 1);
BytesWritten += 8;
}
public void Write(byte[] val)
{
var destination = new IntPtr(Data.ToInt32() + BytesWritten);
Marshal.Copy(val, 0, destination, val.Length);
BytesWritten += val.Length;
}
public void Write(string val, bool unicode = false)
{
var destination = new IntPtr(Data.ToInt32() + BytesWritten);
if (unicode)
{
Marshal.Copy(val.ToCharArray(), 0, destination, val.ToCharArray().Length);
BytesWritten += val.Length*2;
}
else
{
var encodedBytes = Encoding.ASCII.GetBytes(val);
Marshal.Copy(encodedBytes, 0, destination, encodedBytes.Length);
BytesWritten += val.Length;
Write((byte) 0);
}
}
#endregion
#region Read Functions
public T Read<T>()
{
object ret;
var tType = typeof (T);
var address = new IntPtr(Data.ToInt32() + BytesRead);
// Handle types that don't have a real typecode
if (tType == typeof (IntPtr))
{
ret = Marshal.ReadIntPtr(address);
BytesRead += 4;
return (T) ret;
}
int size;
switch (Type.GetTypeCode(tType))
{
case TypeCode.Boolean:
case TypeCode.Byte:
ret = Marshal.ReadByte(address);
size = 1;
break;
case TypeCode.Char:
ret = (char) Marshal.ReadByte(address);
size = 1;
break;
case TypeCode.Int16:
ret = Marshal.ReadInt16(address);
size = 2;
break;
case TypeCode.UInt16:
ret = (ushort) Marshal.ReadInt16(address);
size = 2;
break;
case TypeCode.Int32:
ret = Marshal.ReadInt32(address);
size = 4;
break;
case TypeCode.UInt32:
ret = (uint) Marshal.ReadInt32(address);
size = 4;
break;
case TypeCode.Int64:
ret = Marshal.ReadInt64(address);
size = 8;
break;
case TypeCode.UInt64:
ret = (ulong) Marshal.ReadInt64(address);
size = 8;
break;
case TypeCode.Single:
float[] tmp = new float[1];
Marshal.Copy(address, tmp, 0, 1);
size = 4;
ret = tmp[0];
break;
case TypeCode.Double:
double[] tmp2 = new double[1];
Marshal.Copy(address, tmp2, 0, 1);
ret = tmp2[0];
size = 8;
break;
default:
throw new ArgumentOutOfRangeException(tType.FullName + " is not supported with this method.");
}
BytesRead += size;
return (T)ret;
}
public byte[] Read(int length)
{
if (BytesRead + length > Capacity)
throw new OverflowException("CPacket: Read overflow");
byte[] ret = new byte[length];
Marshal.Copy(new IntPtr(Data.ToInt32() + BytesRead), ret, 0, length);
BytesRead += length;
return ret;
}
public string ReadAnsiString()
{
IntPtr stringPtr = new IntPtr(Data.ToInt32() + BytesRead);
string ret = Marshal.PtrToStringAnsi(stringPtr);
BytesRead += ret.Length + 1;
return ret;
}
public string ReadUnicodeString()
{
var stringPtr = new IntPtr(Data.ToInt32() + BytesRead);
string ret = Marshal.PtrToStringUni(stringPtr);
if (ret == null)
return string.Empty;
BytesRead += (ret.Length + 1)*2;
return ret;
}
#endregion
public override string ToString()
{
var ret = OpCode.ToString();
for (var i = 0; i < BytesWritten; i++)
ret += " 0x" + Marshal.ReadByte(Data, i).ToString("X2");
return ret;
}
}
class MovementPacket : CDataStore
{
#region Complete
/// <summary>
/// Whether this packet was created by us. Only these packets are capable of being
/// checked for well-formness.
/// </summary>
private readonly bool _ourPacket;
private bool _flagsSet;
private bool _timeSet;
private bool _xSet;
private bool _ySet;
private bool _zSet;
private bool _orientationSet;
private bool _transportGuidSet;
private bool _transportXSet;
private bool _transportYSet;
private bool _transportZSet;
private bool _transportOrientationSet;
private bool _pitchSet;
private bool _fallTimeSet;
private bool _fallVelocitySet;
private bool _fallSinAngleSet;
private bool _fallCosAngleSet;
private bool _fallLateralSpeedSet;
private bool _splineSet;
public new bool Complete
{
get
{
if (!_ourPacket)
return true;
if (!_flagsSet || !_timeSet || !_xSet || !_ySet || !_zSet || !_orientationSet || !_fallTimeSet)
return false;
if (Flags.HasFlag(MovementFlags.OnTransport) &&
(!_transportGuidSet || !_transportXSet || !_transportYSet || !_transportZSet || !_transportOrientationSet))
return false;
if (Flags.HasFlag(MovementFlags.Swimming) && !_pitchSet)
return false;
if (Flags.HasFlag(MovementFlags.Falling) &&
(!_fallVelocitySet || !_fallSinAngleSet || !_fallCosAngleSet || !_fallLateralSpeedSet))
return false;
if (Flags.HasFlag(MovementFlags.SplineElevation) && !_splineSet)
return false;
return true;
}
}
#endregion
public MovementPacket(IntPtr unmanagedPtr) : base(unmanagedPtr) {}
public MovementPacket(MovementFlags flags) : base(BufferSize(flags))
{
Flags = flags;
BytesWritten = Capacity;
_ourPacket = true;
_flagsSet = true;
_timeSet = false;
_xSet = _ySet = _zSet = _orientationSet = false;
_transportGuidSet = false;
_transportXSet = _transportYSet = _transportZSet = false;
_transportOrientationSet = false;
_pitchSet = false;
_fallTimeSet = false;
_fallVelocitySet = false;
_fallSinAngleSet = false;
_fallCosAngleSet = false;
_fallLateralSpeedSet = false;
_splineSet = false;
}
private static int BufferSize(MovementFlags flags)
{
var ret = 0x20;
if (flags.HasFlag(MovementFlags.OnTransport))
ret += 0x18;
if (flags.HasFlag(MovementFlags.Swimming))
ret += 0x4;
if (flags.HasFlag(MovementFlags.Falling))
ret += 0x10;
if (flags.HasFlag(MovementFlags.SplineElevation))
ret += 0x4;
return ret;
}
private const int TransportSize = 24;
private const int SwimmingSize = 4;
private const int FallingSize = 16;
public MovementFlags Flags
{
get
{
MovementFlags ret;
try
{
ret = (MovementFlags)Marshal.ReadInt32(Data, 4);
}
catch (Exception e)
{
Logging.Write("MovementPacket.Flags Exception: " + e);
return MovementFlags.None;
}
return ret;
}
set
{
_flagsSet = true;
Marshal.WriteInt32(Data, 4, (int) value);
}
}
public uint Time
{
get { return (uint) Marshal.ReadInt32(Data, 8); }
set
{
_timeSet = true;
Marshal.WriteInt32(Data, 8, (int) value);
}
}
#region Position
public float X
{
get
{
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0xC), ret, 0, 1);
return ret[0];
}
set
{
_xSet = true;
var ins = new[] {value};
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0xC), 1);
}
}
public float Y
{
get
{
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x10), ret, 0, 1);
return ret[0];
}
set
{
_ySet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x10), 1);
}
}
public float Z
{
get
{
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x14), ret, 0, 1);
return ret[0];
}
set
{
_zSet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x14), 1);
}
}
public Point3 Position
{
get { return new Point3 {X = X, Y = Y, Z = Z}; }
set
{
X = value.X;
Y = value.Y;
Z = value.Z;
}
}
public float Orientation
{
get
{
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x18), ret, 0, 1);
return ret[0];
}
set
{
_orientationSet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x18), 1);
}
}
#endregion
#region OnTransport
public ulong TransportGuid
{
get
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
return (ulong)Marshal.ReadInt64(Data, 0x1C);
}
set
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
_transportGuidSet = true;
Marshal.WriteInt64(Data, 0x1C, (long) value);
}
}
public float TransportX
{
get
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x24), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
_transportXSet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x24), 1);
}
}
public float TransportY
{
get
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x28), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
_transportYSet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x28), 1);
}
}
public float TransportZ
{
get
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x2C), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
_transportZSet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x2C), 1);
}
}
public Point3 TransportPosition
{
get { return new Point3 { X = X, Y = Y, Z = Z }; }
set
{
TransportX = value.X;
TransportY = value.Y;
TransportZ = value.Z;
}
}
public float TransportOrientation
{
get
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + 0x30), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.OnTransport))
throw new ArgumentOutOfRangeException("Not on transport");
_transportOrientationSet = true;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + 0x30), 1);
}
}
#endregion
#region Swimming
public float Pitch
{
get
{
if (!Flags.HasFlag(MovementFlags.Swimming))
throw new ArgumentOutOfRangeException("Not swimming");
var offset = Flags.HasFlag(MovementFlags.OnTransport) ? 0x34 : 0x1C;
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + offset), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.Swimming))
throw new ArgumentOutOfRangeException("Not swimming");
_pitchSet = true;
var offset = Flags.HasFlag(MovementFlags.OnTransport) ? 0x34 : 0x1C;
var ins = new [] {value};
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + offset), 1);
}
}
#endregion
public uint FallTime
{
get
{
var offset = 0x1C;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
return (uint)Marshal.ReadInt32(Data, offset);
}
set
{
_fallTimeSet = true;
var offset = 0x1C;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
Marshal.WriteInt32(Data, offset, (int)value);
}
}
#region Falling
public float FallVelocity
{
get
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
var offset = 0x20;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + offset), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
_fallVelocitySet = true;
var offset = 0x20;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + offset), 1);
}
}
public float FallSinAngle
{
get
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
var offset = 0x24;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + offset), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
_fallSinAngleSet = true;
var offset = 0x24;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + offset), 1);
}
}
public float FallCosAngle
{
get
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
var offset = 0x28;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + offset), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
_fallCosAngleSet = true;
var offset = 0x28;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + offset), 1);
}
}
public float FallLateralSpeed
{
get
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
var offset = 0x2C;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ret = new float[1];
Marshal.Copy(new IntPtr(Data.ToInt32() + offset), ret, 0, 1);
return ret[0];
}
set
{
if (!Flags.HasFlag(MovementFlags.Falling))
throw new ArgumentOutOfRangeException("Not falling");
_fallLateralSpeedSet = true;
var offset = 0x2C;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
var ins = new[] { value };
Marshal.Copy(ins, 0, new IntPtr(Data.ToInt32() + offset), 1);
}
}
#endregion
#region SplineElevation
public int UnknownSpline
{
get
{
if (!Flags.HasFlag(MovementFlags.SplineElevation))
throw new ArgumentOutOfRangeException("Spline elevation missing");
var offset = 0x20;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
if (Flags.HasFlag(MovementFlags.Falling))
offset += FallingSize;
return Marshal.ReadInt32(Data, offset);
}
set
{
if (!Flags.HasFlag(MovementFlags.SplineElevation))
throw new ArgumentOutOfRangeException("Spline elevation missing");
_splineSet = true;
var offset = 0x20;
if (Flags.HasFlag(MovementFlags.OnTransport))
offset += TransportSize;
if (Flags.HasFlag(MovementFlags.Swimming))
offset += SwimmingSize;
if (Flags.HasFlag(MovementFlags.Falling))
offset += FallingSize;
Marshal.WriteInt32(Data, offset, value);
}
}
#endregion
public override string ToString()
{
try
{
long perfCount, perfFreq;
Win32.QueryPerformanceCounter(out perfCount);
Win32.QueryPerformanceFrequency(out perfFreq);
double scalar = 1000.0 / (double)perfFreq;
double time = scalar * (double)perfCount;
var ret = string.Format("{0} MoveFlags: {1} Time: {2} (Current system tick count = {8}, perf: {9}) Position ({3}, {4}, {5}, {6}) Fall Time: {7}",
OpCode, Flags, Time, X, Y, Z, Orientation, FallTime, Environment.TickCount, time);
if (Flags.HasFlag(MovementFlags.Falling))
ret += " Fall velocity: " + FallVelocity;
if (Flags.HasFlag(MovementFlags.OnTransport))
ret += " Transport GUID: 0x" + TransportGuid.ToString("X");
return ret;
}
catch (Exception e)
{
Logging.Write("MovementPacket Exception: " + e + " Data: 0x" + Data.ToString("X"));
return string.Empty;
}
}
}
}