diff --git a/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/PacketTests.cs b/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/PacketTests.cs new file mode 100644 index 000000000..c1cfb5fde --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/PacketTests.cs @@ -0,0 +1,57 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Tests; +using Server.Tests.Network; +using Xunit; + +namespace UOContent.Tests +{ + public class PacketTests : IClassFixture + { + [Fact] + public void TestCorpseEquipPacket() + { + var m = new Mobile(0x1); + m.DefaultMobileInit(); + + var weapon = new VikingSword(); + m.EquipItem(weapon); + + var c = new Corpse(m, m.Items); + + var expected = new CorpseEquip(m, c).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendCorpseEquip(m, c); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + + [Theory] + [InlineData(ProtocolChanges.None)] + [InlineData(ProtocolChanges.ContainerGridLines)] + public void TestCorpseContainerPacket(ProtocolChanges changes) + { + var m = new Mobile(0x1); + m.DefaultMobileInit(); + + var weapon = new VikingSword(); + m.EquipItem(weapon); + + var c = new Corpse(m, m.Items); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.ProtocolChanges = changes; + + var expected = (ns.ContainerGridLines ? (Packet)new CorpseContent6017(m, c) : new CorpseContent(m, c)).Compile(); + + ns.SendCorpseContent(m, c); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + } +} diff --git a/Projects/UOContent/Items/Misc/Corpses/Packets.cs b/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/Packets.cs similarity index 99% rename from Projects/UOContent/Items/Misc/Corpses/Packets.cs rename to Projects/UOContent.Tests/Tests/Items/Misc/Corpses/Packets.cs index 35def09c6..f0d46653f 100644 --- a/Projects/UOContent/Items/Misc/Corpses/Packets.cs +++ b/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/Packets.cs @@ -1,4 +1,5 @@ using System.IO; +using Server; using Server.Items; namespace Server.Network diff --git a/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPackets.cs b/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPackets.cs index 231307b24..88d0a9762 100644 --- a/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPackets.cs +++ b/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPackets.cs @@ -1,18 +1,3 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: ArrowPackets.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 . * - *************************************************************************/ - namespace Server.Network { public sealed class CancelArrow : Packet diff --git a/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs index 530af34ba..859de2579 100644 --- a/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs +++ b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPacketTests.cs @@ -1,5 +1,6 @@ using System; using Server; +using Server.Network; using Server.Tests; using Server.Tests.Network; using Xunit; diff --git a/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs index 72f050458..0723bb9c8 100644 --- a/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs +++ b/Projects/UOContent.Tests/Tests/Network/Packets/BuffIconPackets.cs @@ -1,7 +1,6 @@ using System; -using Server.Network; -namespace Server +namespace Server.Network { public sealed class AddBuffPacket : Packet { diff --git a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs index 669a07280..e4c91c05f 100644 --- a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs +++ b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs @@ -800,28 +800,14 @@ namespace Server.Items return m_Devourer.Devour(this); // Devour the corpse if it hasn't } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SendCorpseContent(NetState ns) - { - if (ns.ContainerGridLines) - { - ns.Send(new CorpseContent6017(ns.Mobile, this)); - } - else - { - ns.Send(new CorpseContent(ns.Mobile, this)); - } - - ns.Send(new CorpseEquip(ns.Mobile, this)); - } - - public override void SendInfoTo(NetState ns, ReadOnlySpan world, Span opl) + public override void SendInfoTo(NetState ns, ReadOnlySpan world = default, Span opl = default) { base.SendInfoTo(ns, world, opl); if (((Body)Amount).IsHuman && ItemID == 0x2006) { - SendCorpseContent(ns); + ns.SendCorpseContent(ns.Mobile, this); + ns.SendCorpseEquip(ns.Mobile, this); } } diff --git a/Projects/UOContent/Items/Misc/Corpses/CorpsePackets.cs b/Projects/UOContent/Items/Misc/Corpses/CorpsePackets.cs new file mode 100644 index 000000000..25a1f3d4d --- /dev/null +++ b/Projects/UOContent/Items/Misc/Corpses/CorpsePackets.cs @@ -0,0 +1,147 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: CorpsePackets.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.Buffers; +using System.IO; +using Server.Items; + +namespace Server.Network +{ + public static class CorpsePackets + { + public static void SendCorpseEquip(this NetState ns, Mobile beholder, Corpse beheld) + { + if (ns == null) + { + return; + } + + var list = beheld.EquipItems; + + var maxLength = 8 + (list.Count + 2) * 5; + var writer = new SpanWriter(stackalloc byte[maxLength]); + writer.Write((byte)0x89); + writer.Seek(2, SeekOrigin.Current); + writer.Write(beheld.Serial); + + for (var i = 0; i < list.Count; ++i) + { + var item = list[i]; + + if (!item.Deleted && beholder.CanSee(item) && item.Parent == beheld) + { + writer.Write((byte)(item.Layer + 1)); + writer.Write(item.Serial); + } + } + + if (beheld.Hair?.ItemID > 0) + { + writer.Write((byte)(Layer.Hair + 1)); + writer.Write(HairInfo.FakeSerial(beheld.Owner.Serial) - 2); + } + + if (beheld.FacialHair?.ItemID > 0) + { + writer.Write((byte)(Layer.FacialHair + 1)); + writer.Write(FacialHairInfo.FakeSerial(beheld.Owner.Serial) - 2); + } + + writer.Write((byte)Layer.Invalid); + + writer.WritePacketLength(); + ns.Send(writer.Span); + } + + public static void SendCorpseContent(this NetState ns, Mobile beholder, Corpse beheld) + { + if (ns == null) + { + return; + } + + var list = beheld.EquipItems; + + var maxLength = 5 + (list.Count + 2) * (ns.ContainerGridLines ? 19 : 20); + var writer = new SpanWriter(stackalloc byte[maxLength]); + writer.Write((byte)0x3C); + writer.Seek(4, SeekOrigin.Current); // Length and Count + + var written = 0; + for (var i = 0; i < list.Count; ++i) + { + var child = list[i]; + + if (!child.Deleted && child.Parent == beheld && beholder.CanSee(child)) + { + writer.Write(child.Serial); + writer.Write((ushort)child.ItemID); + writer.Write((byte)0); // signed, itemID offset + writer.Write((ushort)child.Amount); + writer.Write((short)child.X); + writer.Write((short)child.Y); + if (ns.ContainerGridLines) + { + writer.Write((byte)0); // Grid Location? + } + writer.Write(beheld.Serial); + writer.Write((ushort)child.Hue); + + ++written; + } + } + + if (beheld.Hair?.ItemID > 0) + { + writer.Write(HairInfo.FakeSerial(beheld.Owner.Serial) - 2); + writer.Write((ushort)beheld.Hair.ItemID); + writer.Write((byte)0); // signed, itemID offset + writer.Write((ushort)1); + writer.Write(0); // X/Y + if (ns.ContainerGridLines) + { + writer.Write((byte)0); // Grid Location? + } + writer.Write(beheld.Serial); + writer.Write((ushort)beheld.Hair.Hue); + + ++written; + } + + if (beheld.FacialHair?.ItemID > 0) + { + writer.Write(FacialHairInfo.FakeSerial(beheld.Owner.Serial) - 2); + writer.Write((ushort)beheld.FacialHair.ItemID); + writer.Write((byte)0); // signed, itemID offset + writer.Write((ushort)1); + writer.Write(0); // X/Y + if (ns.ContainerGridLines) + { + writer.Write((byte)0); // Grid Location? + } + writer.Write(beheld.Serial); + writer.Write((ushort)beheld.FacialHair.Hue); + + ++written; + } + + writer.Seek(1, SeekOrigin.Begin); + writer.Write((ushort)writer.BytesWritten); + writer.Write((ushort)written); + writer.Seek(0, SeekOrigin.End); + ns.Send(writer.Span); + } + } +} diff --git a/Projects/UOContent/Misc/MapUO.cs b/Projects/UOContent/Misc/MapUO.cs deleted file mode 100644 index b163343a3..000000000 --- a/Projects/UOContent/Misc/MapUO.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using Server.Engines.PartySystem; -using Server.Guilds; -using Server.Network; - -namespace Server.Misc -{ - public static class MapUO - { - public static void Initialize() - { - if (Settings.PartyTrack) - { - ProtocolExtensions.Register(0x00, true, OnPartyTrack); - } - - if (Settings.GuildTrack) - { - ProtocolExtensions.Register(0x01, true, OnGuildTrack); - } - } - - private static void OnPartyTrack(NetState state, CircularBufferReader reader) - { - var from = state.Mobile; - var party = Party.Get(from); - - if (party != null) - { - var packet = new Packets.PartyTrack(from, party); - - if (packet.Stream.Length > 8) - { - state.Send(packet); - } - } - } - - private static void OnGuildTrack(NetState state, CircularBufferReader reader) - { - var from = state.Mobile; - - if (from.Guild is Guild guild) - { - var locations = reader.ReadByte() != 0; - - var packet = new Packets.GuildTrack(from, guild, locations); - - if (packet.Stream.Length > (locations ? 9 : 5)) - { - state.Send(packet); - } - } - else - { - state.Send(new Packets.GuildTrack()); - } - } - - private static class Settings - { - public const bool PartyTrack = true; - public const bool GuildTrack = true; - public const bool GuildHitsPercent = true; - } - - private static class Packets - { - public sealed class PartyTrack : ProtocolExtension - { - public PartyTrack(Mobile from, Party party) : base(0x01, (party.Members.Count - 1) * 9 + 4) - { - for (var i = 0; i < party.Members.Count; ++i) - { - var pmi = party.Members[i]; - - if (pmi == null || pmi.Mobile == from) - { - continue; - } - - var mob = pmi.Mobile; - - if (Utility.InUpdateRange(from, mob) && from.CanSee(mob)) - { - continue; - } - - Stream.Write(mob.Serial); - Stream.Write((short)mob.X); - Stream.Write((short)mob.Y); - Stream.Write((byte)(mob.Map?.MapID ?? 0)); - } - - Stream.Write(0); - } - } - - public sealed class GuildTrack : ProtocolExtension - { - public GuildTrack() : base(0x02, 5) - { - Stream.Write((byte)0); - Stream.Write(0); - } - - public GuildTrack(Mobile from, Guild guild, bool locations) : base( - 0x02, - (guild.Members.Count - 1) * (locations ? 10 : 4) + 5 - ) - { - Stream.Write((byte)(locations ? 1 : 0)); - - for (var i = 0; i < guild.Members.Count; ++i) - { - var mob = guild.Members[i]; - - if (mob == null || mob == from || mob.NetState == null) - { - continue; - } - - if (locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob)) - { - continue; - } - - Stream.Write(mob.Serial); - - if (locations) - { - Stream.Write((short)mob.X); - Stream.Write((short)mob.Y); - Stream.Write((byte)(mob.Map?.MapID ?? 0)); - - if (Settings.GuildHitsPercent && mob.Alive) - { - Stream.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100)); - } - else - { - Stream.Write((byte)0); - } - } - } - - Stream.Write(0); - } - } - } - } -} diff --git a/Projects/UOContent/Misc/ProtocolExtensions.cs b/Projects/UOContent/Misc/ProtocolExtensions.cs deleted file mode 100644 index c1d50741f..000000000 --- a/Projects/UOContent/Misc/ProtocolExtensions.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Server.Network; - -namespace Server.Misc -{ - public static class ProtocolExtensions - { - private static readonly PacketHandler[] m_Handlers = new PacketHandler[0x100]; - - public static void Initialize() - { - // IncomingPackets.Register(0xF0, 0, false, DecodeBundledPacket); - } - - public static void Register(int packetID, bool ingame, OnPacketReceive onReceive) - { - m_Handlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive); - } - - public static PacketHandler GetHandler(int packetID) => - packetID >= 0 && packetID < m_Handlers.Length ? m_Handlers[packetID] : null; - - public static void DecodeBundledPacket(NetState state, CircularBufferReader reader) - { - int packetID = reader.ReadByte(); - - var ph = GetHandler(packetID); - - if (ph != null) - { - if (ph.Ingame && state.Mobile == null) - { - state.WriteConsole( - "Sent ingame packet (0xF0x{0:X2}) before having been attached to a mobile", - packetID - ); - state.Dispose(); - } - else if (ph.Ingame && state.Mobile.Deleted) - { - state.Dispose(); - } - else - { - ph.OnReceive(state, reader); - } - } - } - } - - public abstract class ProtocolExtension : Packet - { - public ProtocolExtension(int packetID, int capacity) : base(0xF0) - { - EnsureCapacity(4 + capacity); - - Stream.Write((byte)packetID); - } - } -}