fix: Hair and facial hair "teleporting" when mobile dies several times (#1901)
### Summary * Added World.NewVirtual for creating virtual serial numbers * Reserved range 0x7EEEEEEE to 0x7FFFFFFF for virtual serials * Hair and Facial hair (for mobiles) now use virtual serials instead of FakeSerial() functions * Consolidated virtual hair to a single `VirtualHairInfo` class. Corpse hair and facial hair now persists across save/load and hair and facial hair no longer teleport to newest corpse.
This commit is contained in:
parent
883d873c1c
commit
91e37fb8d4
15 changed files with 548 additions and 357 deletions
|
|
@ -504,13 +504,16 @@ namespace Server.Tests.Network
|
|||
|
||||
var eq = beheld.Items;
|
||||
var count = eq.Count;
|
||||
var hair = beheld.Hair;
|
||||
var facialHair = beheld.FacialHair;
|
||||
|
||||
if (beheld.HairItemID > 0)
|
||||
|
||||
if (hair != null)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if (beheld.FacialHairItemID > 0)
|
||||
if (facialHair != null)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
|
@ -570,19 +573,19 @@ namespace Server.Tests.Network
|
|||
}
|
||||
}
|
||||
|
||||
if (beheld.HairItemID > 0)
|
||||
if (hair?.ItemId > 0)
|
||||
{
|
||||
if (m_DupedLayers![(int)Layer.Hair] != m_Version)
|
||||
{
|
||||
m_DupedLayers[(int)Layer.Hair] = m_Version;
|
||||
hue = beheld.HairHue;
|
||||
hue = hair.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
{
|
||||
hue = beheld.SolidHueOverride;
|
||||
}
|
||||
|
||||
var itemID = beheld.HairItemID & itemIdMask;
|
||||
var itemID = hair.ItemId & itemIdMask;
|
||||
var writeHue = newPacket || hue != 0;
|
||||
|
||||
if (!newPacket && writeHue)
|
||||
|
|
@ -590,7 +593,7 @@ namespace Server.Tests.Network
|
|||
itemID |= 0x8000;
|
||||
}
|
||||
|
||||
Stream.Write(HairInfo.FakeSerial(beheld.Serial));
|
||||
Stream.Write(hair.VirtualSerial);
|
||||
Stream.Write((ushort)itemID);
|
||||
Stream.Write((byte)Layer.Hair);
|
||||
|
||||
|
|
@ -601,19 +604,19 @@ namespace Server.Tests.Network
|
|||
}
|
||||
}
|
||||
|
||||
if (beheld.FacialHairItemID > 0)
|
||||
if (facialHair?.ItemId > 0)
|
||||
{
|
||||
if (m_DupedLayers![(int)Layer.FacialHair] != m_Version)
|
||||
{
|
||||
m_DupedLayers[(int)Layer.FacialHair] = m_Version;
|
||||
hue = beheld.FacialHairHue;
|
||||
hue = facialHair.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
{
|
||||
hue = beheld.SolidHueOverride;
|
||||
}
|
||||
|
||||
var itemID = beheld.FacialHairItemID & itemIdMask;
|
||||
var itemID = facialHair.ItemId & itemIdMask;
|
||||
var writeHue = newPacket || hue != 0;
|
||||
|
||||
if (!newPacket && writeHue)
|
||||
|
|
@ -621,7 +624,7 @@ namespace Server.Tests.Network
|
|||
itemID |= 0x8000;
|
||||
}
|
||||
|
||||
Stream.Write(FacialHairInfo.FakeSerial(beheld.Serial));
|
||||
Stream.Write(facialHair.VirtualSerial);
|
||||
Stream.Write((ushort)itemID);
|
||||
Stream.Write((byte)Layer.FacialHair);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Server.Tests
|
|||
var expected = new HairEquipUpdate(m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendHairEquipUpdatePacket(m, HairInfo.FakeSerial(m.Serial), m.HairItemID, m.HairHue, Layer.Hair);
|
||||
ns.SendHairEquipUpdatePacket(m, (uint)m.Hair.VirtualSerial, m.Hair.ItemId, m.Hair.Hue, Layer.Hair);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
|
|
@ -32,7 +32,7 @@ namespace Server.Tests
|
|||
var expected = new RemoveHair(m).Compile();
|
||||
|
||||
var ns = PacketTestUtilities.CreateTestNetState();
|
||||
ns.SendRemoveHairPacket(HairInfo.FakeSerial(m.Serial));
|
||||
ns.SendRemoveHairPacket((uint) m.Hair.VirtualSerial);
|
||||
|
||||
var result = ns.SendPipe.Reader.AvailableToRead();
|
||||
AssertThat.Equal(result, expected);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace Server.Network
|
|||
{
|
||||
var hue = parent.SolidHueOverride >= 0 ? parent.SolidHueOverride : parent.HairHue;
|
||||
|
||||
Stream.Write(HairInfo.FakeSerial(parent.Serial));
|
||||
Stream.Write(parent.Hair.VirtualSerial);
|
||||
Stream.Write((short)parent.HairItemID);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)Layer.Hair);
|
||||
|
|
@ -23,7 +23,7 @@ namespace Server.Network
|
|||
{
|
||||
var hue = parent.SolidHueOverride >= 0 ? parent.SolidHueOverride : parent.FacialHairHue;
|
||||
|
||||
Stream.Write(FacialHairInfo.FakeSerial(parent.Serial));
|
||||
Stream.Write(parent.FacialHair.VirtualSerial);
|
||||
Stream.Write((short)parent.FacialHairItemID);
|
||||
Stream.Write((byte)0);
|
||||
Stream.Write((byte)Layer.FacialHair);
|
||||
|
|
@ -37,7 +37,7 @@ namespace Server.Network
|
|||
public RemoveHair(Mobile parent)
|
||||
: base(0x1D, 5)
|
||||
{
|
||||
Stream.Write(HairInfo.FakeSerial(parent.Serial));
|
||||
Stream.Write(parent.Hair.VirtualSerial);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ namespace Server.Network
|
|||
public RemoveFacialHair(Mobile parent)
|
||||
: base(0x1D, 5)
|
||||
{
|
||||
Stream.Write(FacialHairInfo.FakeSerial(parent.Serial));
|
||||
Stream.Write(parent.FacialHair.VirtualSerial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
Projects/Server.Tests/Tests/World/VirtualSerialTests.cs
Normal file
24
Projects/Server.Tests/Tests/World/VirtualSerialTests.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using Xunit;
|
||||
|
||||
namespace Server.Tests;
|
||||
|
||||
[Collection("Sequential Tests")]
|
||||
public class VirtualSerialTests : IClassFixture<ServerFixture>
|
||||
{
|
||||
[Fact]
|
||||
public void TestNewVirtualGetsAndRollover()
|
||||
{
|
||||
// Acquire virtual serials until we hit the max
|
||||
Serial lastSerial = World.NewVirtual;
|
||||
do
|
||||
{
|
||||
Serial virtualSerial = World.NewVirtual;
|
||||
Assert.Equal(lastSerial + 1, virtualSerial);
|
||||
lastSerial = (Serial) (uint) virtualSerial;
|
||||
} while (lastSerial != World.MaxVirtualSerial);
|
||||
|
||||
// Next one should be MaxItemSerial (the first VirtualSerial) due to rollover
|
||||
var nextSerial = World.NewVirtual;
|
||||
Assert.Equal(nextSerial, (Serial)World.ResetVirtualSerial);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue