From 7531b58ae2f97d3dd923e4c66df97bf0ef505ae4 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Thu, 7 Jan 2021 00:03:12 -0800 Subject: [PATCH] fix(network): Adds protocol extensions (#392) - [X] Adds protocol extensions for CUO --- .../UOContent/Network/ProtocolExtensions.cs | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 Projects/UOContent/Network/ProtocolExtensions.cs diff --git a/Projects/UOContent/Network/ProtocolExtensions.cs b/Projects/UOContent/Network/ProtocolExtensions.cs new file mode 100644 index 000000000..ccfecb70a --- /dev/null +++ b/Projects/UOContent/Network/ProtocolExtensions.cs @@ -0,0 +1,179 @@ +using System; +using System.Buffers; +using System.IO; +using Server.Engines.PartySystem; +using Server.Guilds; + +namespace Server.Network +{ + public static class ProtocolExtensions + { + private static readonly PacketHandler[] _handlers = new PacketHandler[0x100]; + + public static void Configure() + { + IncomingPackets.Register( 0xF0, 0, false, DecodeBundledPacket); + Register(0x00, true, QueryPartyMemberLocations); + Register(0x01, true, QueryGuildMemberLocations); + } + + public static void Register(int packetID, bool ingame, OnPacketReceive onReceive) + { + _handlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive); + } + + public static PacketHandler GetHandler(int packetID) => + packetID >= 0 && packetID < _handlers.Length ? _handlers[packetID] : null; + + public static void DecodeBundledPacket(NetState state, CircularBufferReader reader) + { + int packetID = reader.ReadByte(); + + PacketHandler ph = GetHandler(packetID); + + if (ph == null) + { + return; + } + + if (ph.Ingame && state.Mobile == null) + { + state.WriteConsole("Sent in-game packet (0xBFx{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 static void QueryGuildMemberLocations(NetState ns, CircularBufferReader reader) + { + Mobile from = ns.Mobile; + + ns.SendGuildMemberLocations(from, from.Guild as Guild, reader.ReadBoolean()); + } + + public static void QueryPartyMemberLocations(NetState ns, CircularBufferReader reader) + { + Mobile from = ns.Mobile; + var party = Party.Get(from); + + if (party != null) + { + ns.SendPartyMemberLocations(from, party); + } + } + + public static void SendGuildMemberLocations(this NetState ns, Mobile from, Guild guild, bool sendLocations) + { + if (ns == null) + { + return; + } + + var count = guild?.Members.Count ?? 0; + var maxLength = 9 + (count > 1 ? (count - 1) * (sendLocations ? 10 : 4) : 0); + var writer = new SpanWriter(stackalloc byte[maxLength]); + writer.Write((byte)0xF0); // Packet ID + writer.Seek(2, SeekOrigin.Current); + writer.Write((byte)0x02); // Command + writer.Write(count > 0 && sendLocations); + + bool sendPacket = false; + for (var i = 0; i < count; i++) + { + var m = guild!.Members[i]; + + if (m?.NetState == null || m == from) + { + continue; + } + + if (sendLocations && Utility.InUpdateRange(from, m) && from.CanSee(m)) + { + continue; + } + + sendPacket = true; + writer.Write(m.Serial); + + if (sendLocations) + { + writer.Write((short)m.X); + writer.Write((short)m.Y); + writer.Write((byte)(m.Map?.MapID ?? 0)); + + if (m.Alive) + { + writer.Write((byte)(m.Hits * 100 / Math.Max(m.HitsMax, 1))); + } + else + { + writer.Write((byte)0); + } + } + } + + if (!sendPacket) + { + return; + } + + writer.Write(0); + writer.WritePacketLength(); + ns.Send(writer.Span); + } + + public static void SendPartyMemberLocations(this NetState ns, Mobile from, Party party) + { + if (ns == null) + { + return; + } + + var count = party?.Members.Count ?? 0; + var maxLength = 9 + (count > 1 ? (count - 1) * 9 : 0); + var writer = new SpanWriter(stackalloc byte[maxLength]); + writer.Write((byte)0xF0); // Packet ID + writer.Seek(2, SeekOrigin.Current); + writer.Write((byte)0x01); // Command + + bool sendPacket = false; + for (var i = 0; i < count; i++) + { + var pmi = party!.Members[i]; + Mobile mob = pmi?.Mobile; + + if (mob?.NetState == null || mob == from) + { + continue; + } + + if (Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + { + continue; + } + + sendPacket = true; + writer.Write(mob.Serial); + writer.Write((short)mob.X); + writer.Write((short)mob.Y); + writer.Write((byte)(mob.Map?.MapID ?? 0)); + } + + if (!sendPacket) + { + return; + } + + writer.Write(0); + writer.WritePacketLength(); + ns.Send(writer.Span); + } + } +}