fix(party): Converts party packets (#401)

- [X] Converts party packets
This commit is contained in:
Kamron Batman 2021-01-10 14:23:10 -08:00 • committed by GitHub
parent f52e63f320
commit f4dd7c8e7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 459 additions and 197 deletions

View file

@ -3,10 +3,9 @@
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.0-preview-20201123-03" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.0-preview-20210106-01" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
<PackageReference Include="Zlib.Bindings" Version="1.4.0" /> <PackageReference Include="Zlib.Bindings" Version="1.4.0" />
<ProjectReference Include="..\Server\Server.csproj" /> <ProjectReference Include="..\Server\Server.csproj" />
<ProjectReference Include="..\UOContent\UOContent.csproj" /> <ProjectReference Include="..\UOContent\UOContent.csproj" />

View file

@ -1151,9 +1151,9 @@ namespace Server
{ {
if (state.HighSeas) if (state.HighSeas)
{ {
if (hsWorldItem[0] == 0) var length = OutgoingItemPackets.CreateWorldItemNew(hsWorldItem, this, true);
if (length != hsWorldItem.Length)
{ {
var length = OutgoingItemPackets.CreateWorldItemNew(hsWorldItem, this, true);
hsWorldItem = hsWorldItem.Slice(0, length); hsWorldItem = hsWorldItem.Slice(0, length);
} }
@ -1161,9 +1161,9 @@ namespace Server
} }
else if (state.StygianAbyss) else if (state.StygianAbyss)
{ {
if (saWorldItem[0] == 0) var length = OutgoingItemPackets.CreateWorldItemNew(saWorldItem, this, false);
if (length != saWorldItem.Length)
{ {
var length = OutgoingItemPackets.CreateWorldItemNew(saWorldItem, this, false);
saWorldItem = saWorldItem.Slice(0, length); saWorldItem = saWorldItem.Slice(0, length);
} }
@ -1171,9 +1171,9 @@ namespace Server
} }
else else
{ {
if (oldWorldItem[0] == 0) var length = OutgoingItemPackets.CreateWorldItem(oldWorldItem, this);
if (length != oldWorldItem.Length)
{ {
var length = OutgoingItemPackets.CreateWorldItem(oldWorldItem, this);
oldWorldItem = oldWorldItem.Slice(0, length); oldWorldItem = oldWorldItem.Slice(0, length);
} }
@ -3091,11 +3091,7 @@ namespace Server
return; return;
} }
if (opl[0] == 0) OutgoingEntityPackets.CreateOPLInfo(opl, this);
{
OutgoingEntityPackets.CreateOPLInfo(opl, this);
}
ns.Send(opl); ns.Send(opl);
} }

View file

@ -24,6 +24,11 @@ namespace Server
public static void CreateHairEquipUpdatePacket(Span<byte> buffer, Mobile m, Serial hairSerial, Layer layer) public static void CreateHairEquipUpdatePacket(Span<byte> buffer, Mobile m, Serial hairSerial, Layer layer)
{ {
if (buffer[0] != 0)
{
return;
}
var hue = m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.HairHue; var hue = m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.HairHue;
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
@ -51,6 +56,11 @@ namespace Server
public static void CreateRemoveHairPacket(Span<byte> buffer, Serial hairSerial) public static void CreateRemoveHairPacket(Span<byte> buffer, Serial hairSerial)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0x1D); // Packet ID writer.Write((byte)0x1D); // Packet ID
writer.Write(hairSerial); writer.Write(hairSerial);

View file

@ -3191,11 +3191,7 @@ namespace Server
if (IsDeadBondedPet) if (IsDeadBondedPet)
{ {
if (deadBuffer[0] == 0) OutgoingMobilePackets.CreateBondedStatus(deadBuffer, Serial, true);
{
OutgoingMobilePackets.CreateBondedStatus(deadBuffer, Serial, true);
}
state.Send(deadBuffer); state.Send(deadBuffer);
} }
} }
@ -3209,21 +3205,13 @@ namespace Server
{ {
if (sendHealthbarPoison) if (sendHealthbarPoison)
{ {
if (hbpBuffer[0] == 0) OutgoingMobilePackets.CreateMobileHealthbar(hbpBuffer, this, Healthbar.Poison);
{
OutgoingMobilePackets.CreateMobileHealthbar(hbpBuffer, this, Healthbar.Poison);
}
state.Send(hbpBuffer); state.Send(hbpBuffer);
} }
if (sendHealthbarYellow) if (sendHealthbarYellow)
{ {
if (hbyBuffer[0] == 0) OutgoingMobilePackets.CreateMobileHealthbar(hbyBuffer, this, Healthbar.Yellow);
{
OutgoingMobilePackets.CreateMobileHealthbar(hbyBuffer, this, Healthbar.Yellow);
}
state.Send(hbyBuffer); state.Send(hbyBuffer);
} }
} }
@ -3232,51 +3220,36 @@ namespace Server
{ {
if (CanBeRenamedBy(beholder)) if (CanBeRenamedBy(beholder))
{ {
if (statBufferTrue[0] == 0) OutgoingMobilePackets.CreateMobileStatusCompact(statBufferTrue, this, true);
{
OutgoingMobilePackets.CreateMobileStatusCompact(statBufferTrue, this, true);
}
state.Send(statBufferTrue); state.Send(statBufferTrue);
} }
else else
{ {
if (statBufferFalse[0] == 0) OutgoingMobilePackets.CreateMobileStatusCompact(statBufferFalse, this, false);
{
OutgoingMobilePackets.CreateMobileStatusCompact(statBufferFalse, this, false);
}
state.Send(statBufferFalse); state.Send(statBufferFalse);
} }
} }
else if (sendHits) else if (sendHits)
{ {
if (hitsPacket[0] == 0) OutgoingMobilePackets.CreateMobileHits(hitsPacket, this, true);
{
OutgoingMobilePackets.CreateMobileHits(hitsPacket, this, true);
}
state.Send(hitsPacket); state.Send(hitsPacket);
} }
if (sendHair) if (sendHair)
{ {
if (hairPacket[0] == 0) var hairSerial = HairInfo.FakeSerial(Serial);
if (removeHair)
{ {
var hairSerial = HairInfo.FakeSerial(Serial); OutgoingVirtualHairPackets.CreateRemoveHairPacket(hairPacket, hairSerial);
if (removeHair) }
{ else
OutgoingVirtualHairPackets.CreateRemoveHairPacket(hairPacket, hairSerial); {
} OutgoingVirtualHairPackets.CreateHairEquipUpdatePacket(
else hairPacket,
{ this,
OutgoingVirtualHairPackets.CreateHairEquipUpdatePacket( hairSerial,
hairPacket, Layer.Hair
this, );
hairSerial,
Layer.Hair
);
}
} }
state.Send(hairPacket); state.Send(hairPacket);
@ -3284,24 +3257,20 @@ namespace Server
if (sendFacialHair) if (sendFacialHair)
{ {
if (facialhairPacket[0] == 0) var hairSerial = HairInfo.FakeSerial(Serial);
if (removeFacialHair)
{ {
var hairSerial = HairInfo.FakeSerial(Serial); OutgoingVirtualHairPackets.CreateRemoveHairPacket(facialhairPacket, hairSerial);
if (removeFacialHair) }
{ else
OutgoingVirtualHairPackets.CreateRemoveHairPacket(facialhairPacket, hairSerial); {
} OutgoingVirtualHairPackets.CreateHairEquipUpdatePacket(
else facialhairPacket,
{ this,
OutgoingVirtualHairPackets.CreateHairEquipUpdatePacket( hairSerial,
facialhairPacket, Layer.FacialHair
this, );
hairSerial,
Layer.FacialHair
);
}
} }
state.Send(facialhairPacket); state.Send(facialhairPacket);
} }
@ -5024,11 +4993,7 @@ namespace Server
{ {
if (state != m_NetState) if (state != m_NetState)
{ {
if (deathAnimation[0] == 0) OutgoingMobilePackets.CreateDeathAnimation(deathAnimation, Serial, corpseSerial);
{
OutgoingMobilePackets.CreateDeathAnimation(deathAnimation, Serial, corpseSerial);
}
state.Send(deathAnimation); state.Send(deathAnimation);
if (!state.Mobile.CanSee(this)) if (!state.Mobile.CanSee(this))

View file

@ -28,6 +28,11 @@ namespace Server.Network
public static void CreateOPLInfo(Span<byte> buffer, Serial serial, int hash) public static void CreateOPLInfo(Span<byte> buffer, Serial serial, int hash)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xDC); // Packet ID writer.Write((byte)0xDC); // Packet ID
writer.Write(serial); writer.Write(serial);

View file

@ -25,6 +25,11 @@ namespace Server.Network
public static int CreateWorldItem(Span<byte> buffer, Item item) public static int CreateWorldItem(Span<byte> buffer, Item item)
{ {
if (buffer[0] != 0)
{
return buffer.Length;
}
var itemID = item is BaseMulti ? item.ItemID | 0x4000 : item.ItemID & 0x3FFF; var itemID = item is BaseMulti ? item.ItemID | 0x4000 : item.ItemID & 0x3FFF;
var hasAmount = item.Amount != 0; var hasAmount = item.Amount != 0;
var amount = item.Amount; var amount = item.Amount;
@ -95,6 +100,11 @@ namespace Server.Network
public static int CreateWorldItemNew(Span<byte> buffer, Item item, bool isHS) public static int CreateWorldItemNew(Span<byte> buffer, Item item, bool isHS)
{ {
if (buffer[0] != 0)
{
return buffer.Length;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xF3); // Packet ID writer.Write((byte)0xF3); // Packet ID
writer.Write((short)0x1); // command writer.Write((short)0x1); // command

View file

@ -49,6 +49,7 @@ namespace Server.Network
ns.Send(buffer.Slice(0, length)); ns.Send(buffer.Slice(0, length));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetMaxMessageLocalizedLength(string args) => 50 + (args?.Length ?? 0) * 2; public static int GetMaxMessageLocalizedLength(string args) => 50 + (args?.Length ?? 0) * 2;
public static int CreateMessageLocalized( public static int CreateMessageLocalized(
@ -104,6 +105,7 @@ namespace Server.Network
ns.Send(buffer.Slice(0, length)); ns.Send(buffer.Slice(0, length));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetMaxMessageLocalizedAffixLength(string affix, string args) => public static int GetMaxMessageLocalizedAffixLength(string affix, string args) =>
52 + (affix?.Length ?? 0) + (args?.Length ?? 0) * 2; 52 + (affix?.Length ?? 0) + (args?.Length ?? 0) * 2;
@ -145,7 +147,6 @@ namespace Server.Network
return writer.Position; return writer.Position;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SendMessage( public static void SendMessage(
this NetState ns, this NetState ns,
Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, string lang, string name, string text Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, string lang, string name, string text

View file

@ -39,6 +39,11 @@ namespace Server.Network
public static void CreateBondedStatus(Span<byte> buffer, Serial serial, bool bonded) public static void CreateBondedStatus(Span<byte> buffer, Serial serial, bool bonded)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xBF); // Packet ID writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)11); // Length writer.Write((ushort)11); // Length
@ -68,6 +73,11 @@ namespace Server.Network
public static void CreateDeathAnimation(Span<byte> buffer, Serial killed, Serial corpse) public static void CreateDeathAnimation(Span<byte> buffer, Serial killed, Serial corpse)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xAF); // Packet ID writer.Write((byte)0xAF); // Packet ID
writer.Write(killed); writer.Write(killed);
@ -194,6 +204,11 @@ namespace Server.Network
public static void CreateMobileHits(Span<byte> buffer, Mobile m, bool normalize = false) public static void CreateMobileHits(Span<byte> buffer, Mobile m, bool normalize = false)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xA1); // Packet ID writer.Write((byte)0xA1); // Packet ID
writer.Write(m.Serial); writer.Write(m.Serial);
@ -214,6 +229,11 @@ namespace Server.Network
public static void CreateMobileMana(Span<byte> buffer, Mobile m, bool normalize = false) public static void CreateMobileMana(Span<byte> buffer, Mobile m, bool normalize = false)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xA2); // Packet ID writer.Write((byte)0xA2); // Packet ID
writer.Write(m.Serial); writer.Write(m.Serial);
@ -234,6 +254,11 @@ namespace Server.Network
public static void CreateMobileStam(Span<byte> buffer, Mobile m, bool normalize = false) public static void CreateMobileStam(Span<byte> buffer, Mobile m, bool normalize = false)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0xA3); // Packet ID writer.Write((byte)0xA3); // Packet ID
writer.Write(m.Serial); writer.Write(m.Serial);
@ -254,6 +279,11 @@ namespace Server.Network
public static void CreateMobileAttributes(Span<byte> buffer, Mobile m, bool normalize = false) public static void CreateMobileAttributes(Span<byte> buffer, Mobile m, bool normalize = false)
{ {
if (buffer[0] != 0)
{
return;
}
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0x2D); // Packet ID writer.Write((byte)0x2D); // Packet ID
writer.Write(m.Serial); writer.Write(m.Serial);
@ -355,6 +385,11 @@ namespace Server.Network
public static void CreateMobileHealthbar(Span<byte> buffer, Mobile m, Healthbar healthbar) public static void CreateMobileHealthbar(Span<byte> buffer, Mobile m, Healthbar healthbar)
{ {
if (buffer[0] != 0)
{
return;
}
switch (healthbar) switch (healthbar)
{ {
case Healthbar.Poison: case Healthbar.Poison:
@ -442,20 +477,20 @@ namespace Server.Network
Span<byte> buffer, Mobile beholder, Mobile beheld, int version, bool canBeRenamed Span<byte> buffer, Mobile beholder, Mobile beheld, int version, bool canBeRenamed
) )
{ {
if (buffer[0] != 0)
{
return buffer.Length;
}
var name = beheld.Name ?? ""; var name = beheld.Name ?? "";
var writer = new SpanWriter(buffer); var writer = new SpanWriter(buffer);
writer.Write((byte)0x11); // Packet ID writer.Write((byte)0x11); // Packet ID
writer.Seek(2, SeekOrigin.Current); writer.Seek(2, SeekOrigin.Current);
writer.Write(beheld.Serial); writer.Write(beheld.Serial);
writer.WriteAscii(name, 30); writer.WriteAscii(name, 30);
writer.WriteAttribute(beheld.HitsMax, beheld.Hits, version == 0, true); writer.WriteAttribute(beheld.HitsMax, beheld.Hits, version == 0, true);
writer.Write(canBeRenamed); writer.Write(canBeRenamed);
writer.Write((byte)version); writer.Write((byte)version);
if (version <= 0) if (version <= 0)

View file

@ -4,14 +4,14 @@ namespace Server.Engines.PartySystem
{ {
public sealed class PartyEmptyList : Packet public sealed class PartyEmptyList : Packet
{ {
public PartyEmptyList(Mobile m) : base(0xBF) public PartyEmptyList(Serial m) : base(0xBF)
{ {
EnsureCapacity(7); EnsureCapacity(7);
Stream.Write((short)0x0006); Stream.Write((short)0x0006);
Stream.Write((byte)0x02); Stream.Write((byte)0x02);
Stream.Write((byte)0); Stream.Write((byte)0);
Stream.Write(m.Serial); Stream.Write(m);
} }
} }
@ -34,7 +34,7 @@ namespace Server.Engines.PartySystem
public sealed class PartyRemoveMember : Packet public sealed class PartyRemoveMember : Packet
{ {
public PartyRemoveMember(Mobile removed, Party p) : base(0xBF) public PartyRemoveMember(Serial removed, Party p) : base(0xBF)
{ {
EnsureCapacity(11 + p.Count * 4); EnsureCapacity(11 + p.Count * 4);
@ -42,7 +42,7 @@ namespace Server.Engines.PartySystem
Stream.Write((byte)0x02); Stream.Write((byte)0x02);
Stream.Write((byte)p.Count); Stream.Write((byte)p.Count);
Stream.Write(removed.Serial); Stream.Write(removed);
for (var i = 0; i < p.Count; ++i) for (var i = 0; i < p.Count; ++i)
{ {
@ -53,31 +53,28 @@ namespace Server.Engines.PartySystem
public sealed class PartyTextMessage : Packet public sealed class PartyTextMessage : Packet
{ {
public PartyTextMessage(bool toAll, Mobile from, string text) : base(0xBF) public PartyTextMessage(bool toAll, Serial from, string text) : base(0xBF)
{ {
if (text == null) text ??= "";
{
text = "";
}
EnsureCapacity(12 + text.Length * 2); EnsureCapacity(12 + text.Length * 2);
Stream.Write((short)0x0006); Stream.Write((short)0x0006);
Stream.Write((byte)(toAll ? 0x04 : 0x03)); Stream.Write((byte)(toAll ? 0x04 : 0x03));
Stream.Write(from.Serial); Stream.Write(from);
Stream.WriteBigUniNull(text); Stream.WriteBigUniNull(text);
} }
} }
public sealed class PartyInvitation : Packet public sealed class PartyInvitation : Packet
{ {
public PartyInvitation(Mobile leader) : base(0xBF) public PartyInvitation(Serial leader) : base(0xBF)
{ {
EnsureCapacity(10); EnsureCapacity(10);
Stream.Write((short)0x0006); Stream.Write((short)0x0006);
Stream.Write((byte)0x07); Stream.Write((byte)0x07);
Stream.Write(leader.Serial); Stream.Write(leader);
} }
} }
} }

View file

@ -0,0 +1,99 @@
using System;
using Server;
using Server.Engines.PartySystem;
using Server.Tests;
using Server.Tests.Network;
using Xunit;
namespace UOContent.Tests
{
public class PartyPacketTests : IClassFixture<ServerFixture>
{
[Fact]
public void TestPartyEmptyList()
{
Serial m = 0x1024u;
var expected = new PartyEmptyList(m).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendPartyRemoveMember(m);
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
[Fact]
public void TestPartyRemoveMember()
{
var leader = new Mobile(0x1024u);
leader.DefaultMobileInit();
var member = new Mobile(0x2048u);
member.DefaultMobileInit();
var p = new Party(leader);
p.Add(member);
var expected = new PartyRemoveMember(member.Serial, p).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendPartyRemoveMember(member.Serial, p);
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
[Fact]
public void TestPartyMemberList()
{
var leader = new Mobile(0x1024u);
leader.DefaultMobileInit();
var member = new Mobile(0x2048u);
member.DefaultMobileInit();
var p = new Party(leader);
p.Add(member);
var expected = new PartyMemberList(p).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendPartyMemberList(p);
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void TestPartyTextMessage(bool toAll)
{
Serial serial = 0x1024u;
var text = "[Party] Stuff Happens";
var expected = new PartyTextMessage(toAll, serial, text).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendPartyTextMessage(serial, text, toAll);
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
[Fact]
public void TestPartyInvitation()
{
Serial m = 0x1024u;
var expected = new PartyInvitation(m).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendPartyInvitation(m);
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
}
}

View file

@ -8,7 +8,7 @@ using Xunit;
namespace UOContent.Tests namespace UOContent.Tests
{ {
public class PacketTests : IClassFixture<ServerFixture> public class CorpsePacketTests : IClassFixture<ServerFixture>
{ {
[Fact] [Fact]
public void TestCorpseEquipPacket() public void TestCorpseEquipPacket()

View file

@ -1,5 +1,4 @@
using System.IO; using System.IO;
using Server;
using Server.Items; using Server.Items;
namespace Server.Network namespace Server.Network

View file

@ -3,10 +3,9 @@
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.0-preview-20201123-03" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.0-preview-20210106-01" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
<ProjectReference Include="..\Server\Server.csproj" /> <ProjectReference Include="..\Server\Server.csproj" />
<ProjectReference Include="..\Server.Tests\Server.Tests.csproj" /> <ProjectReference Include="..\Server.Tests\Server.Tests.csproj" />
<ProjectReference Include="..\UOContent\UOContent.csproj" /> <ProjectReference Include="..\UOContent\UOContent.csproj" />

View file

@ -9,7 +9,7 @@ namespace Server.Engines.PartySystem
public class Party : IParty public class Party : IParty
{ {
public const int Capacity = 10; public const int Capacity = 10;
private readonly List<Mobile> m_Listeners; // staff listening private readonly HashSet<Mobile> m_Listeners; // staff listening
public Party(Mobile leader) public Party(Mobile leader)
{ {
@ -17,7 +17,7 @@ namespace Server.Engines.PartySystem
Members = new List<PartyMemberInfo>(); Members = new List<PartyMemberInfo>();
Candidates = new List<Mobile>(); Candidates = new List<Mobile>();
m_Listeners = new List<Mobile>(); m_Listeners = new HashSet<Mobile>();
Members.Add(new PartyMemberInfo(leader)); Members.Add(new PartyMemberInfo(leader));
} }
@ -185,33 +185,34 @@ namespace Server.Engines.PartySystem
public void Add(Mobile m) public void Add(Mobile m)
{ {
var mi = this[m]; var mi = this[m];
if (mi != null)
if (mi == null)
{ {
var ns = m.NetState; return;
Members.Add(new PartyMemberInfo(m)); }
m.Party = this;
var memberList = Packet.Acquire(new PartyMemberList(this)); var ns = m.NetState;
Span<byte> attrsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributesPacketLength]; Members.Add(new PartyMemberInfo(m));
OutgoingMobilePackets.CreateMobileAttributes(attrsPacket, m, true); m.Party = this;
for (var i = 0; i < Members.Count; ++i) Span<byte> memberList =
stackalloc byte[PartyPackets.GetPartyMemberListPacketLength(this)].InitializePacket();
Span<byte> attrsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributesPacketLength].InitializePacket();
for (var i = 0; i < Members.Count; ++i)
{
var f = Members[i].Mobile;
PartyPackets.CreatePartyMemberList(memberList, this);
f.NetState?.Send(memberList);
if (f != m)
{ {
var f = Members[i].Mobile; f.NetState.SendMobileStatusCompact(m, m.CanBeRenamedBy(f));
OutgoingMobilePackets.CreateMobileAttributes(attrsPacket, m, true);
f.Send(memberList); f.NetState?.Send(attrsPacket);
ns.SendMobileStatusCompact(f, f.CanBeRenamedBy(m));
if (f != m) ns.SendMobileAttributes(f, true);
{
f.NetState.SendMobileStatusCompact(m, m.CanBeRenamedBy(f));
f.NetState?.Send(attrsPacket);
ns.SendMobileStatusCompact(f, f.CanBeRenamedBy(m));
ns.SendMobileAttributes(f, true);
}
} }
Packet.Release(memberList);
} }
} }
@ -245,7 +246,9 @@ namespace Server.Engines.PartySystem
); );
// : joined the party. // : joined the party.
SendToAll(buffer.Slice(0, length), true); buffer = buffer.Slice(0, length);
SendToAll(buffer);
SendToAllListeners(buffer);
from.SendLocalizedMessage(1005445); // You have been added to the party. from.SendLocalizedMessage(1005445); // You have been added to the party.
@ -261,18 +264,21 @@ namespace Server.Engines.PartySystem
from.SendLocalizedMessage(1008092); // You notify them that you do not wish to join the party. from.SendLocalizedMessage(1008092); // You notify them that you do not wish to join the party.
Candidates.Remove(from); Candidates.Remove(from);
from.Send(new PartyEmptyList(from)); from.NetState.SendPartyRemoveMember(from.Serial);
if (Candidates.Count == 0 && Members.Count <= 1) if (Candidates.Count != 0 || Members.Count > 1)
{ {
for (var i = 0; i < Members.Count; ++i) return;
{
this[i].Mobile.Send(new PartyEmptyList(this[i].Mobile));
this[i].Mobile.Party = null;
}
Members.Clear();
} }
for (var i = 0; i < Members.Count; ++i)
{
var m = this[i].Mobile;
m.NetState.SendPartyRemoveMember(m.Serial);
m.Party = null;
}
Members.Clear();
} }
public void Remove(Mobile m) public void Remove(Mobile m)
@ -283,18 +289,22 @@ namespace Server.Engines.PartySystem
return; return;
} }
for (var i = 0; i < Members.Count; ++i) Span<byte> removeMember =
stackalloc byte[PartyPackets.GetPartyRemoveMemberPacketLength(this)].InitializePacket();
for (var i = 0; i < Members.Count; i++)
{ {
if (Members[i].Mobile == m) if (Members[i].Mobile == m)
{ {
Members.RemoveAt(i); Members.RemoveAt(i);
m.NetState.SendPartyRemoveMember(m.Serial);
m.Party = null; m.Party = null;
m.Send(new PartyEmptyList(m));
m.SendLocalizedMessage(1005451); // You have been removed from the party. m.SendLocalizedMessage(1005451); // You have been removed from the party.
SendToAll(new PartyRemoveMember(m, this)); PartyPackets.CreatePartyRemoveMember(removeMember, m.Serial, this);
SendToAll(removeMember);
SendToAll(1005452); // A player has been removed from your party. SendToAll(1005452); // A player has been removed from your party.
break; break;
@ -316,8 +326,9 @@ namespace Server.Engines.PartySystem
for (var i = 0; i < Members.Count; ++i) for (var i = 0; i < Members.Count; ++i)
{ {
this[i].Mobile.Send(new PartyEmptyList(this[i].Mobile)); var m = this[i].Mobile;
this[i].Mobile.Party = null; m.NetState.SendPartyRemoveMember(m.Serial);
m.Party = null;
} }
Members.Clear(); Members.Clear();
@ -362,7 +373,7 @@ namespace Server.Engines.PartySystem
from.SendLocalizedMessage(1008090); // You have invited them to join the party. from.SendLocalizedMessage(1008090); // You have invited them to join the party.
target.Send(new PartyInvitation(from)); target.NetState.SendPartyInvitation(from.Serial);
target.Party = from; target.Party = from;
DeclineTimer.Start(target, from); DeclineTimer.Start(target, from);
@ -377,41 +388,28 @@ namespace Server.Engines.PartySystem
Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args
); );
SendToAll(buffer.Slice(0, length), true); buffer = buffer.Slice(0, length);
SendToAll(buffer);
SendToAllListeners(buffer);
} }
public void SendPublicMessage(Mobile from, string text) public void SendPublicMessage(Mobile from, string text)
{ {
SendToAll(new PartyTextMessage(true, from, text)); Span<byte> textMessagePacket =
stackalloc byte[PartyPackets.GetPartyTextMessagePacketLength(text)].InitializePacket();
PartyPackets.CreatePartyTextMessage(textMessagePacket, from.Serial, text, true);
SendToAll(textMessagePacket);
for (var i = 0; i < m_Listeners.Count; ++i) SendToAllListeners($"[{from.Name}]: {text}");
{ SendToStaffMessage(from, $"[Party]: {text}");
var mob = m_Listeners[i];
if (mob.Party != this)
{
m_Listeners[i].SendMessage("[{0}]: {1}", from.Name, text);
}
}
SendToStaffMessage(from, "[Party]: {0}", text);
} }
public void SendPrivateMessage(Mobile from, Mobile to, string text) public void SendPrivateMessage(Mobile from, Mobile to, string text)
{ {
to.Send(new PartyTextMessage(false, from, text)); to.NetState.SendPartyTextMessage(from.Serial, text, false);
SendToAllListeners($"[{from.Name}]->[{to.Name}]: {text}");
for (var i = 0; i < m_Listeners.Count; ++i) SendToStaffMessage(from, $"[Party]->[{to.Name}]: {text}");
{
var mob = m_Listeners[i];
if (mob.Party != this)
{
m_Listeners[i].SendMessage("[{0}]->[{1}]: {2}", from.Name, to.Name, text);
}
}
SendToStaffMessage(from, "[Party]->[{0}]: {1}", to.Name, text);
} }
private void SendToStaffMessage(Mobile from, string text) private void SendToStaffMessage(Mobile from, string text)
@ -448,42 +446,39 @@ namespace Server.Engines.PartySystem
} }
} }
private void SendToStaffMessage(Mobile from, string format, params object[] args) public void SendToAllListeners(string text)
{ {
SendToStaffMessage(from, string.Format(format, args)); if (m_Listeners.Count == 0)
}
public void SendToAll(Packet p)
{
p.Acquire();
for (var i = 0; i < Members.Count; ++i)
{ {
Members[i].Mobile.Send(p); return;
} }
p.Release(); Span<byte> buffer =
stackalloc byte[OutgoingMessagePackets.GetMaxMessageLength(text)].InitializePacket();
OutgoingMessagePackets.CreateMessage(
buffer, Serial.MinusOne, -1, MessageType.Regular, 0x3B2,
3, false, "ENU", "System", text
);
SendToAllListeners(buffer);
} }
public void SendToAll(Span<byte> span, bool isSpeech) public void SendToAllListeners(Span<byte> span)
{
foreach (var mob in m_Listeners)
{
if (mob.Party != this)
{
mob.NetState?.Send(span);
}
}
}
public void SendToAll(Span<byte> span)
{ {
for (var i = 0; i < Members.Count; ++i) for (var i = 0; i < Members.Count; ++i)
{ {
Members[i].Mobile.NetState?.Send(span); Members[i].Mobile.NetState?.Send(span);
} }
if (isSpeech)
{
for (var i = 0; i < m_Listeners.Count; ++i)
{
var mob = m_Listeners[i];
if (mob.Party != this)
{
mob.NetState?.Send(span);
}
}
}
} }
private class RejoinTimer : Timer private class RejoinTimer : Timer
@ -502,12 +497,10 @@ namespace Server.Engines.PartySystem
} }
m_Mobile.SendLocalizedMessage(1005437); // You have rejoined the party. m_Mobile.SendLocalizedMessage(1005437); // You have rejoined the party.
m_Mobile.Send(new PartyMemberList(p)); m_Mobile.NetState.SendPartyMemberList(p);
Span<byte> buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedAffixLength(m_Mobile.Name, "")].InitializePacket(); Span<byte> buffer = stackalloc byte[OutgoingMessagePackets.GetMaxMessageLocalizedAffixLength(m_Mobile.Name, "")].InitializePacket();
Span<byte> attrsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributesPacketLength].InitializePacket();
Span<byte> attrsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributesPacketLength];
OutgoingMobilePackets.CreateMobileAttributes(attrsPacket, m_Mobile, true);
var ns = m_Mobile.NetState; var ns = m_Mobile.NetState;
@ -540,6 +533,7 @@ namespace Server.Engines.PartySystem
m.NetState?.Send(buffer); m.NetState?.Send(buffer);
m.NetState.SendMobileStatusCompact(m_Mobile, m_Mobile.CanBeRenamedBy(m)); m.NetState.SendMobileStatusCompact(m_Mobile, m_Mobile.CanBeRenamedBy(m));
OutgoingMobilePackets.CreateMobileAttributes(attrsPacket, m_Mobile, true);
m.NetState?.Send(attrsPacket); m.NetState?.Send(attrsPacket);
ns.SendMobileStatusCompact(m, m.CanBeRenamedBy(m_Mobile)); ns.SendMobileStatusCompact(m, m.CanBeRenamedBy(m_Mobile));
ns.SendMobileAttributes(m, true); ns.SendMobileAttributes(m, true);

View file

@ -0,0 +1,153 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2021 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: PartyPackets.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.Buffers;
using System.Runtime.CompilerServices;
using Server.Network;
namespace Server.Engines.PartySystem
{
public static class PartyPackets
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetPartyMemberListPacketLength(Party p) => 7 + p.Count * 4;
public static void CreatePartyMemberList(Span<byte> buffer, Party p)
{
if (buffer[0] != 0)
{
return;
}
var length = GetPartyMemberListPacketLength(p);
var writer = new SpanWriter(buffer);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)length);
writer.Write((ushort)0x06); // Sub-packet
writer.Write((byte)0x01); // Command
writer.Write((byte)p.Count);
for (var i = 0; i < p.Count; ++i)
{
writer.Write(p[i].Mobile.Serial);
}
}
public static void SendPartyMemberList(this NetState ns, Party p)
{
if (ns == null)
{
return;
}
Span<byte> buffer = stackalloc byte[GetPartyMemberListPacketLength(p)];
CreatePartyMemberList(buffer, p);
ns.Send(buffer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetPartyRemoveMemberPacketLength(Party p) => 11 + (p?.Count * 4 ?? 0);
public static void SendPartyRemoveMember(this NetState ns, Serial m, Party p = null)
{
if (ns == null)
{
return;
}
Span<byte> buffer = stackalloc byte[GetPartyRemoveMemberPacketLength(p)];
CreatePartyRemoveMember(buffer, m, p);
ns.Send(buffer);
}
public static void CreatePartyRemoveMember(Span<byte> buffer, Serial removed, Party p = null)
{
if (buffer[0] != 0)
{
return;
}
var length = GetPartyRemoveMemberPacketLength(p);
var writer = new SpanWriter(buffer);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)length);
writer.Write((ushort)0x06); // Sub-packet
writer.Write((byte)0x02); // Command
var count = p?.Count ?? 0;
writer.Write((byte)count);
writer.Write(removed);
for (var i = 0; i < count; ++i)
{
writer.Write(p![i].Mobile.Serial);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetPartyTextMessagePacketLength(string text) => 12 + (text?.Length * 2 ?? 0);
public static void SendPartyTextMessage(this NetState ns, Serial m, string text, bool toAll)
{
if (ns == null)
{
return;
}
Span<byte> buffer = stackalloc byte[GetPartyTextMessagePacketLength(text)];
CreatePartyTextMessage(buffer, m, text, toAll);
ns.Send(buffer);
}
public static void CreatePartyTextMessage(Span<byte> buffer, Serial m, string text, bool toAll)
{
if (buffer[0] != 0)
{
return;
}
var length = GetPartyTextMessagePacketLength(text);
var writer = new SpanWriter(buffer);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)length);
writer.Write((ushort)0x06); // Sub-packet
writer.Write((byte)(toAll ? 0x04 : 0x03));
writer.Write(m);
writer.WriteBigUniNull(text);
}
public static void SendPartyInvitation(this NetState ns, Serial leader)
{
if (ns == null)
{
return;
}
Span<byte> buffer = stackalloc byte[10];
var writer = new SpanWriter(buffer);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)10);
writer.Write((ushort)0x06); // Sub-packet
writer.Write((byte)0x07); // command
writer.Write(leader);
ns.Send(buffer);
}
}
}

View file

@ -28,7 +28,7 @@
<ProjectReference Include="..\Server\Server.csproj" Private="false" PrivateAssets="All" IncludeAssets="None"> <ProjectReference Include="..\Server\Server.csproj" Private="false" PrivateAssets="All" IncludeAssets="None">
<IncludeInPackage>false</IncludeInPackage> <IncludeInPackage>false</IncludeInPackage>
</ProjectReference> </ProjectReference>
<PackageReference Include="MailKit" Version="2.10.0" /> <PackageReference Include="MailKit" Version="2.10.1" />
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.0.0-preview4" /> <PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.0.0-preview4" />
<PackageReference Include="Zlib.Bindings" Version="1.4.0" /> <PackageReference Include="Zlib.Bindings" Version="1.4.0" />
<PackageReference Include="Argon2.Bindings" Version="1.8.0" /> <PackageReference Include="Argon2.Bindings" Version="1.8.0" />