Пример #1
0
        public static void WritePacketLength(this CircularBufferWriter writer)
        {
            var length = writer.Position;

            writer.Seek(1, SeekOrigin.Begin);
            writer.Write((ushort)length);
            writer.Seek(length, SeekOrigin.Begin);
        }
Пример #2
0
        public static void SendContainerContent(this NetState ns, Mobile beholder, Item beheld)
        {
            if (ns == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var items = beheld.Items;
            var count = items.Count;

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x3C);           // Packet ID
            writer.Seek(4, SeekOrigin.Current); // Length & writter count

            var written = 0;

            for (var i = 0; i < count; ++i)
            {
                var child = items[i];

                if (!child.Deleted && beholder.CanSee(child))
                {
                    var loc = child.Location;

                    writer.Write(child.Serial);
                    writer.Write((ushort)child.ItemID);
                    writer.Write((byte)0); // signed, itemID offset
                    writer.Write((ushort)Math.Min(child.Amount, ushort.MaxValue));
                    writer.Write((short)loc.X);
                    writer.Write((short)loc.Y);
                    if (ns.ContainerGridLines)
                    {
                        writer.Write((byte)0); // Grid Location?
                    }
                    writer.Write(beheld.Serial);
                    writer.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue));

                    ++written;
                }
            }

            var length = writer.Position;

            writer.Seek(1, SeekOrigin.Begin);
            writer.Write((ushort)length);
            writer.Write((ushort)written);

            ns.Send(ref buffer, length);
        }
Пример #3
0
        /**
         * Packet: 0xA8
         * Length: up to 240 bytes
         *
         * Sends login acknowledge with server listing
         */
        public static void SendAccountLoginAck(this NetState ns)
        {
            if (ns == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0xA8);           // Packet ID
            writer.Seek(2, SeekOrigin.Current); // Length

            writer.Write((byte)0x5D);

            var info = ns.ServerInfo;

            writer.Write((ushort)info.Length);

            for (var i = 0; i < info.Length; ++i)
            {
                var si = info[i];

                writer.Write((ushort)i);
                writer.WriteAscii(si.Name, 32);
                writer.Write((byte)si.FullPercent);
                writer.Write((sbyte)si.TimeZone);
                writer.Write(Utility.GetAddressValue(si.Address.Address));
            }

            writer.WritePacketLength();
            ns.Send(ref buffer, writer.Position);
        }
        public static void SendVendorBuyList(this NetState ns, Mobile vendor, List <BuyItemState> list)
        {
            if (ns == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x74); // Packet ID
            writer.Seek(2, SeekOrigin.Current);
            writer.Write((vendor.FindItemOnLayer(Layer.ShopBuy) as Container)?.Serial ?? Serial.MinusOne);
            writer.Write((byte)list.Count);

            for (var i = 0; i < list.Count; ++i)
            {
                var bis = list[i];

                writer.Write(bis.Price);

                var desc = bis.Description ?? "";

                writer.Write((byte)desc.Length);
                writer.WriteAscii(desc); // Doesn't look like it is used anymore
            }

            writer.WritePacketLength();

            ns.Send(ref buffer, writer.Position);
        }
        public static void SendVendorBuyContent(this NetState ns, List <BuyItemState> list)
        {
            if (ns == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x3C); // Packet ID
            writer.Seek(2, SeekOrigin.Current);

            writer.Write((short)list.Count);

            for (var i = list.Count - 1; i >= 0; --i)
            {
                var bis = list[i];

                writer.Write(bis.MySerial);
                writer.Write((ushort)bis.ItemID);
                writer.Write((byte)0);        // itemID offset
                writer.Write((ushort)bis.Amount);
                writer.Write((short)(i + 1)); // x
                writer.Write((short)1);       // y
                if (ns.ContainerGridLines)
                {
                    writer.Write((byte)0); // Grid Location?
                }
                writer.Write(bis.ContainerSerial);
                writer.Write((ushort)bis.Hue);
            }

            writer.WritePacketLength();
            ns.Send(ref buffer, writer.Position);
        }
Пример #6
0
        public static void SendDisplayItemListMenu(this NetState ns, ItemListMenu menu)
        {
            if (ns == null || menu == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x7C);           // Packet ID
            writer.Seek(2, SeekOrigin.Current); // Length
            writer.Write(menu.Serial);
            writer.Write((ushort)0);

            var question = menu.Question?.Trim();

            if (question == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                var questionLength = question.Length;
                writer.Write((byte)questionLength);
                writer.WriteAscii(question);
            }

            var entries = menu.Entries;

            int entriesLength = (byte)entries.Length;

            writer.Write((byte)entriesLength);

            for (var i = 0; i < entriesLength; ++i)
            {
                var e = entries[i];

                writer.Write((ushort)e.ItemID);
                writer.Write((short)e.Hue);

                var name = e.Name?.Trim();

                if (name == null)
                {
                    writer.Write((byte)0);
                }
                else
                {
                    var nameLength = name.Length;
                    writer.Write((byte)nameLength);
                    writer.WriteAscii(name);
                }
            }

            writer.WritePacketLength();

            ns.Send(ref buffer, writer.Position);
        }
Пример #7
0
        public static void SendOldSpellbookContent(this NetState ns, Serial book, int offset, ulong content)
        {
            if (ns == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x3C);           // Packet ID
            writer.Seek(4, SeekOrigin.Current); // Length & written count

            var written = 0;

            ulong mask = 1;

            for (var i = 0; i < 64; ++i, mask <<= 1)
            {
                if ((content & mask) != 0)
                {
                    writer.Write(0x7FFFFFFF - i);
                    writer.Write((ushort)0);            // child ItemID
                    writer.Write((byte)0);              // ItemID offset
                    writer.Write((ushort)(i + offset)); // Amount
                    writer.Write(0);                    // X, Y
                    if (ns.ContainerGridLines)
                    {
                        writer.Write((byte)0); // Grid Location
                    }
                    writer.Write(book);
                    writer.Write((short)0); // Quest Hue

                    ++written;
                }
            }

            var length = writer.Position;

            writer.Seek(1, SeekOrigin.Begin);
            writer.Write((ushort)length);
            writer.Write((ushort)written);

            ns.Send(ref buffer, length);
        }
Пример #8
0
        public static void SendDisplayQuestionMenu(this NetState ns, QuestionMenu menu)
        {
            if (ns == null || menu == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x7C);           // Packet ID
            writer.Seek(2, SeekOrigin.Current); // Length
            writer.Write(menu.Serial);
            writer.Write((ushort)0);

            var question = menu.Question?.Trim();

            if (question == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                var questionLength = question.Length;
                writer.Write((byte)questionLength);
                writer.WriteAscii(question);
            }

            var answers = menu.Answers;

            int answersLength = (byte)answers.Length;

            writer.Write((byte)answersLength);

            for (var i = 0; i < answersLength; ++i)
            {
                writer.Write(0);

                var answer = answers[i]?.Trim();

                if (answer == null)
                {
                    writer.Write((byte)0);
                }
                else
                {
                    var nameLength = answer.Length;
                    writer.Write((byte)nameLength);
                    writer.WriteAscii(answer);
                }
            }

            writer.WritePacketLength();

            ns.Send(ref buffer, writer.Position);
        }
Пример #9
0
        /**
         * Packet: 0x81
         * Length: Up to 425 bytes
         *
         * Displays the list of characters during the login process.
         * Note: Currently Unused
         */
        public static void SendChangeCharacter(this NetState ns, IAccount a)
        {
            if (ns == null || a == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var length = 5 + a.Length * 60;
            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x81); // Packet ID
            writer.Write((ushort)length);
            writer.Write((ushort)0);  // Count & Placeholder

            int count = 0;

            for (var i = 0; i < a.Length; ++i)
            {
                var m = a[i];

                if (m == null)
                {
                    writer.Clear(60);
                }
                else
                {
                    var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");

                    count++;
                    writer.WriteAscii(name, 30);
                    writer.Clear(30); // Password (empty)
                }
            }

            var position = writer.Position;

            writer.Seek(3, SeekOrigin.Begin);
            writer.Write((byte)count);
            writer.Seek(position, SeekOrigin.Begin);

            ns.Send(ref buffer, writer.Position);
        }
Пример #10
0
        /**
         * Packet: 0x86
         * Length: Up to 424 bytes
         *
         * Sends updated character list
         */
        public static void SendCharacterListUpdate(this NetState ns, IAccount a)
        {
            if (ns == null || a == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0x86);           // Packet ID
            writer.Seek(2, SeekOrigin.Current); // Length

            var highSlot = -1;

            for (var i = a.Length - 1; i >= 0; i--)
            {
                if (a[i] != null)
                {
                    highSlot = i;
                    break;
                }
            }

            var count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);

            writer.Write((byte)count);

            for (int i = 0; i < count; i++)
            {
                var m = a[i];

                if (m == null)
                {
                    writer.Clear(60);
                }
                else
                {
                    var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
                    writer.WriteAscii(name, 30);
                    writer.Clear(30); // password
                }
            }

            writer.WritePacketLength();
            ns.Send(ref buffer, writer.Position);
        }
        // First only, beginning

        // Second only

        // Split

        // First only, beginning, fixed length smaller

        // Second only, fixed length smaller

        // Split, fixed length smaller

        // First only, beginning, fixed length bigger

        // Second only, fixed length bigger

        // Split, fixed length bigger
        public void TestWriteString(
            string value,
            string encodingStr,
            int fixedLength,
            int firstSize,
            int secondSize,
            int offset
            )
        {
            Span <byte> buffer = stackalloc byte[firstSize + secondSize];

            buffer.Clear();

            var encoding  = EncodingHelpers.GetEncoding(encodingStr);
            var strLength = fixedLength > -1 ? Math.Min(value.Length, fixedLength) : value.Length;
            var chars     = value.AsSpan(0, strLength);

            var writer = new CircularBufferWriter(buffer.Slice(0, firstSize), buffer.Slice(firstSize));

            writer.Seek(offset, SeekOrigin.Begin);
            writer.WriteString(chars, encoding);

            if (offset > 0)
            {
                Span <byte> testEmpty = stackalloc byte[offset];
                testEmpty.Clear();
                AssertThat.Equal(buffer.Slice(0, offset), testEmpty);
            }

            Span <byte> expectedStr = stackalloc byte[encoding.GetByteCount(chars)];

            encoding.GetBytes(chars, expectedStr.Slice(0));

            AssertThat.Equal(buffer.Slice(offset, expectedStr.Length), expectedStr);
            offset += expectedStr.Length;

            if (offset < buffer.Length)
            {
                Span <byte> testEmpty = stackalloc byte[buffer.Length - offset];
                testEmpty.Clear();
                AssertThat.Equal(buffer.Slice(offset), testEmpty);
            }
        }
Пример #12
0
        /**
         * Packet: 0xA9
         * Length: 1410 or more bytes
         *
         * Sends list of characters and starting cities.
         */
        public static void SendCharacterList(this NetState ns)
        {
            var acct = ns?.Account;

            if (acct == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var client70130 = ns.NewCharacterList;
            var textLength  = client70130 ? 32 : 31;

            var cityInfo = ns.CityInfo;

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0xA9);           // Packet ID
            writer.Seek(2, SeekOrigin.Current); // Length

            var highSlot = -1;

            for (var i = acct.Length - 1; i >= 0; i--)
            {
                if (acct[i] != null)
                {
                    highSlot = i;
                    break;
                }
            }

            var count = Math.Max(Math.Max(highSlot + 1, acct.Limit), 5);

            writer.Write((byte)count);

            for (int i = 0; i < count; i++)
            {
                var m = acct[i];

                if (m == null)
                {
                    writer.Clear(60);
                }
                else
                {
                    var name = (m.RawName?.Trim()).DefaultIfNullOrEmpty("-no name-");
                    writer.WriteAscii(name, 30);
                    writer.Clear(30); // password
                }
            }

            writer.Write((byte)cityInfo.Length);

            for (int i = 0; i < cityInfo.Length; ++i)
            {
                var ci = cityInfo[i];

                writer.Write((byte)i);
                writer.WriteAscii(ci.City, textLength);
                writer.WriteAscii(ci.Building, textLength);
                if (client70130)
                {
                    writer.Write(ci.X);
                    writer.Write(ci.Y);
                    writer.Write(ci.Z);
                    writer.Write(ci.Map?.MapID ?? 0);
                    writer.Write(ci.Description);
                    writer.Write(0);
                }
            }

            var flags = ExpansionInfo.CoreExpansion.CharacterListFlags;

            if (count > 6)
            {
                flags |= CharacterListFlags.SeventhCharacterSlot |
                         CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required?
            }
            else if (count == 6)
            {
                flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
            }
            else if (acct.Limit == 1)
            {
                flags |= CharacterListFlags.SlotLimit &
                         CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
            }

            writer.Write((int)flags);
            if (client70130)
            {
                writer.Write((short)-1);
            }

            writer.WritePacketLength();
            ns.Send(ref buffer, writer.Position);
        }
Пример #13
0
        public static void SendDisplayContextMenu(this NetState ns, ContextMenu menu)
        {
            if (ns == null || menu == null || !ns.GetSendBuffer(out var buffer))
            {
                return;
            }

            var newCommand = ns.NewHaven && menu.RequiresNewPacket;

            var entries       = menu.Entries;
            var entriesLength = (byte)entries.Length;

            var writer = new CircularBufferWriter(buffer);

            writer.Write((byte)0xBF);                        // Packet ID
            writer.Seek(2, SeekOrigin.Current);              // Length
            writer.Write((short)0x14);                       // Subpacket
            writer.Write((short)(newCommand ? 0x02 : 0x01)); // Command

            var target = menu.Target;

            writer.Write(target.Serial);
            writer.Write(entriesLength);

            var p = target switch
            {
                Mobile _ => target.Location,
                Item item => item.GetWorldLocation(),
                _ => Point3D.Zero
            };

            for (var i = 0; i < entriesLength; ++i)
            {
                var e = entries[i];

                var range = e.Range;

                if (range == -1)
                {
                    range = Core.GlobalUpdateRange;
                }

                var flags = e.Flags;
                if (!(e.Enabled && menu.From.InRange(p, range)))
                {
                    flags |= CMEFlags.Disabled;
                }

                if (newCommand)
                {
                    writer.Write(e.Number);
                    writer.Write((short)i);
                    writer.Write((short)flags);
                }
                else
                {
                    writer.Write((short)i);
                    writer.Write((ushort)(e.Number - 3000000));

                    var color = e.Color & 0xFFFF;

                    if (color != 0xFFFF)
                    {
                        flags |= CMEFlags.Colored;
                    }

                    writer.Write((short)flags);

                    if ((flags & CMEFlags.Colored) != 0)
                    {
                        writer.Write((short)color);
                    }
                }
            }

            writer.WritePacketLength();

            ns.Send(ref buffer, writer.Position);
        }
    }