Changes account packets to functional (#284)
- [X] Moved packets from objects to functions - [X] Fixed bug where characters were showing up with their modded names in the character list Bumps release version
This commit is contained in:
parent
90220feb41
commit
0e02cf0821
19 changed files with 866 additions and 631 deletions
|
|
@ -1,8 +1,5 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Server.Accounting;
|
||||
using Server.Network;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -15,85 +12,57 @@ namespace Server.Tests.Network
|
|||
{
|
||||
var firstMobile = new Mobile(0x1);
|
||||
firstMobile.DefaultMobileInit();
|
||||
firstMobile.Name = "Test Mobile";
|
||||
firstMobile.RawName = "Test Mobile";
|
||||
|
||||
var account = new TestAccount(new[] { firstMobile, null, null });
|
||||
var secondMobile = new Mobile(0x2);
|
||||
secondMobile.DefaultMobileInit();
|
||||
secondMobile.RawName = null;
|
||||
|
||||
var data = new ChangeCharacter(account).Compile();
|
||||
var account = new MockAccount(new[] { firstMobile, null, secondMobile });
|
||||
var oldPacket = new ChangeCharacter(account).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[5 + account.Length * 60];
|
||||
var pos = 0;
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendChangeCharacter(ns, account);
|
||||
|
||||
expectedData.Write(ref pos, (byte)0x81); // Packet ID
|
||||
expectedData.Write(ref pos, (ushort)expectedData.Length); // Length
|
||||
expectedData.Write(ref pos, (byte)1); // Count of non-null characters
|
||||
expectedData.Write(ref pos, (byte)0);
|
||||
|
||||
for (var i = 0; i < account.Length; ++i)
|
||||
{
|
||||
var m = account[i];
|
||||
if (m == null)
|
||||
{
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Clear(ref pos, 60);
|
||||
#else
|
||||
pos += 60;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
expectedData.WriteAsciiFixed(ref pos, m.Name, 30);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Clear(ref pos, 30); // Password (empty)
|
||||
#else
|
||||
pos += 30;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), oldPacket);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestClientVersionReq()
|
||||
{
|
||||
var data = new ClientVersionReq().Compile();
|
||||
var expected = new ClientVersionReq().Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[]
|
||||
{
|
||||
0xBD, // Packet ID
|
||||
0x00, 0x03 // Length
|
||||
};
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
Packets.SendClientVersionRequest(ns);
|
||||
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestDeleteResult()
|
||||
{
|
||||
var data = new DeleteResult(DeleteResultType.BadRequest).Compile();
|
||||
var expected = new DeleteResult(DeleteResultType.BadRequest).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[2];
|
||||
var pos = 0;
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendCharacterDeleteResult(ns, DeleteResultType.BadRequest);
|
||||
|
||||
expectedData.Write(ref pos, (byte)0x85); // Packet ID
|
||||
expectedData.Write(ref pos, (byte)DeleteResultType.BadRequest);
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPopupMessage()
|
||||
{
|
||||
var data = new PopupMessage(PMMessage.IdleWarning).Compile();
|
||||
var expected = new PopupMessage(PMMessage.LoginSyncError).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[2];
|
||||
var pos = 0;
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendPopupMessage(ns, PMMessage.LoginSyncError);
|
||||
|
||||
expectedData.Write(ref pos, (byte)0x53); // Packet ID
|
||||
expectedData.Write(ref pos, (byte)PMMessage.IdleWarning);
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -105,48 +74,17 @@ namespace Server.Tests.Network
|
|||
firstMobile.DefaultMobileInit();
|
||||
firstMobile.Name = "Test Mobile";
|
||||
|
||||
var account = new TestAccount(new[] { firstMobile, null, null, null, null });
|
||||
var account = new MockAccount(new[] { firstMobile, null, null, null, null });
|
||||
|
||||
var ns = new NetState(null)
|
||||
{
|
||||
Account = account,
|
||||
ProtocolChanges = protocolChanges
|
||||
};
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.Account = account;
|
||||
ns.ProtocolChanges = protocolChanges;
|
||||
|
||||
var data = new SupportedFeatures(ns).Compile();
|
||||
var expected = new SupportedFeatures(ns).Compile();
|
||||
Packets.SendSupportedFeature(ns);
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[ns.ExtendedSupportedFeatures ? 5 : 3];
|
||||
var pos = 0;
|
||||
|
||||
expectedData[pos++] = 0xB9; // Packet ID
|
||||
|
||||
var flags = ExpansionInfo.GetFeatures(Expansion.EJ);
|
||||
|
||||
if (ns.Account.Limit >= 6)
|
||||
{
|
||||
flags |= FeatureFlags.LiveAccount;
|
||||
flags &= ~FeatureFlags.UOTD;
|
||||
|
||||
if (ns.Account.Limit > 6)
|
||||
{
|
||||
flags |= FeatureFlags.SeventhCharacterSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= FeatureFlags.SixthCharacterSlot;
|
||||
}
|
||||
}
|
||||
|
||||
if (ns.ExtendedSupportedFeatures)
|
||||
{
|
||||
expectedData.Write(ref pos, (uint)flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
expectedData.Write(ref pos, (ushort)flags);
|
||||
}
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -161,59 +99,25 @@ namespace Server.Tests.Network
|
|||
m.Direction = Direction.Down;
|
||||
m.LogoutMap = Map.Felucca;
|
||||
|
||||
var data = new LoginConfirm(m).Compile();
|
||||
var expected = new LoginConfirm(m).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[37];
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendLoginConfirmation(ns, m);
|
||||
|
||||
var pos = 0;
|
||||
expectedData.Write(ref pos, (byte)0x1B); // Packet ID
|
||||
expectedData.Write(ref pos, m.Serial);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, 0);
|
||||
#else
|
||||
pos += 4;
|
||||
#endif
|
||||
|
||||
expectedData.Write(ref pos, (ushort)m.Body);
|
||||
expectedData.Write(ref pos, (ushort)m.X);
|
||||
expectedData.Write(ref pos, (ushort)m.Y);
|
||||
expectedData.Write(ref pos, (short)m.Z);
|
||||
expectedData.Write(ref pos, (byte)m.Direction);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (byte)0);
|
||||
#else
|
||||
pos++;
|
||||
#endif
|
||||
expectedData.Write(ref pos, 0xFFFFFFFF);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, 0);
|
||||
#else
|
||||
pos += 4;
|
||||
#endif
|
||||
var map = m.Map;
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
map = m.LogoutMap;
|
||||
}
|
||||
|
||||
expectedData.Write(ref pos, (ushort)(map?.Width ?? Map.Felucca.Width));
|
||||
expectedData.Write(ref pos, (ushort)(map?.Height ?? Map.Felucca.Height));
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLoginComplete()
|
||||
{
|
||||
var data = new LoginComplete().Compile();
|
||||
var expected = new LoginComplete().Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[]
|
||||
{
|
||||
0x55 // Packet ID
|
||||
};
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendLoginComplete(ns);
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -221,175 +125,43 @@ namespace Server.Tests.Network
|
|||
{
|
||||
var firstMobile = new Mobile(0x1);
|
||||
firstMobile.DefaultMobileInit();
|
||||
firstMobile.Name = "Test Mobile";
|
||||
firstMobile.RawName = "Test Mobile";
|
||||
|
||||
var account = new TestAccount(new[] { firstMobile, null, null, null, null });
|
||||
var acct = new MockAccount(new[] { null, firstMobile, null, null, null });
|
||||
|
||||
var data = new CharacterListUpdate(account).Compile();
|
||||
var expected = new CharacterListUpdate(acct).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[4 + account.Length * 60];
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendCharacterListUpdate(ns, acct);
|
||||
|
||||
var pos = 0;
|
||||
expectedData.Write(ref pos, (byte)0x86); // Packet ID
|
||||
expectedData.Write(ref pos, (ushort)expectedData.Length); // Length
|
||||
|
||||
var highSlot = -1;
|
||||
for (var i = account.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (account[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, account.Limit), 5);
|
||||
expectedData.Write(ref pos, (byte)count);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var m = account[i];
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
expectedData.WriteAsciiFixed(ref pos, m.Name, 30);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, 0);
|
||||
expectedData.Write(ref pos, (ushort)0);
|
||||
#else
|
||||
pos += 30;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, 0);
|
||||
#else
|
||||
pos += 60;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestCharacterList()
|
||||
public void TestCharacterList70130()
|
||||
{
|
||||
var firstMobile = new Mobile(0x1);
|
||||
firstMobile.DefaultMobileInit();
|
||||
firstMobile.Name = "Test Mobile";
|
||||
|
||||
var account = new TestAccount(new[] { firstMobile, null, null, null, null });
|
||||
var acct = new MockAccount(new[] { null, firstMobile, null, null, null });
|
||||
var info = new[]
|
||||
{
|
||||
new CityInfo("Test City", "Test Building", 50, 100, 10, -10)
|
||||
};
|
||||
|
||||
var data = new CharacterList(account, info).Compile();
|
||||
var expected = new CharacterList(acct, info).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[11 + account.Length * 60 + info.Length * 89];
|
||||
var pos = 0;
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.CityInfo = info;
|
||||
ns.Account = acct;
|
||||
ns.ProtocolChanges = ProtocolChanges.Version70130;
|
||||
|
||||
expectedData.Write(ref pos, (byte)0xA9); // Packet ID
|
||||
expectedData.Write(ref pos, (ushort)expectedData.Length); // Length
|
||||
Packets.SendCharacterList(ns);
|
||||
|
||||
var highSlot = -1;
|
||||
for (var i = account.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (account[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, account.Limit), 5);
|
||||
expectedData.Write(ref pos, (byte)count);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var m = account[i];
|
||||
if (m != null)
|
||||
{
|
||||
expectedData.WriteAsciiFixed(ref pos, m.Name, 30);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, 0);
|
||||
expectedData.Write(ref pos, (ushort)0);
|
||||
#else
|
||||
pos += 30;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, 0);
|
||||
#else
|
||||
pos += 60;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
expectedData.Write(ref pos, (byte)info.Length);
|
||||
|
||||
for (var i = 0; i < info.Length; i++)
|
||||
{
|
||||
var ci = info[i];
|
||||
expectedData.Write(ref pos, (byte)i);
|
||||
expectedData.WriteAsciiFixed(ref pos, ci.City, 32);
|
||||
expectedData.WriteAsciiFixed(ref pos, ci.Building, 32);
|
||||
expectedData.Write(ref pos, ci.X);
|
||||
expectedData.Write(ref pos, ci.Y);
|
||||
expectedData.Write(ref pos, ci.Z);
|
||||
expectedData.Write(ref pos, ci.Map.MapID);
|
||||
expectedData.Write(ref pos, ci.Description);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, 0);
|
||||
#else
|
||||
pos += 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
var flags = ExpansionInfo.GetInfo(Expansion.EJ).CharacterListFlags;
|
||||
if (count > 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SeventhCharacterSlot |
|
||||
CharacterListFlags.SixthCharacterSlot; // 7th Character Slot
|
||||
}
|
||||
else if (count == 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
|
||||
}
|
||||
else if (account.Limit == 1)
|
||||
{
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
expectedData.Write(ref pos, (int)flags);
|
||||
expectedData.Write(ref pos, (short)-1);
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -399,110 +171,35 @@ namespace Server.Tests.Network
|
|||
firstMobile.DefaultMobileInit();
|
||||
firstMobile.Name = "Test Mobile";
|
||||
|
||||
var account = new TestAccount(new[] { firstMobile, null, null, null, null });
|
||||
var acct = new MockAccount(new[] { null, firstMobile, null, null, null });
|
||||
var info = new[]
|
||||
{
|
||||
new CityInfo("Test City", "Test Building", 50, 100, 10, -10)
|
||||
};
|
||||
|
||||
var data = new CharacterListOld(account, info).Compile();
|
||||
var expected = new CharacterListOld(acct, info).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[9 + account.Length * 60 + info.Length * 63];
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.CityInfo = info;
|
||||
ns.Account = acct;
|
||||
|
||||
var pos = 0;
|
||||
expectedData.Write(ref pos, (byte)0xA9); // Packet ID
|
||||
expectedData.Write(ref pos, (ushort)expectedData.Length); // Length
|
||||
Packets.SendCharacterList(ns);
|
||||
|
||||
var highSlot = -1;
|
||||
for (var i = account.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (account[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, account.Limit), 5);
|
||||
expectedData.Write(ref pos, (byte)count);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var m = account[i];
|
||||
if (m != null)
|
||||
{
|
||||
expectedData.WriteAsciiFixed(ref pos, m.Name, 30);
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, 0);
|
||||
expectedData.Write(ref pos, (ushort)0);
|
||||
#else
|
||||
pos += 30;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NO_LOCAL_INIT
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, (ulong)0);
|
||||
expectedData.Write(ref pos, 0);
|
||||
#else
|
||||
pos += 60;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
expectedData.Write(ref pos, (byte)info.Length);
|
||||
|
||||
for (var i = 0; i < info.Length; i++)
|
||||
{
|
||||
var ci = info[i];
|
||||
expectedData.Write(ref pos, (byte)i);
|
||||
expectedData.WriteAsciiFixed(ref pos, ci.City, 31);
|
||||
expectedData.WriteAsciiFixed(ref pos, ci.Building, 31);
|
||||
}
|
||||
|
||||
var flags = ExpansionInfo.GetInfo(Expansion.EJ).CharacterListFlags;
|
||||
if (count > 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SeventhCharacterSlot |
|
||||
CharacterListFlags.SixthCharacterSlot; // 7th Character Slot
|
||||
}
|
||||
else if (count == 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
|
||||
}
|
||||
else if (account.Limit == 1)
|
||||
{
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
expectedData.Write(ref pos, (int)flags);
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAccountLoginRej()
|
||||
{
|
||||
var reason = ALRReason.BadComm;
|
||||
var data = new AccountLoginRej(reason).Compile();
|
||||
var expected = new AccountLoginRej(reason).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[2];
|
||||
var pos = 0;
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
Packets.SendAccountLoginRejected(ns, reason);
|
||||
|
||||
expectedData.Write(ref pos, (byte)0x82); // Packet ID
|
||||
expectedData.Write(ref pos, (byte)reason);
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -513,136 +210,31 @@ namespace Server.Tests.Network
|
|||
new ServerInfo("Test Server", 0, TimeZoneInfo.Local, IPEndPoint.Parse("127.0.0.1"))
|
||||
};
|
||||
|
||||
var data = new AccountLoginAck(info).Compile();
|
||||
var expected = new AccountLoginAck(info).Compile();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[6 + info.Length * 40];
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.ServerInfo = info;
|
||||
|
||||
var pos = 0;
|
||||
expectedData.Write(ref pos, (byte)0xA8); // Packet ID
|
||||
expectedData.Write(ref pos, (ushort)expectedData.Length);
|
||||
expectedData.Write(ref pos, (byte)0x5D); // Unknown
|
||||
expectedData.Write(ref pos, (ushort)info.Length);
|
||||
Packets.SendAccountLoginAck(ns);
|
||||
|
||||
for (var i = 0; i < info.Length; i++)
|
||||
{
|
||||
var si = info[i];
|
||||
expectedData.Write(ref pos, (ushort)i);
|
||||
expectedData.WriteAsciiFixed(ref pos, si.Name, 32);
|
||||
expectedData.Write(ref pos, (byte)si.FullPercent);
|
||||
expectedData.Write(ref pos, (byte)si.TimeZone);
|
||||
expectedData.Write(ref pos, Utility.GetAddressValue(si.Address.Address));
|
||||
}
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPlayServerAck()
|
||||
{
|
||||
var si = new ServerInfo("Test Server", 0, TimeZoneInfo.Local, IPEndPoint.Parse("127.0.0.1"));
|
||||
var authId = 0x123456;
|
||||
|
||||
var data = new PlayServerAck(si).Compile();
|
||||
var expected = new PlayServerAck(si, authId).Compile();
|
||||
|
||||
var addr = Utility.GetAddressValue(si.Address.Address);
|
||||
using var ns = PacketTestUtilities.CreateTestNetState();
|
||||
|
||||
Span<byte> expectedData = stackalloc byte[11];
|
||||
var pos = 0;
|
||||
Packets.SendPlayServerAck(ns, si, authId);
|
||||
|
||||
expectedData.Write(ref pos, (byte)0x8C); // Packet ID
|
||||
expectedData.WriteLE(ref pos, addr);
|
||||
expectedData.Write(ref pos, (ushort)si.Address.Port);
|
||||
expectedData.Write(ref pos, -1); // Auth ID
|
||||
|
||||
AssertThat.Equal(data, expectedData);
|
||||
}
|
||||
|
||||
internal class TestAccount : IAccount, IComparable<TestAccount>
|
||||
{
|
||||
private readonly Mobile[] m_Mobiles;
|
||||
private string m_Password;
|
||||
|
||||
public TestAccount(Mobile[] mobiles)
|
||||
{
|
||||
m_Mobiles = mobiles;
|
||||
foreach (var mobile in mobiles)
|
||||
{
|
||||
if (mobile != null)
|
||||
{
|
||||
mobile.Account = this;
|
||||
}
|
||||
}
|
||||
|
||||
Length = mobiles.Length;
|
||||
Count = mobiles.Count(t => t != null);
|
||||
Limit = mobiles.Length;
|
||||
}
|
||||
|
||||
public int TotalGold { get; private set; }
|
||||
public int TotalPlat { get; private set; }
|
||||
|
||||
public bool DepositGold(int amount)
|
||||
{
|
||||
TotalGold += amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DepositPlat(int amount)
|
||||
{
|
||||
TotalPlat += amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WithdrawGold(int amount)
|
||||
{
|
||||
if (TotalGold - amount < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TotalGold -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WithdrawPlat(int amount)
|
||||
{
|
||||
if (TotalPlat - amount < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TotalPlat -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public long GetTotalGold() => TotalGold + TotalPlat * 100;
|
||||
|
||||
public int CompareTo(IAccount other) => other == null ? 1 : Username.CompareTo(other.Username);
|
||||
|
||||
public string Username { get; set; }
|
||||
public string Email { get; set; }
|
||||
public AccessLevel AccessLevel { get; set; }
|
||||
public int Length { get; }
|
||||
public int Limit { get; }
|
||||
public int Count { get; }
|
||||
|
||||
public Mobile this[int index]
|
||||
{
|
||||
get => m_Mobiles[index];
|
||||
set => m_Mobiles[index] = value;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetPassword(string password)
|
||||
{
|
||||
m_Password = password;
|
||||
}
|
||||
|
||||
public bool CheckPassword(string password) => m_Password == password;
|
||||
|
||||
public int CompareTo(TestAccount other) => other == null ? 1 : Username.CompareTo(other.Username);
|
||||
ns.SendPipe.Reader.TryRead(out var buffer);
|
||||
AssertThat.Equal(buffer.GetSpan(0), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,361 @@
|
|||
using System;
|
||||
using Server.Accounting;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Tests.Network
|
||||
{
|
||||
public sealed class ChangeCharacter : Packet
|
||||
{
|
||||
public ChangeCharacter(IAccount a) : base(0x81)
|
||||
{
|
||||
EnsureCapacity(305);
|
||||
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (a[i] != null)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
Stream.Write((byte)count);
|
||||
Stream.Write((byte)0);
|
||||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
var m = a[i];
|
||||
if (a[i] != null)
|
||||
{
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
|
||||
Stream.WriteAsciiFixed(name, 30);
|
||||
Stream.Fill(30); // password
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Fill(60);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ClientVersionReq : Packet
|
||||
{
|
||||
public ClientVersionReq() : base(0xBD)
|
||||
{
|
||||
EnsureCapacity(3);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DeleteResult : Packet
|
||||
{
|
||||
public DeleteResult(DeleteResultType res) : base(0x85, 2)
|
||||
{
|
||||
Stream.Write((byte)res);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PopupMessage : Packet
|
||||
{
|
||||
public PopupMessage(PMMessage msg) : base(0x53, 2)
|
||||
{
|
||||
Stream.Write((byte)msg);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SupportedFeatures : Packet
|
||||
{
|
||||
public SupportedFeatures(NetState ns) : base(0xB9, ns.ExtendedSupportedFeatures ? 5 : 3)
|
||||
{
|
||||
var flags = ExpansionInfo.CoreExpansion.SupportedFeatures;
|
||||
|
||||
if (ns.Account.Limit >= 6)
|
||||
{
|
||||
flags |= FeatureFlags.LiveAccount;
|
||||
flags &= ~FeatureFlags.UOTD;
|
||||
|
||||
if (ns.Account.Limit > 6)
|
||||
{
|
||||
flags |= FeatureFlags.SeventhCharacterSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= FeatureFlags.SixthCharacterSlot;
|
||||
}
|
||||
}
|
||||
|
||||
if (ns.ExtendedSupportedFeatures)
|
||||
{
|
||||
Stream.Write((uint)flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Write((ushort)flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class LoginConfirm : Packet
|
||||
{
|
||||
public LoginConfirm(Mobile m) : base(0x1B, 37)
|
||||
{
|
||||
Stream.Write(m.Serial);
|
||||
Stream.Write(0);
|
||||
Stream.Write((short)m.Body);
|
||||
Stream.Write((short)m.X);
|
||||
Stream.Write((short)m.Y);
|
||||
Stream.Write((short)m.Z);
|
||||
Stream.Write((byte)m.Direction);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write(-1);
|
||||
|
||||
var map = m.Map;
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
map = m.LogoutMap;
|
||||
}
|
||||
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((short)0);
|
||||
Stream.Write((short)(map?.Width ?? Map.Felucca.Width));
|
||||
Stream.Write((short)(map?.Height ?? Map.Felucca.Height));
|
||||
|
||||
Stream.Fill();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class LoginComplete : Packet
|
||||
{
|
||||
public LoginComplete() : base(0x55, 1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CharacterListUpdate : Packet
|
||||
{
|
||||
public CharacterListUpdate(IAccount a) : base(0x86)
|
||||
{
|
||||
EnsureCapacity(4 + a.Length * 60);
|
||||
|
||||
var highSlot = -1;
|
||||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (a[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
|
||||
Stream.Write((byte)count);
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var m = a[i];
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
Stream.WriteAsciiFixed(name, 30);
|
||||
Stream.Fill(30); // password
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Fill(60);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CharacterList : Packet
|
||||
{
|
||||
public CharacterList(IAccount a, CityInfo[] info) : base(0xA9)
|
||||
{
|
||||
EnsureCapacity(11 + a.Length * 60 + info.Length * 89);
|
||||
|
||||
var highSlot = -1;
|
||||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (a[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
|
||||
Stream.Write((byte)count);
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
if (a[i] != null)
|
||||
{
|
||||
Stream.WriteAsciiFixed(a[i].Name, 30);
|
||||
Stream.Fill(30); // password
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Fill(60);
|
||||
}
|
||||
}
|
||||
|
||||
Stream.Write((byte)info.Length);
|
||||
|
||||
for (var i = 0; i < info.Length; ++i)
|
||||
{
|
||||
var ci = info[i];
|
||||
|
||||
Stream.Write((byte)i);
|
||||
Stream.WriteAsciiFixed(ci.City, 32);
|
||||
Stream.WriteAsciiFixed(ci.Building, 32);
|
||||
Stream.Write(ci.X);
|
||||
Stream.Write(ci.Y);
|
||||
Stream.Write(ci.Z);
|
||||
Stream.Write(ci.Map.MapID);
|
||||
Stream.Write(ci.Description);
|
||||
Stream.Write(0);
|
||||
}
|
||||
|
||||
var flags = ExpansionInfo.CoreExpansion.CharacterListFlags;
|
||||
|
||||
if (count > 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SeventhCharacterSlot |
|
||||
CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required?
|
||||
}
|
||||
else if (count == 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
|
||||
}
|
||||
else if (a.Limit == 1)
|
||||
{
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
Stream.Write((int)flags); // Additional Flags
|
||||
|
||||
Stream.Write((short)-1);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CharacterListOld : Packet
|
||||
{
|
||||
public CharacterListOld(IAccount a, CityInfo[] info) : base(0xA9)
|
||||
{
|
||||
EnsureCapacity(9 + a.Length * 60 + info.Length * 63);
|
||||
|
||||
var highSlot = -1;
|
||||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (a[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
|
||||
Stream.Write((byte)count);
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var m = a[i];
|
||||
if (m != null)
|
||||
{
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
Stream.WriteAsciiFixed(name, 30);
|
||||
Stream.Fill(30); // password
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream.Fill(60);
|
||||
}
|
||||
}
|
||||
|
||||
Stream.Write((byte)info.Length);
|
||||
|
||||
for (var i = 0; i < info.Length; ++i)
|
||||
{
|
||||
var ci = info[i];
|
||||
|
||||
Stream.Write((byte)i);
|
||||
Stream.WriteAsciiFixed(ci.City, 31);
|
||||
Stream.WriteAsciiFixed(ci.Building, 31);
|
||||
}
|
||||
|
||||
var flags = ExpansionInfo.CoreExpansion.CharacterListFlags;
|
||||
|
||||
if (count > 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SeventhCharacterSlot |
|
||||
CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required?
|
||||
}
|
||||
else if (count == 6)
|
||||
{
|
||||
flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
|
||||
}
|
||||
else if (a.Limit == 1)
|
||||
{
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
Stream.Write((int)flags); // Additional Flags
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AccountLoginRej : Packet
|
||||
{
|
||||
public AccountLoginRej(ALRReason reason) : base(0x82, 2)
|
||||
{
|
||||
Stream.Write((byte)reason);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AccountLoginAck : Packet
|
||||
{
|
||||
public AccountLoginAck(ServerInfo[] info) : base(0xA8)
|
||||
{
|
||||
EnsureCapacity(6 + info.Length * 40);
|
||||
|
||||
Stream.Write((byte)0x5D); // Unknown
|
||||
|
||||
Stream.Write((ushort)info.Length);
|
||||
|
||||
for (var i = 0; i < info.Length; ++i)
|
||||
{
|
||||
var si = info[i];
|
||||
|
||||
Stream.Write((ushort)i);
|
||||
Stream.WriteAsciiFixed(si.Name, 32);
|
||||
Stream.Write((byte)si.FullPercent);
|
||||
Stream.Write((sbyte)si.TimeZone);
|
||||
Stream.Write(Utility.GetAddressValue(si.Address.Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PlayServerAck : Packet
|
||||
{
|
||||
public PlayServerAck(ServerInfo si, int authId) : base(0x8C, 11)
|
||||
{
|
||||
var addr = Utility.GetAddressValue(si.Address.Address);
|
||||
|
||||
Stream.Write((byte)addr);
|
||||
Stream.Write((byte)(addr >> 8));
|
||||
Stream.Write((byte)(addr >> 16));
|
||||
Stream.Write((byte)(addr >> 24));
|
||||
|
||||
Stream.Write((short)si.Address.Port);
|
||||
Stream.Write(authId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
using Xunit;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Net;
|
||||
using Server.Network;
|
||||
using Xunit;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Server.Accounting;
|
||||
|
||||
namespace Server.Tests.Network
|
||||
{
|
||||
public class MockAccount : IAccount, IComparable<MockAccount>
|
||||
{
|
||||
private readonly Mobile[] m_Mobiles;
|
||||
private string m_Password;
|
||||
|
||||
public MockAccount(Mobile[] mobiles)
|
||||
{
|
||||
m_Mobiles = mobiles;
|
||||
foreach (var mobile in mobiles)
|
||||
{
|
||||
if (mobile != null)
|
||||
{
|
||||
mobile.Account = this;
|
||||
}
|
||||
}
|
||||
|
||||
Length = mobiles.Length;
|
||||
Count = mobiles.Count(t => t != null);
|
||||
Limit = mobiles.Length;
|
||||
}
|
||||
|
||||
public int TotalGold { get; private set; }
|
||||
public int TotalPlat { get; private set; }
|
||||
|
||||
public bool DepositGold(int amount)
|
||||
{
|
||||
TotalGold += amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DepositPlat(int amount)
|
||||
{
|
||||
TotalPlat += amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WithdrawGold(int amount)
|
||||
{
|
||||
if (TotalGold - amount < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TotalGold -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WithdrawPlat(int amount)
|
||||
{
|
||||
if (TotalPlat - amount < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TotalPlat -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public long GetTotalGold() => TotalGold + TotalPlat * 100;
|
||||
|
||||
public int CompareTo(IAccount other) => other == null ? 1 : Username.CompareTo(other.Username);
|
||||
|
||||
public string Username { get; set; }
|
||||
public string Email { get; set; }
|
||||
public AccessLevel AccessLevel { get; set; }
|
||||
public int Length { get; }
|
||||
public int Limit { get; }
|
||||
public int Count { get; }
|
||||
|
||||
public Mobile this[int index]
|
||||
{
|
||||
get => m_Mobiles[index];
|
||||
set => m_Mobiles[index] = value;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetPassword(string password)
|
||||
{
|
||||
m_Password = password;
|
||||
}
|
||||
|
||||
public bool CheckPassword(string password) => m_Password == password;
|
||||
|
||||
public int CompareTo(MockAccount other) => other == null ? 1 : Username.CompareTo(other.Username);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Tests.Network
|
||||
{
|
||||
public class MockSocket : ISocket
|
||||
{
|
||||
public EndPoint LocalEndPoint { get; set; }
|
||||
public EndPoint RemoteEndPoint { get; set; }
|
||||
public Task<int> SendAsync(IList<ArraySegment<byte>> buffers, SocketFlags flags) => Task.Run(() => 0);
|
||||
|
||||
public Task<int> ReceiveAsync(IList<ArraySegment<byte>> buffers, SocketFlags flags) => Task.Run(() => 0);
|
||||
|
||||
public void Shutdown(SocketShutdown how)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Tests.Network
|
||||
{
|
||||
public static class PacketTestUtilities
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Span<byte> Compile(this Packet p) =>
|
||||
p.Compile(false, out var length).AsSpan(0, length);
|
||||
|
||||
public static NetState CreateTestNetState() =>
|
||||
new NetState(new MockSocket());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue