diff --git a/Projects/Server/Network/Packets/AttributeNormalizer.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/AttributeNormalizer.cs similarity index 100% rename from Projects/Server/Network/Packets/AttributeNormalizer.cs rename to Projects/Server.Tests/Tests/Network/Packets/Outgoing/AttributeNormalizer.cs diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs index 5873b1f6f..01f551bdd 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePacketTests.cs @@ -286,7 +286,7 @@ namespace Server.Tests.Network [InlineData(ProtocolChanges.Version7000, 10, 1024, 0, 0)] [InlineData(ProtocolChanges.Version7000, 10, 1024, 11, 2048)] public void TestMobileIncoming( - ProtocolChanges protocolChanges, int hairItemId, int hairHue, int facialHairItemId, int facialHairHue + ProtocolChanges changes, int hairItemId, int hairHue, int facialHairItemId, int facialHairHue ) { var beholder = new Mobile(0x1) @@ -320,143 +320,14 @@ namespace Server.Tests.Network beheld.FacialHairItemID = facialHairItemId; beheld.FacialHairHue = facialHairHue; - var ns = new NetState(null) - { - ProtocolChanges = protocolChanges - }; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.ProtocolChanges = changes; - var data = new MobileIncoming(ns, beholder, beheld).Compile(); + var expected = new MobileIncoming(ns, beholder, beheld).Compile(); + ns.SendMobileIncoming(beholder, beheld); - var sa = ns.StygianAbyss; - var newPacket = ns.NewMobileIncoming; - var itemIdMask = newPacket ? 0xFFFF : 0x7FFF; - - Span layers = stackalloc bool[256]; -#if NO_LOCAL_INIT - layers.Clear(); -#endif - - var items = beheld.Items; - var count = items.Count; - - if (beheld.HairItemID > 0) - { - count++; - } - - if (beheld.FacialHairItemID > 0) - { - count++; - } - - var length = 23 + count * 9; // Max Size - - Span expectedData = stackalloc byte[length]; - var pos = 0; - - expectedData.Write(ref pos, (byte)0x78); - pos += 2; // Length - - var isSolidHue = beheld.SolidHueOverride >= 0; - - expectedData.Write(ref pos, beheld.Serial); - expectedData.Write(ref pos, (ushort)beheld.Body); - expectedData.Write(ref pos, (ushort)beheld.X); - expectedData.Write(ref pos, (ushort)beheld.Y); - expectedData.Write(ref pos, (byte)beheld.Z); - expectedData.Write(ref pos, (byte)beheld.Direction); - expectedData.Write(ref pos, (ushort)(isSolidHue ? beheld.SolidHueOverride : beheld.Hue)); - expectedData.Write(ref pos, (byte)beheld.GetPacketFlags(sa)); - expectedData.Write(ref pos, (byte)Notoriety.Compute(beholder, beheld)); - - byte layer; - - for (var i = 0; i < items.Count; i++) - { - var item = items[i]; - - layer = (byte)item.Layer; - - if (!item.Deleted && !layers[layer] && beholder.CanSee(item)) - { - layers[layer] = true; - - expectedData.Write(ref pos, item.Serial); - - var hue = isSolidHue ? beheld.SolidHueOverride : item.Hue; - var itemID = item.ItemID & itemIdMask; - var writeHue = newPacket || hue != 0; - - if (!newPacket) - { - itemID |= 0x8000; - } - - expectedData.Write(ref pos, (ushort)itemID); - expectedData.Write(ref pos, layer); - if (writeHue) - { - expectedData.Write(ref pos, (ushort)hue); - } - } - } - - layer = (byte)Layer.Hair; - var itemId = beheld.HairItemID; - - if (itemId > 0 && !layers[layer]) - { - expectedData.Write(ref pos, HairInfo.FakeSerial(beheld)); - var hue = isSolidHue ? beheld.SolidHueOverride : beheld.HairHue; - itemId &= itemIdMask; - var writeHue = newPacket || hue != 0; - - if (!newPacket) - { - itemId |= 0x8000; - } - - expectedData.Write(ref pos, (ushort)itemId); - expectedData.Write(ref pos, layer); - if (writeHue) - { - expectedData.Write(ref pos, (ushort)hue); - } - } - - layer = (byte)Layer.FacialHair; - itemId = beheld.FacialHairItemID; - - if (itemId > 0 && !layers[layer]) - { - expectedData.Write(ref pos, FacialHairInfo.FakeSerial(beheld)); - var hue = isSolidHue ? beheld.SolidHueOverride : beheld.FacialHairHue; - itemId &= itemIdMask; - var writeHue = newPacket || hue != 0; - - if (!newPacket) - { - itemId |= 0x8000; - } - - expectedData.Write(ref pos, (ushort)itemId); - expectedData.Write(ref pos, layer); - if (writeHue) - { - expectedData.Write(ref pos, (ushort)hue); - } - } - -#if NO_LOCAL_INIT - expectedData.Write(ref pos, 0); // Zero serial, terminate list -#else - pos += 4; -#endif - - expectedData.Slice(1, 2).Write((ushort)pos); // Length - expectedData = expectedData.Slice(0, pos); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } } diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs index 8f9d94b8d..d1e8bb3f8 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs @@ -1,3 +1,4 @@ +using System.Threading; using Server.Network; namespace Server.Tests.Network @@ -486,4 +487,152 @@ namespace Server.Tests.Network Stream.Write((sbyte)m.Z); } } + + public sealed class MobileIncoming : Packet + { + private static readonly ThreadLocal m_DupedLayersTL = new(() => new int[256]); + private static readonly ThreadLocal m_VersionTL = new(); + + public MobileIncoming(NetState ns, Mobile beholder, Mobile beheld) : base(0x78) + { + var sa = ns.StygianAbyss; + var newPacket = ns.NewMobileIncoming; + var itemIdMask = newPacket ? 0xFFFF : 0x7FFF; + + var m_Version = ++m_VersionTL.Value; + var m_DupedLayers = m_DupedLayersTL.Value; + + var eq = beheld.Items; + var count = eq.Count; + + if (beheld.HairItemID > 0) + { + count++; + } + + if (beheld.FacialHairItemID > 0) + { + count++; + } + + EnsureCapacity(23 + count * 9); + + var hue = beheld.Hue; + + if (beheld.SolidHueOverride >= 0) + { + hue = beheld.SolidHueOverride; + } + + Stream.Write(beheld.Serial); + Stream.Write((short)beheld.Body); + Stream.Write((short)beheld.X); + Stream.Write((short)beheld.Y); + Stream.Write((sbyte)beheld.Z); + Stream.Write((byte)beheld.Direction); + Stream.Write((short)hue); + Stream.Write((byte)beheld.GetPacketFlags(sa)); + Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + for (var i = 0; i < eq.Count; ++i) + { + var item = eq[i]; + + var layer = (byte)item.Layer; + + if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if (beheld.SolidHueOverride >= 0) + { + hue = beheld.SolidHueOverride; + } + + var itemID = item.ItemID & itemIdMask; + var writeHue = newPacket || hue != 0; + + if (!newPacket) + { + itemID |= 0x8000; + } + + Stream.Write(item.Serial); + Stream.Write((ushort)itemID); + Stream.Write(layer); + + if (writeHue) + { + Stream.Write((short)hue); + } + } + } + + if (beheld.HairItemID > 0) + { + if (m_DupedLayers[(int)Layer.Hair] != m_Version) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if (beheld.SolidHueOverride >= 0) + { + hue = beheld.SolidHueOverride; + } + + var itemID = beheld.HairItemID & itemIdMask; + var writeHue = newPacket || hue != 0; + + if (!newPacket) + { + itemID |= 0x8000; + } + + Stream.Write(HairInfo.FakeSerial(beheld)); + Stream.Write((ushort)itemID); + Stream.Write((byte)Layer.Hair); + + if (writeHue) + { + Stream.Write((short)hue); + } + } + } + + if (beheld.FacialHairItemID > 0) + { + if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if (beheld.SolidHueOverride >= 0) + { + hue = beheld.SolidHueOverride; + } + + var itemID = beheld.FacialHairItemID & itemIdMask; + var writeHue = newPacket || hue != 0; + + if (!newPacket) + { + itemID |= 0x8000; + } + + Stream.Write(FacialHairInfo.FakeSerial(beheld)); + Stream.Write((ushort)itemID); + Stream.Write((byte)Layer.FacialHair); + + if (writeHue) + { + Stream.Write((short)hue); + } + } + } + + Stream.Write(0); // terminate + } + } } diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index ca8062a9f..95682e66a 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -1177,9 +1177,6 @@ namespace Server m_LightLevel = value; CheckLightLevels(false); - - /*if (m_NetState != null) - m_NetState.Send( new PersonalLightLevel( this ) );*/ } } } @@ -2474,9 +2471,6 @@ namespace Server } } - // [CommandProperty( AccessLevel.GameMaster )] - // public int HairSerial { get { return HairInfo.FakeSerial( this ); } } - [CommandProperty(AccessLevel.GameMaster)] public int FacialHairItemID { @@ -2500,9 +2494,6 @@ namespace Server } } - // [CommandProperty( AccessLevel.GameMaster )] - // public int FacialHairSerial { get { return FacialHairInfo.FakeSerial( this ); } } - [CommandProperty(AccessLevel.GameMaster)] public int HairHue { @@ -2831,7 +2822,7 @@ namespace Server Send(new ServerChange(m_Location, m_Map)); } - ns.Send(new MobileIncoming(ns, this, this)); + ns.SendMobileIncoming(this, this); ns.SendMobileUpdate(this); CheckLightLevels(true); @@ -2841,7 +2832,7 @@ namespace Server SendEverything(); SendIncomingPacket(); - ns?.Send(new MobileIncoming(ns, this, this)); + ns.SendMobileIncoming(this, this); ns.SendSupportedFeature(); ns.SendMobileUpdate(this); ns.SendMobileAttributes(this); @@ -3044,7 +3035,7 @@ namespace Server if (sendIncoming) { - ourState.Send(new MobileIncoming(ourState, this, this)); + ourState.SendMobileIncoming(this, this); } if (sendMoving || !ourState.StygianAbyss && (sendHealthbarPoison || sendHealthbarYellow)) @@ -3201,7 +3192,7 @@ namespace Server if (sendIncoming) { - state.Send(new MobileIncoming(state, beholder, this)); + state.SendMobileIncoming(beholder, this); if (IsDeadBondedPet) { @@ -3635,7 +3626,7 @@ namespace Server if (m_NetState != null && CanSee(attacker) && Utility.InUpdateRange(m_Location, attacker.m_Location)) { - m_NetState.Send(new MobileIncoming(m_NetState, this, attacker)); + m_NetState.SendMobileIncoming(this, attacker); } } } @@ -3659,7 +3650,7 @@ namespace Server if (m_NetState != null && CanSee(defender) && Utility.InUpdateRange(m_Location, defender.m_Location)) { - m_NetState.Send(new MobileIncoming(m_NetState, this, defender)); + m_NetState.SendMobileIncoming(this, defender); } } } @@ -4072,7 +4063,7 @@ namespace Server if (CanSee(aggressor)) { - m_NetState?.Send(new MobileIncoming(m_NetState, this, aggressor)); + m_NetState.SendMobileIncoming(this, aggressor); } if (Combatant == null) @@ -4095,7 +4086,7 @@ namespace Server if (CanSee(aggressor)) { - m_NetState?.Send(new MobileIncoming(m_NetState, this, aggressor)); + m_NetState.SendMobileIncoming(this, aggressor); } if (Combatant == null) @@ -4134,7 +4125,7 @@ namespace Server if (m_NetState != null && CanSee(aggressed)) { - m_NetState.Send(new MobileIncoming(m_NetState, this, aggressed)); + m_NetState.SendMobileIncoming(this, aggressed); } break; @@ -4164,7 +4155,7 @@ namespace Server if (m_NetState != null && CanSee(aggressor)) { - m_NetState.Send(new MobileIncoming(m_NetState, this, aggressor)); + m_NetState.SendMobileIncoming(this, aggressor); } break; @@ -7160,7 +7151,7 @@ namespace Server { if (CanSee(m) && Utility.InUpdateRange(m_Location, m.m_Location)) { - ns.Send(new MobileIncoming(ns, this, m)); + ns.SendMobileIncoming(this, m); if (ns.StygianAbyss) { @@ -7291,7 +7282,8 @@ namespace Server foreach (var state in eable) { - if (!state.Mobile.CanSee(this)) + var m = state.Mobile; + if (!m.CanSee(this)) { if (removeEntity[0] == 0) { @@ -7302,7 +7294,7 @@ namespace Server } else { - state.Send(new MobileIncoming(state, state.Mobile, this)); + state.SendMobileIncoming(m, this); if (IsDeadBondedPet) { @@ -7574,7 +7566,7 @@ namespace Server if (ns != null && (isTeleport && (!ns.HighSeas || !NoMoveHS) || !inOldRange) && m.CanSee(this)) { - ns.Send(new MobileIncoming(m.m_NetState, m, this)); + ns.SendMobileIncoming(m, this); if (ns.StygianAbyss) { @@ -7595,7 +7587,7 @@ namespace Server continue; } - ourState.Send(new MobileIncoming(ourState, this, m)); + ourState.SendMobileIncoming(this, m); if (ourState.StygianAbyss) { @@ -7621,10 +7613,11 @@ namespace Server // We're not attached to a client, so simply send an Incoming foreach (var ns in eable) { - if ((isTeleport && (!ns.HighSeas || !NoMoveHS) || - !Utility.InUpdateRange(oldLocation, ns.Mobile.Location)) && ns.Mobile.CanSee(this)) + var m = ns.Mobile; + if ((isTeleport && (!ns.HighSeas || !NoMoveHS) || !Utility.InUpdateRange(oldLocation, m.Location)) && + m.CanSee(this)) { - ns.Send(new MobileIncoming(ns, ns.Mobile, this)); + ns.SendMobileIncoming(m, this); if (ns.StygianAbyss) { @@ -7700,9 +7693,10 @@ namespace Server foreach (var state in eable) { - if (state.Mobile.CanSee(this)) + var m = state.Mobile; + if (m.CanSee(this)) { - state.Send(new MobileIncoming(state, state.Mobile, this)); + state.SendMobileIncoming(m, this); if (state.StygianAbyss) { @@ -8628,9 +8622,7 @@ namespace Server } // TODO: Pets - if ( /*m_Player &&*/ - !Region.AllowHarmful(this, target) - ) // (target.m_Player || target.Body.IsHuman) && !Region.AllowHarmful( this, target ) ) + if (!Region.AllowHarmful(this, target)) { if (message) { diff --git a/Projects/Server/Network/Packets/IncomingAccountPackets.cs b/Projects/Server/Network/Packets/IncomingAccountPackets.cs index c62df0adc..71eaf48ef 100644 --- a/Projects/Server/Network/Packets/IncomingAccountPackets.cs +++ b/Projects/Server/Network/Packets/IncomingAccountPackets.cs @@ -323,7 +323,7 @@ namespace Server.Network state.SendMobileUpdate(m); - state.Send(new MobileIncoming(state, m, m)); + state.SendMobileIncoming(m, m); state.SendMobileStatus(m); state.SendSetWarMode(m.Warmode); @@ -335,7 +335,7 @@ namespace Server.Network state.SendMobileStatus(m); state.SendSetWarMode(m.Warmode); - state.Send(new MobileIncoming(state, m, m)); + state.SendMobileIncoming(m, m); state.SendLoginComplete(); state.Send(new CurrentTime()); diff --git a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs index 1c51c924e..52f1c3b42 100644 --- a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs @@ -474,7 +474,7 @@ namespace Server.Network } state.SendMobileUpdate(from); - state.Send(new MobileIncoming(state, from, from)); + state.SendMobileIncoming(from, from); from.SendEverything(); diff --git a/Projects/Server/Network/Packets/MobilePackets.cs b/Projects/Server/Network/Packets/MobilePackets.cs deleted file mode 100644 index 2b6ba6869..000000000 --- a/Projects/Server/Network/Packets/MobilePackets.cs +++ /dev/null @@ -1,167 +0,0 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: MobilePackets.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 . * - *************************************************************************/ - -using System.Threading; - -namespace Server.Network -{ - public sealed class MobileIncoming : Packet - { - private static readonly ThreadLocal m_DupedLayersTL = new(() => new int[256]); - private static readonly ThreadLocal m_VersionTL = new(); - - public MobileIncoming(NetState ns, Mobile beholder, Mobile beheld) : base(0x78) - { - var sa = ns.StygianAbyss; - var newPacket = ns.NewMobileIncoming; - var itemIdMask = newPacket ? 0xFFFF : 0x7FFF; - - var m_Version = ++m_VersionTL.Value; - var m_DupedLayers = m_DupedLayersTL.Value; - - var eq = beheld.Items; - var count = eq.Count; - - if (beheld.HairItemID > 0) - { - count++; - } - - if (beheld.FacialHairItemID > 0) - { - count++; - } - - EnsureCapacity(23 + count * 9); - - var hue = beheld.Hue; - - if (beheld.SolidHueOverride >= 0) - { - hue = beheld.SolidHueOverride; - } - - Stream.Write(beheld.Serial); - Stream.Write((short)beheld.Body); - Stream.Write((short)beheld.X); - Stream.Write((short)beheld.Y); - Stream.Write((sbyte)beheld.Z); - Stream.Write((byte)beheld.Direction); - Stream.Write((short)hue); - Stream.Write((byte)beheld.GetPacketFlags(sa)); - Stream.Write((byte)Notoriety.Compute(beholder, beheld)); - - for (var i = 0; i < eq.Count; ++i) - { - var item = eq[i]; - - var layer = (byte)item.Layer; - - if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) - { - m_DupedLayers[layer] = m_Version; - - hue = item.Hue; - - if (beheld.SolidHueOverride >= 0) - { - hue = beheld.SolidHueOverride; - } - - var itemID = item.ItemID & itemIdMask; - var writeHue = newPacket || hue != 0; - - if (!newPacket) - { - itemID |= 0x8000; - } - - Stream.Write(item.Serial); - Stream.Write((ushort)itemID); - Stream.Write(layer); - - if (writeHue) - { - Stream.Write((short)hue); - } - } - } - - if (beheld.HairItemID > 0) - { - if (m_DupedLayers[(int)Layer.Hair] != m_Version) - { - m_DupedLayers[(int)Layer.Hair] = m_Version; - hue = beheld.HairHue; - - if (beheld.SolidHueOverride >= 0) - { - hue = beheld.SolidHueOverride; - } - - var itemID = beheld.HairItemID & itemIdMask; - var writeHue = newPacket || hue != 0; - - if (!newPacket) - { - itemID |= 0x8000; - } - - Stream.Write(HairInfo.FakeSerial(beheld)); - Stream.Write((ushort)itemID); - Stream.Write((byte)Layer.Hair); - - if (writeHue) - { - Stream.Write((short)hue); - } - } - } - - if (beheld.FacialHairItemID > 0) - { - if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) - { - m_DupedLayers[(int)Layer.FacialHair] = m_Version; - hue = beheld.FacialHairHue; - - if (beheld.SolidHueOverride >= 0) - { - hue = beheld.SolidHueOverride; - } - - var itemID = beheld.FacialHairItemID & itemIdMask; - var writeHue = newPacket || hue != 0; - - if (!newPacket) - { - itemID |= 0x8000; - } - - Stream.Write(FacialHairInfo.FakeSerial(beheld)); - Stream.Write((ushort)itemID); - Stream.Write((byte)Layer.FacialHair); - - if (writeHue) - { - Stream.Write((short)hue); - } - } - } - - Stream.Write(0); // terminate - } - } -} diff --git a/Projects/Server/Network/Packets/OutgoingMobilePackets.cs b/Projects/Server/Network/Packets/OutgoingMobilePackets.cs index 9f3d72287..773406355 100644 --- a/Projects/Server/Network/Packets/OutgoingMobilePackets.cs +++ b/Projects/Server/Network/Packets/OutgoingMobilePackets.cs @@ -536,5 +536,121 @@ namespace Server.Network ns.Send(ref buffer, writer.Position); } + + public static void SendMobileIncoming(this NetState ns, Mobile beholder, Mobile beheld) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + Span layers = stackalloc bool[256]; +#if NO_LOCAL_INIT + layers.Clear(); +#endif + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x78); // Packet ID + writer.Seek(2, SeekOrigin.Current); + + var sa = ns.StygianAbyss; + var newPacket = ns.NewMobileIncoming; + var itemIdMask = newPacket ? 0xFFFF : 0x7FFF; + + var hue = beheld.SolidHueOverride >= 0 ? beheld.SolidHueOverride : beheld.Hue; + + writer.Write(beheld.Serial); + writer.Write((short)beheld.Body); + writer.Write((short)beheld.X); + writer.Write((short)beheld.Y); + writer.Write((sbyte)beheld.Z); + writer.Write((byte)beheld.Direction); + writer.Write((short)hue); + writer.Write((byte)beheld.GetPacketFlags(sa)); + writer.Write((byte)Notoriety.Compute(beholder, beheld)); + + var eq = beheld.Items; + for (var i = 0; i < eq.Count; ++i) + { + var item = eq[i]; + var layer = (byte)item.Layer; + + if (item.Deleted || !beholder.CanSee(item) || layers[layer]) + { + continue; + } + + layers[layer] = true; + hue = beheld.SolidHueOverride >= 0 ? beheld.SolidHueOverride : item.Hue; + + var itemID = item.ItemID & itemIdMask; + var writeHue = newPacket || hue != 0; + + if (!newPacket) + { + itemID |= 0x8000; + } + + writer.Write(item.Serial); + writer.Write((ushort)itemID); + writer.Write(layer); + + if (writeHue) + { + writer.Write((short)hue); + } + } + + if (beheld.HairItemID > 0 && !layers[(int)Layer.Hair]) + { + layers[(int)Layer.Hair] = true; + hue = beheld.SolidHueOverride >= 0 ? beheld.SolidHueOverride : beheld.HairHue; + + var itemID = beheld.HairItemID & itemIdMask; + var writeHue = newPacket || hue != 0; + + if (!newPacket) + { + itemID |= 0x8000; + } + + writer.Write(HairInfo.FakeSerial(beheld)); + writer.Write((ushort)itemID); + writer.Write((byte)Layer.Hair); + + if (writeHue) + { + writer.Write((short)hue); + } + } + + if (beheld.FacialHairItemID > 0 && !layers[(int)Layer.FacialHair]) + { + layers[(int)Layer.FacialHair] = true; + hue = beheld.SolidHueOverride >= 0 ? beheld.SolidHueOverride : beheld.FacialHairHue; + + var itemID = beheld.FacialHairItemID & itemIdMask; + var writeHue = newPacket || hue != 0; + + if (!newPacket) + { + itemID |= 0x8000; + } + + writer.Write(FacialHairInfo.FakeSerial(beheld)); + writer.Write((ushort)itemID); + writer.Write((byte)Layer.FacialHair); + + if (writeHue) + { + writer.Write((short)hue); + } + } + + writer.Write(0); // terminate + + writer.WritePacketLength(); + ns.Send(ref buffer, writer.Position); + } } } diff --git a/Projects/UOContent/Commands/VisibilityList.cs b/Projects/UOContent/Commands/VisibilityList.cs index c980e8fda..cc080cc6f 100644 --- a/Projects/UOContent/Commands/VisibilityList.cs +++ b/Projects/UOContent/Commands/VisibilityList.cs @@ -123,7 +123,7 @@ namespace Server.Commands { if (targ.CanSee(pm)) { - ns.Send(new MobileIncoming(ns, targ, pm)); + ns.SendMobileIncoming(targ, pm); pm.SendOPLPacketTo(ns);