fix(core): Converts virtual hair packets (#388)

- [X] Converts virtual hair packets
This commit is contained in:
Kamron Batman 2021-01-05 22:14:54 -08:00 committed by GitHub
parent 30ef0761cb
commit 0912876f7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 214 additions and 86 deletions

View file

@ -1,7 +1,4 @@
using System; using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using Server.Gumps; using Server.Gumps;
using Server.Network; using Server.Network;
using Xunit; using Xunit;

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Buffers;
using Server.Network; using Server.Network;
using Xunit; using Xunit;

View file

@ -590,7 +590,7 @@ namespace Server.Tests.Network
itemID |= 0x8000; itemID |= 0x8000;
} }
Stream.Write(HairInfo.FakeSerial(beheld)); Stream.Write(HairInfo.FakeSerial(beheld.Serial));
Stream.Write((ushort)itemID); Stream.Write((ushort)itemID);
Stream.Write((byte)Layer.Hair); Stream.Write((byte)Layer.Hair);
@ -621,7 +621,7 @@ namespace Server.Tests.Network
itemID |= 0x8000; itemID |= 0x8000;
} }
Stream.Write(FacialHairInfo.FakeSerial(beheld)); Stream.Write(FacialHairInfo.FakeSerial(beheld.Serial));
Stream.Write((ushort)itemID); Stream.Write((ushort)itemID);
Stream.Write((byte)Layer.FacialHair); Stream.Write((byte)Layer.FacialHair);

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Buffers;
using Server.HuePickers; using Server.HuePickers;
using Server.Network; using Server.Network;
using Xunit; using Xunit;

View file

@ -1,7 +1,5 @@
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Server.Network; using Server.Network;
using Xunit; using Xunit;

View file

@ -0,0 +1,40 @@
using System;
using Server.Network;
using Server.Tests.Network;
using Xunit;
namespace Server.Tests
{
public class VirtualHairPacketTests: IClassFixture<ServerFixture>
{
[Fact]
public void TestSendVirtualHairUpdate()
{
var m = new Mobile(0x1024u);
m.DefaultMobileInit();
var expected = new HairEquipUpdate(m).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendHairEquipUpdatePacket(m, HairInfo.FakeSerial(m.Serial), Layer.Hair);
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
[Fact]
public void TestSendRemoveVirtualHair()
{
var m = new Mobile(0x1024u);
m.DefaultMobileInit();
var expected = new RemoveHair(m).Compile();
using var ns = PacketTestUtilities.CreateTestNetState();
ns.SendRemoveHairPacket(HairInfo.FakeSerial(m.Serial));
var result = ns.SendPipe.Reader.TryRead();
AssertThat.Equal(result.Buffer[0].AsSpan(0), expected);
}
}
}

View file

@ -0,0 +1,52 @@
namespace Server.Network
{
public sealed class HairEquipUpdate : Packet
{
public HairEquipUpdate(Mobile parent)
: base(0x2E, 15)
{
var hue = parent.SolidHueOverride >= 0 ? parent.SolidHueOverride : parent.HairHue;
Stream.Write(HairInfo.FakeSerial(parent.Serial));
Stream.Write((short)parent.HairItemID);
Stream.Write((byte)0);
Stream.Write((byte)Layer.Hair);
Stream.Write(parent.Serial);
Stream.Write((short)hue);
}
}
public sealed class FacialHairEquipUpdate : Packet
{
public FacialHairEquipUpdate(Mobile parent)
: base(0x2E, 15)
{
var hue = parent.SolidHueOverride >= 0 ? parent.SolidHueOverride : parent.FacialHairHue;
Stream.Write(FacialHairInfo.FakeSerial(parent.Serial));
Stream.Write((short)parent.FacialHairItemID);
Stream.Write((byte)0);
Stream.Write((byte)Layer.FacialHair);
Stream.Write(parent.Serial);
Stream.Write((short)hue);
}
}
public sealed class RemoveHair : Packet
{
public RemoveHair(Mobile parent)
: base(0x1D, 5)
{
Stream.Write(HairInfo.FakeSerial(parent.Serial));
}
}
public sealed class RemoveFacialHair : Packet
{
public RemoveFacialHair(Mobile parent)
: base(0x1D, 5)
{
Stream.Write(FacialHairInfo.FakeSerial(parent.Serial));
}
}
}

View file

@ -1,7 +1,62 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using Server.Network; using Server.Network;
namespace Server namespace Server
{ {
public static class OutgoingVirtualHairPackets
{
public const int EquipUpdatePacketLength = 15;
public const int RemovePacketLength = 5;
public static void SendHairEquipUpdatePacket(this NetState ns, Mobile m, Serial hairSerial, Layer layer)
{
if (ns == null)
{
return;
}
Span<byte> buffer = stackalloc byte[EquipUpdatePacketLength];
CreateHairEquipUpdatePacket(buffer, m, hairSerial, layer);
ns.Send(buffer);
}
public static void CreateHairEquipUpdatePacket(Span<byte> buffer, Mobile m, Serial hairSerial, Layer layer)
{
var hue = m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.HairHue;
var writer = new SpanWriter(buffer);
writer.Write((byte)0x2E); // Packet ID
writer.Write(hairSerial);
writer.Write((short)m.HairItemID);
writer.Write((byte)0);
writer.Write((byte)layer);
writer.Write(m.Serial);
writer.Write((short)hue);
}
public static void SendRemoveHairPacket(this NetState ns, Serial hairSerial)
{
if (ns == null)
{
return;
}
Span<byte> buffer = stackalloc byte[RemovePacketLength];
CreateRemoveHairPacket(buffer, hairSerial);
ns.Send(buffer);
}
public static void CreateRemoveHairPacket(Span<byte> buffer, Serial hairSerial)
{
var writer = new SpanWriter(buffer);
writer.Write((byte)0x1D); // Packet ID
writer.Write(hairSerial);
}
}
public abstract class BaseHairInfo public abstract class BaseHairInfo
{ {
protected BaseHairInfo(int itemid, int hue = 0) protected BaseHairInfo(int itemid, int hue = 0)
@ -57,7 +112,8 @@ namespace Server
} }
// TODO: Can we make this higher for newer clients? // TODO: Can we make this higher for newer clients?
public static uint FakeSerial(Mobile parent) => 0x7FFFFFFF - 0x400 - parent.Serial * 4; [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint FakeSerial(Serial m) => 0x7FFFFFFF - 0x400 - m * 4;
} }
public class FacialHairInfo : BaseHairInfo public class FacialHairInfo : BaseHairInfo
@ -77,57 +133,8 @@ namespace Server
{ {
} }
// TOOD: Can we make this higher for newer clients? // TODO: Can we make this higher for newer clients?
public static uint FakeSerial(Mobile parent) => 0x7FFFFFFF - 0x400 - 1 - parent.Serial * 4; [MethodImpl(MethodImplOptions.AggressiveInlining)]
} public static uint FakeSerial(Serial m) => 0x7FFFFFFF - 0x400 - 1 - m * 4;
public sealed class HairEquipUpdate : Packet
{
public HairEquipUpdate(Mobile parent)
: base(0x2E, 15)
{
var hue = parent.SolidHueOverride >= 0 ? parent.SolidHueOverride : parent.HairHue;
Stream.Write(HairInfo.FakeSerial(parent));
Stream.Write((short)parent.HairItemID);
Stream.Write((byte)0);
Stream.Write((byte)Layer.Hair);
Stream.Write(parent.Serial);
Stream.Write((short)hue);
}
}
public sealed class FacialHairEquipUpdate : Packet
{
public FacialHairEquipUpdate(Mobile parent)
: base(0x2E, 15)
{
var hue = parent.SolidHueOverride >= 0 ? parent.SolidHueOverride : parent.FacialHairHue;
Stream.Write(FacialHairInfo.FakeSerial(parent));
Stream.Write((short)parent.FacialHairItemID);
Stream.Write((byte)0);
Stream.Write((byte)Layer.FacialHair);
Stream.Write(parent.Serial);
Stream.Write((short)hue);
}
}
public sealed class RemoveHair : Packet
{
public RemoveHair(Mobile parent)
: base(0x1D, 5)
{
Stream.Write(HairInfo.FakeSerial(parent));
}
}
public sealed class RemoveFacialHair : Packet
{
public RemoveFacialHair(Mobile parent)
: base(0x1D, 5)
{
Stream.Write(FacialHairInfo.FakeSerial(parent));
}
} }
} }

View file

@ -3101,11 +3101,11 @@ namespace Server
{ {
if (removeHair) if (removeHair)
{ {
ourState.Send(new RemoveHair(this)); ourState.SendRemoveHairPacket(HairInfo.FakeSerial(Serial));
} }
else else
{ {
ourState.Send(new HairEquipUpdate(this)); ourState.SendHairEquipUpdatePacket(this, HairInfo.FakeSerial(Serial), Layer.Hair);
} }
} }
@ -3113,11 +3113,11 @@ namespace Server
{ {
if (removeFacialHair) if (removeFacialHair)
{ {
ourState.Send(new RemoveFacialHair(this)); ourState.SendRemoveHairPacket(FacialHairInfo.FakeSerial(Serial));
} }
else else
{ {
ourState.Send(new FacialHairEquipUpdate(this)); ourState.SendHairEquipUpdatePacket(this, FacialHairInfo.FakeSerial(Serial), Layer.FacialHair);
} }
} }
@ -3144,9 +3144,6 @@ namespace Server
return; return;
} }
Packet hairPacket = null;
Packet facialhairPacket = null;
var eable = Map.GetClientsInRange(m_Location); var eable = Map.GetClientsInRange(m_Location);
Span<byte> statBufferTrue = stackalloc byte[OutgoingMobilePackets.MobileStatusCompactLength]; Span<byte> statBufferTrue = stackalloc byte[OutgoingMobilePackets.MobileStatusCompactLength];
@ -3170,6 +3167,20 @@ namespace Server
Span<byte> hitsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributePacketLength]; Span<byte> hitsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributePacketLength];
hitsPacket.InitializePacket(); hitsPacket.InitializePacket();
var hairLength = removeHair
? OutgoingVirtualHairPackets.RemovePacketLength
: OutgoingVirtualHairPackets.EquipUpdatePacketLength;
Span<byte> hairPacket = stackalloc byte[hairLength];
hairPacket.InitializePacket();
var facialHairLength = removeFacialHair
? OutgoingVirtualHairPackets.RemovePacketLength
: OutgoingVirtualHairPackets.EquipUpdatePacketLength;
Span<byte> facialhairPacket = stackalloc byte[facialHairLength];
facialhairPacket.InitializePacket();
foreach (var state in eable) foreach (var state in eable)
{ {
var beholder = state.Mobile; var beholder = state.Mobile;
@ -3265,18 +3276,46 @@ namespace Server
if (sendHair) if (sendHair)
{ {
hairPacket ??= removeHair if (hairPacket[0] == 0)
? Packet.Acquire(new RemoveHair(this)) {
: Packet.Acquire(new HairEquipUpdate(this)); var hairSerial = HairInfo.FakeSerial(Serial);
if (removeHair)
{
OutgoingVirtualHairPackets.CreateRemoveHairPacket(hairPacket, hairSerial);
}
else
{
OutgoingVirtualHairPackets.CreateHairEquipUpdatePacket(
hairPacket,
this,
hairSerial,
Layer.Hair
);
}
}
state.Send(hairPacket); state.Send(hairPacket);
} }
if (sendFacialHair) if (sendFacialHair)
{ {
facialhairPacket ??= removeFacialHair if (facialhairPacket[0] == 0)
? Packet.Acquire(new RemoveFacialHair(this)) {
: Packet.Acquire(new FacialHairEquipUpdate(this)); var hairSerial = HairInfo.FakeSerial(Serial);
if (removeFacialHair)
{
OutgoingVirtualHairPackets.CreateRemoveHairPacket(facialhairPacket, hairSerial);
}
else
{
OutgoingVirtualHairPackets.CreateHairEquipUpdatePacket(
facialhairPacket,
this,
hairSerial,
Layer.FacialHair
);
}
}
state.Send(facialhairPacket); state.Send(facialhairPacket);
} }
@ -3284,9 +3323,6 @@ namespace Server
SendOPLPacketTo(state); SendOPLPacketTo(state);
} }
Packet.Release(hairPacket);
Packet.Release(facialhairPacket);
eable.Free(); eable.Free();
} }

View file

@ -614,7 +614,7 @@ namespace Server.Network
itemID |= 0x8000; itemID |= 0x8000;
} }
writer.Write(HairInfo.FakeSerial(beheld)); writer.Write(HairInfo.FakeSerial(beheld.Serial));
writer.Write((ushort)itemID); writer.Write((ushort)itemID);
writer.Write((byte)Layer.Hair); writer.Write((byte)Layer.Hair);
@ -637,7 +637,7 @@ namespace Server.Network
itemID |= 0x8000; itemID |= 0x8000;
} }
writer.Write(FacialHairInfo.FakeSerial(beheld)); writer.Write(FacialHairInfo.FakeSerial(beheld.Serial));
writer.Write((ushort)itemID); writer.Write((ushort)itemID);
writer.Write((byte)Layer.FacialHair); writer.Write((byte)Layer.FacialHair);

View file

@ -38,13 +38,13 @@ namespace Server.Network
if (beheld.Hair?.ItemID > 0) if (beheld.Hair?.ItemID > 0)
{ {
Stream.Write((byte)(Layer.Hair + 1)); Stream.Write((byte)(Layer.Hair + 1));
Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2); Stream.Write(HairInfo.FakeSerial(beheld.Owner.Serial) - 2);
} }
if (beheld.FacialHair?.ItemID > 0) if (beheld.FacialHair?.ItemID > 0)
{ {
Stream.Write((byte)(Layer.FacialHair + 1)); Stream.Write((byte)(Layer.FacialHair + 1));
Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2); Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner.Serial) - 2);
} }
Stream.Write((byte)Layer.Invalid); Stream.Write((byte)Layer.Invalid);
@ -98,7 +98,7 @@ namespace Server.Network
if (beheld.Hair?.ItemID > 0) if (beheld.Hair?.ItemID > 0)
{ {
Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2); Stream.Write(HairInfo.FakeSerial(beheld.Owner.Serial) - 2);
Stream.Write((ushort)beheld.Hair.ItemID); Stream.Write((ushort)beheld.Hair.ItemID);
Stream.Write((byte)0); // signed, itemID offset Stream.Write((byte)0); // signed, itemID offset
Stream.Write((ushort)1); Stream.Write((ushort)1);
@ -112,7 +112,7 @@ namespace Server.Network
if (beheld.FacialHair?.ItemID > 0) if (beheld.FacialHair?.ItemID > 0)
{ {
Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2); Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner.Serial) - 2);
Stream.Write((ushort)beheld.FacialHair.ItemID); Stream.Write((ushort)beheld.FacialHair.ItemID);
Stream.Write((byte)0); // signed, itemID offset Stream.Write((byte)0); // signed, itemID offset
Stream.Write((ushort)1); Stream.Write((ushort)1);
@ -177,7 +177,7 @@ namespace Server.Network
if (beheld.Hair?.ItemID > 0) if (beheld.Hair?.ItemID > 0)
{ {
Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2); Stream.Write(HairInfo.FakeSerial(beheld.Owner.Serial) - 2);
Stream.Write((ushort)beheld.Hair.ItemID); Stream.Write((ushort)beheld.Hair.ItemID);
Stream.Write((byte)0); // signed, itemID offset Stream.Write((byte)0); // signed, itemID offset
Stream.Write((ushort)1); Stream.Write((ushort)1);
@ -192,7 +192,7 @@ namespace Server.Network
if (beheld.FacialHair?.ItemID > 0) if (beheld.FacialHair?.ItemID > 0)
{ {
Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2); Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner.Serial) - 2);
Stream.Write((ushort)beheld.FacialHair.ItemID); Stream.Write((ushort)beheld.FacialHair.ItemID);
Stream.Write((byte)0); // signed, itemID offset Stream.Write((byte)0); // signed, itemID offset
Stream.Write((ushort)1); Stream.Write((ushort)1);