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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,9 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: AccountPackets.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Accounting;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Network
|
||||
namespace Server.Tests.Network
|
||||
{
|
||||
public enum ALRReason : byte
|
||||
{
|
||||
Invalid = 0x00,
|
||||
InUse = 0x01,
|
||||
Blocked = 0x02,
|
||||
BadPass = 0x03,
|
||||
Idle = 0xFE,
|
||||
BadComm = 0xFF
|
||||
}
|
||||
|
||||
public enum PMMessage : byte
|
||||
{
|
||||
CharNoExist = 1,
|
||||
CharExists = 2,
|
||||
CharInWorld = 5,
|
||||
LoginSyncError = 6,
|
||||
IdleWarning = 7
|
||||
}
|
||||
|
||||
public enum DeleteResultType
|
||||
{
|
||||
PasswordInvalid,
|
||||
CharNotExist,
|
||||
CharBeingPlayed,
|
||||
CharTooYoung,
|
||||
CharQueued,
|
||||
BadRequest
|
||||
}
|
||||
|
||||
public sealed class ChangeCharacter : Packet
|
||||
{
|
||||
public ChangeCharacter(IAccount a) : base(0x81)
|
||||
|
|
@ -68,18 +25,10 @@ namespace Server.Network
|
|||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
var m = a[i];
|
||||
if (a[i] != null)
|
||||
{
|
||||
var name = a[i].Name;
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
name = "-null-";
|
||||
}
|
||||
else if ((name = name.Trim()).Length == 0)
|
||||
{
|
||||
name = "-empty-";
|
||||
}
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
|
||||
Stream.WriteAsciiFixed(name, 30);
|
||||
Stream.Fill(30); // password
|
||||
|
|
@ -92,9 +41,6 @@ namespace Server.Network
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks the client for it's version
|
||||
/// </summary>
|
||||
public sealed class ClientVersionReq : Packet
|
||||
{
|
||||
public ClientVersionReq() : base(0xBD)
|
||||
|
|
@ -125,8 +71,6 @@ namespace Server.Network
|
|||
{
|
||||
var flags = ExpansionInfo.CoreExpansion.SupportedFeatures;
|
||||
|
||||
flags |= Value;
|
||||
|
||||
if (ns.Account.Limit >= 6)
|
||||
{
|
||||
flags |= FeatureFlags.LiveAccount;
|
||||
|
|
@ -151,10 +95,6 @@ namespace Server.Network
|
|||
Stream.Write((ushort)flags);
|
||||
}
|
||||
}
|
||||
|
||||
public static FeatureFlags Value { get; set; }
|
||||
|
||||
public static SupportedFeatures Instantiate(NetState ns) => new SupportedFeatures(ns);
|
||||
}
|
||||
|
||||
public sealed class LoginConfirm : Packet
|
||||
|
|
@ -189,8 +129,6 @@ namespace Server.Network
|
|||
|
||||
public sealed class LoginComplete : Packet
|
||||
{
|
||||
public static readonly Packet Instance = SetStatic(new LoginComplete());
|
||||
|
||||
public LoginComplete() : base(0x55, 1)
|
||||
{
|
||||
}
|
||||
|
|
@ -222,7 +160,8 @@ namespace Server.Network
|
|||
|
||||
if (m != null)
|
||||
{
|
||||
Stream.WriteAsciiFixed(m.Name, 30);
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
Stream.WriteAsciiFixed(name, 30);
|
||||
Stream.Fill(30); // password
|
||||
}
|
||||
else
|
||||
|
|
@ -300,12 +239,10 @@ namespace Server.Network
|
|||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
Stream.Write((int)(flags | AdditionalFlags)); // Additional Flags
|
||||
Stream.Write((int)flags); // Additional Flags
|
||||
|
||||
Stream.Write((short)-1);
|
||||
}
|
||||
|
||||
public static CharacterListFlags AdditionalFlags { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CharacterListOld : Packet
|
||||
|
|
@ -330,9 +267,11 @@ namespace Server.Network
|
|||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
if (a[i] != null)
|
||||
var m = a[i];
|
||||
if (m != null)
|
||||
{
|
||||
Stream.WriteAsciiFixed(a[i].Name, 30);
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
Stream.WriteAsciiFixed(name, 30);
|
||||
Stream.Fill(30); // password
|
||||
}
|
||||
else
|
||||
|
|
@ -369,7 +308,7 @@ namespace Server.Network
|
|||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
Stream.Write((int)(flags | CharacterList.AdditionalFlags)); // Additional Flags
|
||||
Stream.Write((int)flags); // Additional Flags
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,9 +345,7 @@ namespace Server.Network
|
|||
|
||||
public sealed class PlayServerAck : Packet
|
||||
{
|
||||
internal static int m_AuthID = -1;
|
||||
|
||||
public PlayServerAck(ServerInfo si) : base(0x8C, 11)
|
||||
public PlayServerAck(ServerInfo si, int authId) : base(0x8C, 11)
|
||||
{
|
||||
var addr = Utility.GetAddressValue(si.Address.Address);
|
||||
|
||||
|
|
@ -418,7 +355,7 @@ namespace Server.Network
|
|||
Stream.Write((byte)(addr >> 24));
|
||||
|
||||
Stream.Write((short)si.Address.Port);
|
||||
Stream.Write(m_AuthID);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,10 @@ namespace Server.Network
|
|||
{
|
||||
}
|
||||
|
||||
public CircularBufferReader(CircularBuffer<byte> buffer) : this(buffer.GetSpan(0), buffer.GetSpan(1))
|
||||
{
|
||||
}
|
||||
|
||||
public CircularBufferReader(ReadOnlySpan<byte> first, ReadOnlySpan<byte> second)
|
||||
{
|
||||
_first = first;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ namespace System.Buffers
|
|||
public int Length { get; }
|
||||
public int Position { get; private set; }
|
||||
|
||||
public CircularBufferWriter(CircularBuffer<byte> buffer) : this(buffer.GetSpan(0), buffer.GetSpan(1))
|
||||
{
|
||||
}
|
||||
|
||||
public CircularBufferWriter(Span<byte> first, Span<byte> second)
|
||||
{
|
||||
_first = first;
|
||||
|
|
@ -153,6 +157,34 @@ namespace System.Buffers
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteLE(int value)
|
||||
{
|
||||
if (Position < _first.Length)
|
||||
{
|
||||
if (!BinaryPrimitives.TryWriteInt32LittleEndian(_first.Slice(Position), value))
|
||||
{
|
||||
// Not enough space. Split the spans
|
||||
Write((byte)(value >> 24));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Position += 4;
|
||||
}
|
||||
}
|
||||
else if (BinaryPrimitives.TryWriteInt32LittleEndian(_second.Slice(Position - _first.Length), value))
|
||||
{
|
||||
Position += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ namespace System.Buffers
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAscii(this Span<byte> span, ref int pos, string value, int max)
|
||||
{
|
||||
var length = value.Length <= max ? value.Length : max;
|
||||
var length = Math.Min(value.Length, max);
|
||||
|
||||
pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ namespace System.Buffers
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAsciiNull(this Span<byte> span, ref int pos, string value, int max)
|
||||
{
|
||||
var length = value.Length < max ? value.Length : max - 1;
|
||||
var length = Math.Min(value.Length, max - 1);
|
||||
|
||||
pos += Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
#if NO_LOCAL_INIT
|
||||
|
|
@ -172,7 +172,7 @@ namespace System.Buffers
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void WriteAsciiFixed(this Span<byte> span, ref int pos, string value, int amount)
|
||||
{
|
||||
var length = value.Length <= amount ? value.Length : amount;
|
||||
var length = Math.Min(value.Length, amount);
|
||||
#if NO_LOCAL_INIT
|
||||
int bytesWritten = Encoding.ASCII.GetBytes(value.AsSpan(0, length), span.Slice(pos, length));
|
||||
|
||||
|
|
|
|||
|
|
@ -2940,13 +2940,13 @@ namespace Server
|
|||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
ns.Send(SupportedFeatures.Instantiate(ns));
|
||||
Packets.SendSupportedFeature(ns);
|
||||
ns.Send(new MobileUpdate(this));
|
||||
ns.Send(new MobileAttributes(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
ns.Send(SupportedFeatures.Instantiate(ns));
|
||||
Packets.SendSupportedFeature(ns);
|
||||
ns.Send(new MobileUpdateOld(this));
|
||||
ns.Send(new MobileAttributes(this));
|
||||
}
|
||||
|
|
@ -3084,13 +3084,13 @@ namespace Server
|
|||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
ns.Send(SupportedFeatures.Instantiate(ns));
|
||||
Packets.SendSupportedFeature(ns);
|
||||
ns.Send(new MobileUpdate(this));
|
||||
ns.Send(new MobileAttributes(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
ns.Send(SupportedFeatures.Instantiate(ns));
|
||||
Packets.SendSupportedFeature(ns);
|
||||
ns.Send(new MobileUpdateOld(this));
|
||||
ns.Send(new MobileAttributes(this));
|
||||
}
|
||||
|
|
|
|||
36
Projects/Server/Network/ISocket.cs
Normal file
36
Projects/Server/Network/ISocket.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: ISocket.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public interface ISocket
|
||||
{
|
||||
public EndPoint LocalEndPoint { get; }
|
||||
|
||||
public EndPoint RemoteEndPoint { get; }
|
||||
|
||||
public Task<int> SendAsync(IList<ArraySegment<byte>> buffer, SocketFlags flags);
|
||||
|
||||
public Task<int> ReceiveAsync(IList<ArraySegment<byte>> buffer, SocketFlags flags);
|
||||
|
||||
public void Shutdown(SocketShutdown how);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ namespace Server.Network
|
|||
Timer.DelayCall(checkAliveDuration, checkAliveDuration, CheckAllAlive);
|
||||
}
|
||||
|
||||
public NetState(Socket connection)
|
||||
public NetState(ISocket connection)
|
||||
{
|
||||
m_Running = false;
|
||||
Connection = connection;
|
||||
|
|
@ -141,7 +141,7 @@ namespace Server.Network
|
|||
|
||||
public Pipe<byte> SendPipe { get; private set; }
|
||||
|
||||
public Socket Connection { get; private set; }
|
||||
public ISocket Connection { get; private set; }
|
||||
|
||||
public bool CompressionEnabled { get; set; }
|
||||
|
||||
|
|
@ -371,7 +371,7 @@ namespace Server.Network
|
|||
|
||||
public virtual void Send(ref CircularBuffer<byte> buffer, int length)
|
||||
{
|
||||
if (Connection == null || BlockAllPackets || buffer.Length == 0)
|
||||
if (Connection == null || BlockAllPackets || buffer.Length == 0 || length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
40
Projects/Server/Network/NetworkSocket.cs
Normal file
40
Projects/Server/Network/NetworkSocket.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: NetworkSocket.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class NetworkSocket : ISocket
|
||||
{
|
||||
public Socket Connection { get; }
|
||||
public EndPoint LocalEndPoint => Connection.LocalEndPoint;
|
||||
public EndPoint RemoteEndPoint => Connection.RemoteEndPoint;
|
||||
|
||||
public NetworkSocket(Socket connection) => Connection = connection;
|
||||
|
||||
public Task<int> SendAsync(IList<ArraySegment<byte>> buffers, SocketFlags flags) =>
|
||||
Connection.SendAsync(buffers, flags);
|
||||
|
||||
public Task<int> ReceiveAsync(IList<ArraySegment<byte>> buffers, SocketFlags flags) =>
|
||||
Connection.ReceiveAsync(buffers, flags);
|
||||
|
||||
public void Shutdown(SocketShutdown how) => Connection.Shutdown(how);
|
||||
}
|
||||
}
|
||||
|
|
@ -2060,7 +2060,7 @@ namespace Server.Network
|
|||
if (check != null && check.Map != Map.Internal && check != m)
|
||||
{
|
||||
state.WriteConsole("Account in use");
|
||||
state.Send(new PopupMessage(PMMessage.CharInWorld));
|
||||
Packets.SendPopupMessage(state, PMMessage.CharInWorld);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2076,7 +2076,7 @@ namespace Server.Network
|
|||
// TODO: Make this wait one tick so we don't have to call it unnecessarily
|
||||
NetState.ProcessDisposedQueue();
|
||||
|
||||
state.Send(new ClientVersionReq());
|
||||
Packets.SendClientVersionRequest(state);
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
|
|
@ -2096,7 +2096,7 @@ namespace Server.Network
|
|||
|
||||
public static void DoLogin(NetState state, Mobile m)
|
||||
{
|
||||
state.Send(new LoginConfirm(m));
|
||||
Packets.SendLoginConfirmation(state, m);
|
||||
|
||||
if (m.Map != null)
|
||||
{
|
||||
|
|
@ -2110,7 +2110,7 @@ namespace Server.Network
|
|||
|
||||
state.Send(SeasonChange.Instantiate(m.GetSeason(), true));
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
Packets.SendSupportedFeature(state);
|
||||
|
||||
state.Sequence = 0;
|
||||
|
||||
|
|
@ -2130,7 +2130,7 @@ namespace Server.Network
|
|||
|
||||
m.SendEverything();
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
Packets.SendSupportedFeature(state);
|
||||
state.Send(new MobileUpdate(m));
|
||||
// state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
|
|
@ -2153,7 +2153,7 @@ namespace Server.Network
|
|||
|
||||
m.SendEverything();
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
Packets.SendSupportedFeature(state);
|
||||
state.Send(new MobileUpdate(m));
|
||||
// state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
|
|
@ -2176,7 +2176,7 @@ namespace Server.Network
|
|||
|
||||
m.SendEverything();
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
Packets.SendSupportedFeature(state);
|
||||
state.Send(new MobileUpdateOld(m));
|
||||
// state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
|
|
@ -2184,7 +2184,7 @@ namespace Server.Network
|
|||
state.Send(new MobileIncomingOld(m, m));
|
||||
}
|
||||
|
||||
state.Send(LoginComplete.Instance);
|
||||
Packets.SendLoginComplete(state);
|
||||
state.Send(new CurrentTime());
|
||||
state.Send(SeasonChange.Instantiate(m.GetSeason(), true));
|
||||
if (m.Map != null)
|
||||
|
|
@ -2278,7 +2278,7 @@ namespace Server.Network
|
|||
if (check != null && check.Map != Map.Internal)
|
||||
{
|
||||
state.WriteConsole("Account in use");
|
||||
state.Send(new PopupMessage(PMMessage.CharInWorld));
|
||||
Packets.SendPopupMessage(state, PMMessage.CharInWorld);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2311,7 +2311,7 @@ namespace Server.Network
|
|||
race
|
||||
);
|
||||
|
||||
state.Send(new ClientVersionReq());
|
||||
Packets.SendClientVersionRequest(state);
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
|
|
@ -2403,7 +2403,7 @@ namespace Server.Network
|
|||
if (check != null && check.Map != Map.Internal)
|
||||
{
|
||||
state.WriteConsole("Account in use");
|
||||
state.Send(new PopupMessage(PMMessage.CharInWorld));
|
||||
Packets.SendPopupMessage(state, PMMessage.CharInWorld);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2437,7 +2437,7 @@ namespace Server.Network
|
|||
race
|
||||
);
|
||||
|
||||
state.Send(new ClientVersionReq());
|
||||
Packets.SendClientVersionRequest(state);
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
|
|
@ -2547,16 +2547,8 @@ namespace Server.Network
|
|||
state.CompressionEnabled = true;
|
||||
state.PacketEncoder = NetworkCompression.Compress;
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
|
||||
if (state.NewCharacterList)
|
||||
{
|
||||
state.Send(new CharacterList(state.Account, state.CityInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Send(new CharacterListOld(state.Account, state.CityInfo));
|
||||
}
|
||||
Packets.SendSupportedFeature(state);
|
||||
Packets.SendCharacterList(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2578,10 +2570,10 @@ namespace Server.Network
|
|||
{
|
||||
var si = info[index];
|
||||
|
||||
state.m_AuthID = PlayServerAck.m_AuthID = GenerateAuthID(state);
|
||||
state.m_AuthID = GenerateAuthID(state);
|
||||
|
||||
state.SentFirstPacket = false;
|
||||
state.Send(new PlayServerAck(si));
|
||||
Packets.SendPlayServerAck(state, si, state.m_AuthID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2679,17 +2671,14 @@ namespace Server.Network
|
|||
}
|
||||
else
|
||||
{
|
||||
var info = e.Servers.ToArray();
|
||||
|
||||
state.ServerInfo = info;
|
||||
|
||||
state.Send(new AccountLoginAck(info));
|
||||
state.ServerInfo = e.Servers.ToArray();
|
||||
Packets.SendAccountLoginAck(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AccountLogin_ReplyRej(NetState state, ALRReason reason)
|
||||
{
|
||||
state.Send(new AccountLoginRej(reason));
|
||||
Packets.SendAccountLoginRejected(state, reason);
|
||||
state.Dispose();
|
||||
}
|
||||
|
||||
|
|
|
|||
488
Projects/Server/Network/Packets/AccountPackets.cs
Normal file
488
Projects/Server/Network/Packets/AccountPackets.cs
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2020 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: AccountPackets.cs *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Server.Accounting;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public enum ALRReason : byte
|
||||
{
|
||||
Invalid = 0,
|
||||
InUse = 1,
|
||||
Blocked = 2,
|
||||
BadPass = 3,
|
||||
Idle = 254,
|
||||
BadComm = 255
|
||||
}
|
||||
|
||||
public enum PMMessage : byte
|
||||
{
|
||||
None = 0,
|
||||
CharNoExist = 1,
|
||||
CharExists = 2,
|
||||
CharInWorld = 5,
|
||||
LoginSyncError = 6,
|
||||
IdleWarning = 7
|
||||
}
|
||||
|
||||
public enum DeleteResultType
|
||||
{
|
||||
PasswordInvalid,
|
||||
CharNotExist,
|
||||
CharBeingPlayed,
|
||||
CharTooYoung,
|
||||
CharQueued,
|
||||
BadRequest
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
/**
|
||||
* Packet: 0x81
|
||||
* Length: Up to 425 bytes
|
||||
*
|
||||
* Displays the list of characters during the login process.
|
||||
* Note: Currently Unused
|
||||
*/
|
||||
public static void SendChangeCharacter(NetState ns, IAccount a)
|
||||
{
|
||||
if (ns == null || a == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var length = 5 + a.Length * 60;
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
|
||||
writer.Write((byte)0x81); // Packet ID
|
||||
writer.Write((ushort)length);
|
||||
writer.Write((ushort)0); // Count & Placeholder
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
var m = a[i];
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
writer.Clear(60);
|
||||
}
|
||||
else
|
||||
{
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
|
||||
count++;
|
||||
writer.WriteAscii(name, 30);
|
||||
writer.Clear(30); // Password (empty)
|
||||
}
|
||||
}
|
||||
|
||||
var position = writer.Position;
|
||||
writer.Seek(3, SeekOrigin.Begin);
|
||||
writer.Write((byte)count);
|
||||
writer.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
ns.Send(ref buffer, writer.Position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0xBD
|
||||
* Length: 3 bytes
|
||||
*
|
||||
* Sends a requests for the client version
|
||||
*/
|
||||
public static void SendClientVersionRequest(NetState ns)
|
||||
{
|
||||
if (ns != null && ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
buffer[0] = 0xBD; // Packet ID
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = 0x03; // Length
|
||||
|
||||
ns.Send(ref buffer, 3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x85
|
||||
* Length: 2 bytes
|
||||
*
|
||||
* Sends the result of a deletion request
|
||||
*/
|
||||
public static void SendCharacterDeleteResult(NetState ns, DeleteResultType res)
|
||||
{
|
||||
if (ns != null && ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
buffer[0] = 0x85; // Packet ID
|
||||
buffer[1] = (byte)res;
|
||||
|
||||
ns.Send(ref buffer, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x53
|
||||
* Length: 2 bytes
|
||||
*
|
||||
* Sends a PopupMessage with a predetermined message
|
||||
*/
|
||||
public static void SendPopupMessage(NetState ns, PMMessage msg)
|
||||
{
|
||||
if (ns != null && ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
buffer[0] = 0x53; // Packet ID
|
||||
buffer[1] = (byte)msg;
|
||||
|
||||
ns.Send(ref buffer, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0xB9
|
||||
* Length: 3 or 5 bytes
|
||||
*
|
||||
* Sends support features based on the client version
|
||||
*/
|
||||
public static void SendSupportedFeature(NetState ns)
|
||||
{
|
||||
if (ns == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0xB9); // Packet ID
|
||||
|
||||
if (ns.ExtendedSupportedFeatures)
|
||||
{
|
||||
writer.Write((uint)flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write((ushort)flags);
|
||||
}
|
||||
|
||||
ns.Send(ref buffer, ns.ExtendedSupportedFeatures ? 5 : 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x1B
|
||||
* Length: 37 bytes
|
||||
*
|
||||
* Sends login confirmation
|
||||
*/
|
||||
public static void SendLoginConfirmation(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0x1B); // PacketID
|
||||
writer.Write(m.Serial);
|
||||
writer.Write(0);
|
||||
writer.Write((short)m.Body);
|
||||
writer.Write((short)m.X);
|
||||
writer.Write((short)m.Y);
|
||||
writer.Write((short)m.Z);
|
||||
writer.Write((byte)m.Direction);
|
||||
writer.Write((byte)0);
|
||||
writer.Write(-1);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
var map = m.Map;
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
map = m.LogoutMap;
|
||||
}
|
||||
|
||||
writer.Write((short)(map?.Width ?? Map.Felucca.Width));
|
||||
writer.Write((short)(map?.Height ?? Map.Felucca.Height));
|
||||
writer.Clear();
|
||||
|
||||
ns.Send(ref buffer, 37);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x55
|
||||
* Length: 1 byte
|
||||
*
|
||||
* Sends login completion
|
||||
*/
|
||||
public static void SendLoginComplete(NetState ns)
|
||||
{
|
||||
if (ns != null && ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
buffer[0] = 0x55; // Packet ID
|
||||
|
||||
ns.Send(ref buffer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x86
|
||||
* Length: Up to 424 bytes
|
||||
*
|
||||
* Sends updated character list
|
||||
*/
|
||||
public static void SendCharacterListUpdate(NetState ns, IAccount a)
|
||||
{
|
||||
if (ns == null || a == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0x86); // Packet ID
|
||||
writer.Seek(2, SeekOrigin.Current); // Length
|
||||
|
||||
var highSlot = -1;
|
||||
|
||||
for (var i = a.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (a[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
writer.Write((byte)count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var m = a[i];
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
writer.Clear(60);
|
||||
}
|
||||
else
|
||||
{
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
writer.WriteAscii(name, 30);
|
||||
writer.Clear(30); // password
|
||||
}
|
||||
}
|
||||
|
||||
writer.WritePacketLength();
|
||||
ns.Send(ref buffer, writer.Position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0xA9
|
||||
* Length: 1410 or more bytes
|
||||
*
|
||||
* Sends list of characters and starting cities.
|
||||
*/
|
||||
public static void SendCharacterList(NetState ns)
|
||||
{
|
||||
var acct = ns?.Account;
|
||||
|
||||
if (acct == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var client70130 = ns.NewCharacterList;
|
||||
var textLength = client70130 ? 32 : 31;
|
||||
|
||||
var cityInfo = ns.CityInfo;
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0xA9); // Packet ID
|
||||
writer.Seek(2, SeekOrigin.Current); // Length
|
||||
|
||||
var highSlot = -1;
|
||||
|
||||
for (var i = acct.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (acct[i] != null)
|
||||
{
|
||||
highSlot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var count = Math.Max(Math.Max(highSlot + 1, acct.Limit), 5);
|
||||
writer.Write((byte)count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var m = acct[i];
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
writer.Clear(60);
|
||||
}
|
||||
else
|
||||
{
|
||||
var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
|
||||
writer.WriteAscii(name, 30);
|
||||
writer.Clear(30); // password
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write((byte)cityInfo.Length);
|
||||
|
||||
for (int i = 0; i < cityInfo.Length; ++i)
|
||||
{
|
||||
var ci = cityInfo[i];
|
||||
|
||||
writer.Write((byte)i);
|
||||
writer.WriteAscii(ci.City, textLength);
|
||||
writer.WriteAscii(ci.Building, textLength);
|
||||
if (client70130)
|
||||
{
|
||||
writer.Write(ci.X);
|
||||
writer.Write(ci.Y);
|
||||
writer.Write(ci.Z);
|
||||
writer.Write(ci.Map.MapID);
|
||||
writer.Write(ci.Description);
|
||||
writer.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 (acct.Limit == 1)
|
||||
{
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
}
|
||||
|
||||
writer.Write((int)flags);
|
||||
if (client70130)
|
||||
{
|
||||
writer.Write((short)-1);
|
||||
}
|
||||
|
||||
writer.WritePacketLength();
|
||||
ns.Send(ref buffer, writer.Position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x82
|
||||
* Length: 2 bytes
|
||||
*
|
||||
* Sends a reason for rejecting the login
|
||||
*/
|
||||
public static void SendAccountLoginRejected(NetState ns, ALRReason reason)
|
||||
{
|
||||
if (ns != null && ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
buffer[0] = 0x82; // Packet ID
|
||||
buffer[1] = (byte)reason;
|
||||
|
||||
ns.Send(ref buffer, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0xA8
|
||||
* Length: up to 240 bytes
|
||||
*
|
||||
* Sends login acknowledge with server listing
|
||||
*/
|
||||
public static void SendAccountLoginAck(NetState ns)
|
||||
{
|
||||
if (ns == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0xA8); // Packet ID
|
||||
writer.Seek(2, SeekOrigin.Current); // Length
|
||||
|
||||
writer.Write((byte)0x5D);
|
||||
|
||||
var info = ns.ServerInfo;
|
||||
writer.Write((ushort)info.Length);
|
||||
|
||||
for (var i = 0; i < info.Length; ++i)
|
||||
{
|
||||
var si = info[i];
|
||||
|
||||
writer.Write((ushort)i);
|
||||
writer.WriteAscii(si.Name, 32);
|
||||
writer.Write((byte)si.FullPercent);
|
||||
writer.Write((sbyte)si.TimeZone);
|
||||
writer.Write(Utility.GetAddressValue(si.Address.Address));
|
||||
}
|
||||
|
||||
writer.WritePacketLength();
|
||||
ns.Send(ref buffer, writer.Position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet: 0x8C
|
||||
* Length: 11 bytes
|
||||
*
|
||||
* Sends acknowledge play server
|
||||
*/
|
||||
public static void SendPlayServerAck(NetState ns, ServerInfo si, int authId)
|
||||
{
|
||||
if (ns == null || !ns.SendPipe.Writer.GetAvailable(out var buffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var writer = new CircularBufferWriter(buffer);
|
||||
writer.Write((byte)0x8C); // Packet ID
|
||||
|
||||
var addr = Utility.GetAddressValue(si.Address.Address);
|
||||
writer.WriteLE(addr);
|
||||
writer.Write((short)si.Address.Port);
|
||||
writer.Write(authId);
|
||||
|
||||
ns.Send(ref buffer, writer.Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ namespace Server.Network
|
|||
// ignored
|
||||
}
|
||||
|
||||
var ns = new NetState(socket);
|
||||
var ns = new NetState(new NetworkSocket(socket));
|
||||
m_ConnectedQueue.Enqueue(ns);
|
||||
ns.Start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,11 +218,14 @@ namespace Server.Misc
|
|||
if (!(state.Account is Account acct))
|
||||
{
|
||||
state.Dispose();
|
||||
return;
|
||||
}
|
||||
else if (index < 0 || index >= acct.Length)
|
||||
|
||||
DeleteResultType res;
|
||||
|
||||
if (index < 0 || index >= acct.Length)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.BadRequest));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
res = DeleteResultType.BadRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -230,25 +233,21 @@ namespace Server.Misc
|
|||
|
||||
if (m == null)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.CharNotExist));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
res = DeleteResultType.CharNotExist;
|
||||
}
|
||||
else if (m.NetState != null)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.CharBeingPlayed));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
res = DeleteResultType.CharBeingPlayed;
|
||||
}
|
||||
else if (RestrictDeletion && DateTime.UtcNow < m.CreationTime + DeleteDelay)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.CharTooYoung));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
res = DeleteResultType.CharTooYoung;
|
||||
}
|
||||
else if (m.AccessLevel == AccessLevel.Player &&
|
||||
Region.Find(m.LogoutLocation, m.LogoutMap).IsPartOf<JailRegion>()
|
||||
) // Don't need to check current location, if netstate is null, they're logged out
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.BadRequest));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
res = DeleteResultType.BadRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -257,9 +256,14 @@ namespace Server.Misc
|
|||
acct.Comments.Add(new AccountComment("System", $"Character #{index + 1} {m} deleted by {state}"));
|
||||
|
||||
m.Delete();
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
Packets.SendCharacterListUpdate(state, acct);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Packets.SendCharacterDeleteResult(state, res);
|
||||
Packets.SendCharacterListUpdate(state, acct);
|
||||
|
||||
}
|
||||
|
||||
public static bool CanCreate(IPAddress ip) =>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue