using System; using System.Buffers.Binary; using System.Text; using AcDream.Core.Net.Messages; using Xunit; namespace AcDream.Core.Net.Tests.Messages; public sealed class CombatEventTests { private static byte[] MakeString16L(string s) { byte[] data = Encoding.ASCII.GetBytes(s); int recordSize = 2 + data.Length; int padding = (4 - (recordSize & 3)) & 3; byte[] result = new byte[recordSize + padding]; BinaryPrimitives.WriteUInt16LittleEndian(result, (ushort)data.Length); Array.Copy(data, 0, result, 2, data.Length); return result; } [Fact] public void AttackTargetRequest_Build_EmitsCorrectWireBytes() { byte[] body = AttackTargetRequest.Build( gameActionSequence: 3, targetGuid: 0x12345678u, powerLevel: 0.75f, accuracyLevel: 0.5f, attackHeight: 2); Assert.Equal(28, body.Length); Assert.Equal(AttackTargetRequest.GameActionEnvelope, BinaryPrimitives.ReadUInt32LittleEndian(body)); Assert.Equal(3u, BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(4))); Assert.Equal(AttackTargetRequest.SubOpcode, BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8))); Assert.Equal(0x12345678u, BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12))); Assert.Equal(0.75f, BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(16)), 4); Assert.Equal(0.5f, BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(20)), 4); Assert.Equal(2u, BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(24))); } [Fact] public void ParseVictimNotification_RoundTrip() { byte[] name = MakeString16L("Attacker"); byte[] tail = new byte[24]; BinaryPrimitives.WriteUInt32LittleEndian(tail, 0xAAu); // guid BinaryPrimitives.WriteUInt32LittleEndian(tail.AsSpan(4), 1u); // damageType BinaryPrimitives.WriteUInt32LittleEndian(tail.AsSpan(8), 42u); // damage BinaryPrimitives.WriteUInt32LittleEndian(tail.AsSpan(12), 3u); // quadrant BinaryPrimitives.WriteUInt32LittleEndian(tail.AsSpan(16), 1u); // crit BinaryPrimitives.WriteUInt32LittleEndian(tail.AsSpan(20), 8u); // attackType byte[] payload = new byte[name.Length + tail.Length]; Buffer.BlockCopy(name, 0, payload, 0, name.Length); Buffer.BlockCopy(tail, 0, payload, name.Length, tail.Length); var parsed = GameEvents.ParseVictimNotification(payload); Assert.NotNull(parsed); Assert.Equal("Attacker", parsed!.Value.AttackerName); Assert.Equal(0xAAu, parsed.Value.AttackerGuid); Assert.Equal(42u, parsed.Value.Damage); Assert.Equal(1u, parsed.Value.Critical); } [Fact] public void ParseAttackerNotification_RoundTrip() { byte[] name = MakeString16L("Drudge"); byte[] tail = new byte[12]; BinaryPrimitives.WriteUInt32LittleEndian(tail, 1u); // damageType BinaryPrimitives.WriteUInt32LittleEndian(tail.AsSpan(4), 30u); // damage BinaryPrimitives.WriteSingleLittleEndian(tail.AsSpan(8), 0.15f); // percent byte[] payload = new byte[name.Length + tail.Length]; Buffer.BlockCopy(name, 0, payload, 0, name.Length); Buffer.BlockCopy(tail, 0, payload, name.Length, tail.Length); var parsed = GameEvents.ParseAttackerNotification(payload); Assert.NotNull(parsed); Assert.Equal("Drudge", parsed!.Value.DefenderName); Assert.Equal(30u, parsed.Value.Damage); Assert.Equal(0.15f, parsed.Value.DamagePercent, 4); } [Fact] public void ParseEvasionAttackerNotification_RoundTrip() { byte[] payload = MakeString16L("Thrower"); Assert.Equal("Thrower", GameEvents.ParseEvasionAttackerNotification(payload)); } [Fact] public void ParseAttackDone_RoundTrip() { byte[] payload = new byte[8]; BinaryPrimitives.WriteUInt32LittleEndian(payload, 42u); BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(4), 0u); // no error var parsed = GameEvents.ParseAttackDone(payload); Assert.NotNull(parsed); Assert.Equal(42u, parsed!.Value.AttackSequence); Assert.Equal(0u, parsed.Value.WeenieError); } }