diff --git a/Projects/Server.Tests/Server.Tests.csproj b/Projects/Server.Tests/Server.Tests.csproj index 2e682976e..c8ab6bcd9 100644 --- a/Projects/Server.Tests/Server.Tests.csproj +++ b/Projects/Server.Tests/Server.Tests.csproj @@ -9,5 +9,6 @@ + diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPacketTests.cs index 8183fe941..fa1ac8d3c 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPacketTests.cs @@ -8,26 +8,19 @@ using Xunit; namespace Server.Tests.Network { - public class GumpPacketTests + public class GumpPacketTests : IClassFixture { - [Fact] - public void TestCloseGump() + [Theory] + [InlineData(100, 10)] + public void TestCloseGump(int typeId, int buttonId) { - var typeId = 100; - var buttonId = 10; + var expected = new CloseGump(typeId, buttonId).Compile(); - var data = new CloseGump(typeId, buttonId).Compile(); + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendCloseGump(typeId, buttonId); - Span expectedData = stackalloc byte[13]; - var pos = 0; - - expectedData.Write(ref pos, (byte)0xBF); // Packet ID - expectedData.Write(ref pos, (ushort)0xD); // Length - expectedData.Write(ref pos, (ushort)0x4); // Close Gump - expectedData.Write(ref pos, typeId); - expectedData.Write(ref pos, buttonId); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } [Fact] @@ -38,212 +31,97 @@ namespace Server.Tests.Network var unknownString = "This is an unknown string"; var caption = "This is a caption"; - var data = new DisplaySignGump(gumpSerial, gumpId, unknownString, caption).Compile(); + var expected = new DisplaySignGump(gumpSerial, gumpId, unknownString, caption).Compile(); - Span expectedData = stackalloc byte[15 + unknownString.Length + caption.Length]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendDisplaySignGump(gumpSerial, gumpId, unknownString, caption); - expectedData.Write(ref pos, (byte)0x8B); - expectedData.Write(ref pos, (ushort)expectedData.Length); - expectedData.Write(ref pos, gumpSerial); - expectedData.Write(ref pos, (ushort)gumpId); - expectedData.Write(ref pos, (ushort)(unknownString.Length + 1)); - expectedData.WriteAsciiNull(ref pos, unknownString); - expectedData.Write(ref pos, (ushort)(caption.Length + 1)); - expectedData.WriteAsciiNull(ref pos, caption); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestFastGumpPacket() + [Theory] + [InlineData(ProtocolChanges.None)] + [InlineData(ProtocolChanges.Unpack)] + public void TestGumpPacketNameChange(ProtocolChanges changes) { - var ns = new NetState(null); + var gump = new NameChangeDeedGump(); - var gump = new ResurrectGump(2); + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.ProtocolChanges = changes; - var data = gump.Compile(ns).Compile(); + var expected = gump.Compile(ns).Compile(); - Span expectedData = stackalloc byte[0x1000]; + ns.SendDisplayGump(gump, out _, out _); - var pos = 0; - - expectedData[pos++] = 0xB0; // Packet ID - pos += 2; // Length - - expectedData.Write(ref pos, gump.Serial); - expectedData.Write(ref pos, gump.TypeID); - expectedData.Write(ref pos, gump.X); - expectedData.Write(ref pos, gump.Y); - pos += 2; // Layout Length - - var layoutLength = 0; - - if (!gump.Draggable) - { - expectedData.Write(ref pos, GumpUtilities.NoMoveBuffer); - layoutLength += GumpUtilities.NoMove.Length; - } - - if (!gump.Closable) - { - expectedData.Write(ref pos, GumpUtilities.NoCloseBuffer); - layoutLength += GumpUtilities.NoClose.Length; - } - - if (!gump.Disposable) - { - expectedData.Write(ref pos, GumpUtilities.NoDisposeBuffer); - layoutLength += GumpUtilities.NoDispose.Length; - } - - if (!gump.Resizable) - { - expectedData.Write(ref pos, GumpUtilities.NoResizeBuffer); - layoutLength += GumpUtilities.NoResize.Length; - } - - foreach (var entry in gump.Entries) - { - var str = entry.Compile(ns); - expectedData.WriteAscii(ref pos, str); - layoutLength += str.Length; // ASCII so 1:1 - } - - expectedData.Slice(19, 2).Write((ushort)layoutLength); - expectedData.Write(ref pos, (ushort)gump.Strings.Count); - - for (var i = 0; i < gump.Strings.Count; ++i) - { - expectedData.WriteBigUni(ref pos, gump.Strings[i] ?? ""); - } - - 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); } - [Fact] - public void TestPackedGumpPacket() + [Theory] + [InlineData(ProtocolChanges.None)] + [InlineData(ProtocolChanges.Unpack)] + public void TestGumpPacketAdmin(ProtocolChanges changes) { - var ns = new NetState(null) - { - ProtocolChanges = ProtocolChanges.Unpack - }; + var m = new Mobile(0x1); + m.DefaultMobileInit(); + m.RawName = "Test Mobile"; + m.AccessLevel = AccessLevel.Administrator; - var gump = new ResurrectGump(2); + var gump = new AdminGump(m, AdminGumpPage.Clients); - var data = gump.Compile(ns).Compile(); + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.ProtocolChanges = changes; - Span expectedData = stackalloc byte[0x1000]; + var expected = gump.Compile(ns).Compile(); - var pos = 0; + ns.SendDisplayGump(gump, out _, out _); - expectedData[pos++] = 0xDD; // Packet ID - pos += 2; // Length - - expectedData.Write(ref pos, gump.Serial); - expectedData.Write(ref pos, gump.TypeID); - expectedData.Write(ref pos, gump.X); - expectedData.Write(ref pos, gump.Y); - - var layoutList = new List(); - var bufferLength = 1; // Null terminated - - if (!gump.Draggable) - { - layoutList.Add(GumpUtilities.NoMove); - bufferLength += GumpUtilities.NoMove.Length; - } - - if (!gump.Closable) - { - layoutList.Add(GumpUtilities.NoClose); - bufferLength += GumpUtilities.NoClose.Length; - } - - if (!gump.Disposable) - { - layoutList.Add(GumpUtilities.NoDispose); - bufferLength += GumpUtilities.NoDispose.Length; - } - - if (!gump.Resizable) - { - layoutList.Add(GumpUtilities.NoResize); - bufferLength += GumpUtilities.NoResize.Length; - } - - foreach (var entry in gump.Entries) - { - var str = entry.Compile(ns); - bufferLength += str.Length; - layoutList.Add(str); - } - - var rawBuffer = ArrayPool.Shared.Rent(bufferLength); - Span buffer = rawBuffer; - var bufferPos = 0; - - foreach (var layout in layoutList) - { - buffer.WriteAscii(ref bufferPos, layout); - } - -#if NO_LOCAL_INIT - buffer.Write(ref bufferPos, (byte)0); // Layout terminator -#else - bufferPos++; -#endif - - expectedData.WritePacked(ref pos, buffer.Slice(0, bufferPos)); - ArrayPool.Shared.Return(rawBuffer); - - expectedData.Write(ref pos, gump.Strings.Count); - bufferLength = gump.Strings.Sum(str => 2 + str.Length * 2); - rawBuffer = ArrayPool.Shared.Rent(bufferLength); - buffer = rawBuffer; - bufferPos = 0; - - foreach (var str in gump.Strings) - { - buffer.WriteBigUni(ref bufferPos, str); - } - - expectedData.WritePacked(ref pos, buffer.Slice(0, bufferPos)); - ArrayPool.Shared.Return(rawBuffer); - - // Length - expectedData.Slice(1, 2).Write((ushort)pos); - expectedData = expectedData.Slice(0, pos); - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } } - public class ResurrectGump : Gump + public class NameChangeDeedGump : Gump { - public ResurrectGump(int msg) : base(100, 0) + public NameChangeDeedGump() : base(50, 50) { + Closable = false; + Draggable = false; + Resizable = false; + AddPage(0); - AddBackground(0, 0, 400, 350, 2600); + AddBlackAlpha(10, 120, 250, 85); + AddHtml(10, 125, 250, 20, Color(Center("Name Change Deed"), 0xFFFFFF)); - AddHtmlLocalized(0, 20, 400, 35, 1011022); //
Resurrection
+ AddLabel(73, 15, 1152, ""); + AddLabel(20, 150, 0x480, "New Name:"); + AddTextField(100, 150, 150, 20, 0); - /* It is possible for you to be resurrected here by this healer. Do you wish to try?
- * CONTINUE - You chose to try to come back to life now.
- * CANCEL - You prefer to remain a ghost for now. - */ - AddHtmlLocalized(50, 55, 300, 140, 1011023 + msg, true, true); + AddButtonLabeled(75, 180, 1, "Submit"); + } - AddButton(200, 227, 4005, 4007, 0); - AddHtmlLocalized(235, 230, 110, 35, 1011012); // CANCEL + public void AddBlackAlpha(int x, int y, int width, int height) + { + AddImageTiled(x, y, width, height, 2624); + AddAlphaRegion(x, y, width, height); + } - AddButton(65, 227, 4005, 4007, 1); - AddHtmlLocalized(100, 230, 110, 35, 1011011); // CONTINUE + public void AddTextField(int x, int y, int width, int height, int index) + { + AddBackground(x - 2, y - 2, width + 4, height + 4, 0x2486); + AddTextEntry(x + 2, y + 2, width - 4, height - 4, 0, index, ""); + } + + public static string Center(string text) => $"
{text}
"; + + public static string Color(string text, int color) => $"{text}"; + + public void AddButtonLabeled(int x, int y, int buttonID, string text) + { + AddButton(x, y - 1, 4005, 4007, buttonID); + AddHtml(x + 35, y, 240, 20, Color(text, 0xFFFFFF)); } } } diff --git a/Projects/Server/Network/Packets/GumpPackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPackets.cs similarity index 82% rename from Projects/Server/Network/Packets/GumpPackets.cs rename to Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPackets.cs index a4741f43f..be305fa48 100644 --- a/Projects/Server/Network/Packets/GumpPackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/GumpPackets.cs @@ -1,39 +1,13 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: GumpPackets.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.Collections.Generic; using System.IO; using System.IO.Compression; using System.Text; using Server.Gumps; +using Server.Network; -namespace Server.Network +namespace Server.Tests { - public sealed class CloseGump : Packet - { - public CloseGump(int typeID, int buttonID) : base(0xBF) - { - EnsureCapacity(13); - - Stream.Write((short)0x04); - Stream.Write(typeID); - Stream.Write(buttonID); - } - } - public interface IGumpWriter { int TextEntries { get; set; } @@ -50,6 +24,18 @@ namespace Server.Network void Flush(); } + public sealed class CloseGump : Packet + { + public CloseGump(int typeID, int buttonID) : base(0xBF) + { + EnsureCapacity(13); + + Stream.Write((short)0x04); + Stream.Write(typeID); + Stream.Write(buttonID); + } + } + public sealed class DisplayGumpPacked : Packet, IGumpWriter { private static readonly byte[] m_True = Gump.StringToBuffer(" 1"); @@ -154,6 +140,7 @@ namespace Server.Network // Note: layout MUST be null terminated (don't listen to krrios) m_Layout.Write((byte)0); + WritePacked(m_Layout); Stream.Write(m_StringCount); @@ -175,7 +162,7 @@ namespace Server.Network return; } - var wantLength = 1 + buffer.Length * 1024 / 1000; + var wantLength = 1 + length * 1024 / 1000; wantLength += 4095; wantLength &= ~4095; @@ -303,35 +290,6 @@ namespace Server.Network } } - public sealed class DisplayGump : Packet - { - public DisplayGump(Gump g, string layout, string[] text) : base(0xB0) - { - layout ??= ""; - - EnsureCapacity(256); - - Stream.Write(g.Serial); - Stream.Write(g.TypeID); - Stream.Write(g.X); - Stream.Write(g.Y); - Stream.Write((ushort)(layout.Length + 1)); - Stream.WriteAsciiNull(layout); - - Stream.Write((ushort)text.Length); - - for (var i = 0; i < text.Length; ++i) - { - var v = text[i] ?? ""; - - var length = (ushort)v.Length; - - Stream.Write(length); - Stream.WriteBigUniFixed(v, length); - } - } - } - public sealed class DisplaySignGump : Packet { public DisplaySignGump(Serial serial, int gumpID, string unknown, string caption) : base(0x8B) diff --git a/Projects/Server.Tests/Tests/Network/Packets/Utilities/GumpUtilities.cs b/Projects/Server.Tests/Tests/Network/Packets/Utilities/GumpUtilities.cs index ef91ba04e..f6c6b6450 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Utilities/GumpUtilities.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Utilities/GumpUtilities.cs @@ -1,46 +1,469 @@ -using System; -using System.Buffers; -using System.IO.Compression; -using System.Text; +using Server.Gumps; +using Server.Network; namespace Server.Tests.Network { public static class GumpUtilities { - public const string NoMove = "{ nomove }"; - public const string NoClose = "{ noclose }"; - public const string NoDispose = "{ nodispose }"; - public const string NoResize = "{ noresize }"; - public static readonly byte[] NoMoveBuffer = Encoding.ASCII.GetBytes("{ nomove }"); - public static readonly byte[] NoCloseBuffer = Encoding.ASCII.GetBytes("{ noclose }"); - public static readonly byte[] NoDisposeBuffer = Encoding.ASCII.GetBytes("{ nodispose }"); - public static readonly byte[] NoResizeBuffer = Encoding.ASCII.GetBytes("{ noresize }"); + private static readonly byte[] m_BeginLayout = Gump.StringToBuffer("{ "); + private static readonly byte[] m_EndLayout = Gump.StringToBuffer(" }"); - public static void WritePacked(this Span dest, ref int pos, ReadOnlySpan source) + public static Packet Compile(this Gump g, NetState ns = null) { - var length = source.Length; + IGumpWriter disp; - if (length == 0) + if (ns?.Unpack == true) { -#if NO_LOCAL_INIT - dest.Write(ref pos, 0); -#else - pos += 4; -#endif - return; + disp = new DisplayGumpPacked(g); + } + else + { + disp = new DisplayGumpFast(g); } - var packLength = (ulong)dest.Length - 8; - - ZlibError ce = Zlib.Pack(dest.Slice(pos + 8), ref packLength, source, ZlibQuality.Default); - if (ce != ZlibError.Okay) + if (!g.Draggable) { - Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); + disp.AppendLayout(Gump.NoMove); } - dest.Write(ref pos, (int)(4 + packLength)); - dest.Write(ref pos, length); - pos += (int)packLength; + if (!g.Closable) + { + disp.AppendLayout(Gump.NoClose); + } + + if (!g.Disposable) + { + disp.AppendLayout(Gump.NoDispose); + } + + if (!g.Resizable) + { + disp.AppendLayout(Gump.NoResize); + } + + var count = g.Entries.Count; + + for (var i = 0; i < count; ++i) + { + var e = g.Entries[i]; + + disp.AppendLayout(m_BeginLayout); + e.AppendToByType(disp); + disp.AppendLayout(m_EndLayout); + } + + disp.WriteStrings(g.Strings); + + disp.Flush(); + + return (Packet)disp; + } + + public static void AppendToByType(this GumpEntry e, IGumpWriter disp) + { + switch (e) + { + case GumpAlphaRegion g: + { + g.AppendTo(disp); + break; + } + case GumpBackground g: + { + g.AppendTo(disp); + break; + } + case GumpButton g: + { + g.AppendTo(disp); + break; + } + case GumpCheck g: + { + g.AppendTo(disp); + break; + } + case GumpGroup g: + { + g.AppendTo(disp); + break; + } + case GumpECHandleInput g: + { + g.AppendTo(disp); + break; + } + case GumpHtml g: + { + g.AppendTo(disp); + break; + } + case GumpHtmlLocalized g: + { + g.AppendTo(disp); + break; + } + case GumpImage g: + { + g.AppendTo(disp); + break; + } + case GumpImageTileButton g: + { + g.AppendTo(disp); + break; + } + case GumpImageTiled g: + { + g.AppendTo(disp); + break; + } + case GumpItem g: + { + g.AppendTo(disp); + break; + } + case GumpItemProperty g: + { + g.AppendTo(disp); + break; + } + case GumpLabel g: + { + g.AppendTo(disp); + break; + } + case GumpLabelCropped g: + { + g.AppendTo(disp); + break; + } + case GumpMasterGump g: + { + g.AppendTo(disp); + break; + } + case GumpPage g: + { + g.AppendTo(disp); + break; + } + case GumpRadio g: + { + g.AppendTo(disp); + break; + } + case GumpSpriteImage g: + { + g.AppendTo(disp); + break; + } + case GumpTextEntry g: + { + g.AppendTo(disp); + break; + } + case GumpTextEntryLimited g: + { + g.AppendTo(disp); + break; + } + case GumpTooltip g: + { + g.AppendTo(disp); + break; + } + } + } + + public static void AppendTo(this GumpAlphaRegion g, IGumpWriter disp) + { + disp.AppendLayout(GumpAlphaRegion.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + } + + public static void AppendTo(this GumpBackground g, IGumpWriter disp) + { + disp.AppendLayout(GumpBackground.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.GumpID); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + } + + public static void AppendTo(this GumpButton g, IGumpWriter disp) + { + disp.AppendLayout(GumpButton.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.NormalID); + disp.AppendLayout(g.PressedID); + disp.AppendLayout((int)g.Type); + disp.AppendLayout(g.Param); + disp.AppendLayout(g.ButtonID); + } + + public static void AppendTo(this GumpCheck g, IGumpWriter disp) + { + disp.AppendLayout(GumpButton.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.InactiveID); + disp.AppendLayout(g.ActiveID); + disp.AppendLayout(g.InitialState); + disp.AppendLayout(g.SwitchID); + + disp.Switches++; + } + + public static void AppendTo(this GumpGroup g, IGumpWriter disp) + { + disp.AppendLayout(GumpGroup.LayoutName); + disp.AppendLayout(g.Group); + } + + public static void AppendTo(this GumpECHandleInput g, IGumpWriter disp) + { + disp.AppendLayout(GumpECHandleInput.LayoutName); + } + + public static void AppendTo(this GumpHtml g, IGumpWriter disp) + { + disp.AppendLayout(GumpHtml.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Parent.Intern(g.Text)); + disp.AppendLayout(g.Background); + disp.AppendLayout(g.Scrollbar); + } + + public static void AppendTo(this GumpHtmlLocalized g, IGumpWriter disp) + { + switch (g.Type) + { + case GumpHtmlLocalizedType.Plain: + { + disp.AppendLayout(GumpHtmlLocalized.LayoutNamePlain); + + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Number); + disp.AppendLayout(g.Background); + disp.AppendLayout(g.Scrollbar); + + break; + } + + case GumpHtmlLocalizedType.Color: + { + disp.AppendLayout(GumpHtmlLocalized.LayoutNameColor); + + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Number); + disp.AppendLayout(g.Background); + disp.AppendLayout(g.Scrollbar); + disp.AppendLayout(g.Color); + + break; + } + + case GumpHtmlLocalizedType.Args: + { + disp.AppendLayout(GumpHtmlLocalized.LayoutNameArgs); + + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Background); + disp.AppendLayout(g.Scrollbar); + disp.AppendLayout(g.Color); + disp.AppendLayout(g.Number); + disp.AppendLayout(g.Args); + + break; + } + } + } + + public static void AppendTo(this GumpImage g, IGumpWriter disp) + { + disp.AppendLayout(GumpImage.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.GumpID); + + if (g.Hue != 0) + { + disp.AppendLayout(GumpImage.HueEquals); + disp.AppendLayoutNS(g.Hue); + } + + if (!string.IsNullOrEmpty(g.Class)) + { + disp.AppendLayout(GumpImage.ClassEquals); + disp.AppendLayoutNS(g.Class); + } + } + + public static void AppendTo(this GumpImageTileButton g, IGumpWriter disp) + { + disp.AppendLayout(GumpImageTileButton.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.NormalID); + disp.AppendLayout(g.PressedID); + disp.AppendLayout((int)g.Type); + disp.AppendLayout(g.Param); + disp.AppendLayout(g.ButtonID); + + disp.AppendLayout(g.ItemID); + disp.AppendLayout(g.Hue); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + + if (g.LocalizedTooltip > 0) + { + disp.AppendLayout(GumpImageTileButton.LayoutTooltip); + disp.AppendLayout(g.LocalizedTooltip); + } + } + + public static void AppendTo(this GumpImageTiled g, IGumpWriter disp) + { + disp.AppendLayout(GumpImageTiled.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.GumpID); + } + + public static void AppendTo(this GumpItem g, IGumpWriter disp) + { + disp.AppendLayout(g.Hue == 0 ? GumpItem.LayoutName : GumpItem.LayoutNameHue); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.ItemID); + + if (g.Hue != 0) + { + disp.AppendLayout(g.Hue); + } + } + + public static void AppendTo(this GumpItemProperty g, IGumpWriter disp) + { + disp.AppendLayout(GumpItemProperty.LayoutName); + disp.AppendLayout(g.Serial); + } + + public static void AppendTo(this GumpLabel g, IGumpWriter disp) + { + disp.AppendLayout(GumpLabel.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Hue); + disp.AppendLayout(g.Parent.Intern(g.Text)); + } + + public static void AppendTo(this GumpLabelCropped g, IGumpWriter disp) + { + disp.AppendLayout(GumpLabelCropped.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Hue); + disp.AppendLayout(g.Parent.Intern(g.Text)); + } + + public static void AppendTo(this GumpMasterGump g, IGumpWriter disp) + { + disp.AppendLayout(GumpMasterGump.LayoutName); + disp.AppendLayout(g.GumpID); + } + + public static void AppendTo(this GumpPage g, IGumpWriter disp) + { + disp.AppendLayout(GumpPage.LayoutName); + disp.AppendLayout(g.Page); + } + + public static void AppendTo(this GumpRadio g, IGumpWriter disp) + { + disp.AppendLayout(GumpRadio.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.InactiveID); + disp.AppendLayout(g.ActiveID); + disp.AppendLayout(g.InitialState); + disp.AppendLayout(g.SwitchID); + + disp.Switches++; + } + + public static void AppendTo(this GumpSpriteImage g, IGumpWriter disp) + { + disp.AppendLayout(GumpSpriteImage.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.GumpID); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.SX); + disp.AppendLayout(g.SY); + } + + public static void AppendTo(this GumpTextEntry g, IGumpWriter disp) + { + disp.AppendLayout(GumpTextEntry.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Hue); + disp.AppendLayout(g.EntryID); + disp.AppendLayout(g.Parent.Intern(g.InitialText)); + + disp.TextEntries++; + } + + public static void AppendTo(this GumpTextEntryLimited g, IGumpWriter disp) + { + disp.AppendLayout(GumpTextEntryLimited.LayoutName); + disp.AppendLayout(g.X); + disp.AppendLayout(g.Y); + disp.AppendLayout(g.Width); + disp.AppendLayout(g.Height); + disp.AppendLayout(g.Hue); + disp.AppendLayout(g.EntryID); + disp.AppendLayout(g.Parent.Intern(g.InitialText)); + disp.AppendLayout(g.Size); + + disp.TextEntries++; + } + + public static void AppendTo(this GumpTooltip g, IGumpWriter disp) + { + disp.AppendLayout(GumpTooltip.LayoutName); + disp.AppendLayout(g.Number); + + if (!string.IsNullOrEmpty(g.Args)) + { + disp.AppendLayout(g.Args); + } } } } diff --git a/Projects/Server/Buffers/CircularBufferWriter.cs b/Projects/Server/Buffers/CircularBufferWriter.cs index 5ad814a52..0ec0c6889 100644 --- a/Projects/Server/Buffers/CircularBufferWriter.cs +++ b/Projects/Server/Buffers/CircularBufferWriter.cs @@ -362,9 +362,11 @@ namespace System.Buffers if (Position < _first.Length) { var sz = Math.Min(buffer.Length, _first.Length - Position); - buffer.CopyTo(_first.Slice(Position)); - buffer.Slice(sz).CopyTo(_second); - Position += buffer.Length; + buffer.Slice(0, sz).CopyTo(_first.Slice(Position)); + if (sz < buffer.Length) + { + buffer.Slice(sz).CopyTo(_second); + } } else if (Position < Length) { @@ -374,6 +376,8 @@ namespace System.Buffers { throw new OutOfMemoryException(); } + + Position += buffer.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Projects/Server/Buffers/SpanWriter.cs b/Projects/Server/Buffers/SpanWriter.cs index b932d3843..0cf840dd2 100644 --- a/Projects/Server/Buffers/SpanWriter.cs +++ b/Projects/Server/Buffers/SpanWriter.cs @@ -224,6 +224,10 @@ namespace System.Buffers var src = value.AsSpan(0, charLength); var byteCount = fixedLength > -1 ? fixedLength * sizeT : encoding.GetByteCount(value); + if (byteCount == 0) + { + return; + } GrowIfNeeded(byteCount); diff --git a/Projects/Server/Gumps/Gump.cs b/Projects/Server/Gumps/Gump.cs index 331883318..0ac9698fc 100644 --- a/Projects/Server/Gumps/Gump.cs +++ b/Projects/Server/Gumps/Gump.cs @@ -9,13 +9,10 @@ namespace Server.Gumps { private static uint m_NextSerial = 1; - private static readonly byte[] m_BeginLayout = StringToBuffer("{ "); - private static readonly byte[] m_EndLayout = StringToBuffer(" }"); - - private static readonly byte[] m_NoMove = StringToBuffer("{ nomove }"); - private static readonly byte[] m_NoClose = StringToBuffer("{ noclose }"); - private static readonly byte[] m_NoDispose = StringToBuffer("{ nodispose }"); - private static readonly byte[] m_NoResize = StringToBuffer("{ noresize }"); + public static readonly byte[] NoMove = StringToBuffer("{ nomove }"); + public static readonly byte[] NoClose = StringToBuffer("{ noclose }"); + public static readonly byte[] NoDispose = StringToBuffer("{ nodispose }"); + public static readonly byte[] NoResize = StringToBuffer("{ noresize }"); internal int m_TextEntries, m_Switches; @@ -41,7 +38,7 @@ namespace Server.Gumps public List Entries { get; } - public uint Serial { get; set; } + public Serial Serial { get; set; } public int X { get; set; } @@ -248,65 +245,11 @@ namespace Server.Gumps public void SendTo(NetState state) { state.AddGump(this); - state.Send(Compile(state)); + state.SendDisplayGump(this, out m_Switches, out m_TextEntries); } public static byte[] StringToBuffer(string str) => Encoding.ASCII.GetBytes(str); - public Packet Compile(NetState ns = null) - { - IGumpWriter disp; - - if (ns?.Unpack == true) - { - disp = new DisplayGumpPacked(this); - } - else - { - disp = new DisplayGumpFast(this); - } - - if (!Draggable) - { - disp.AppendLayout(m_NoMove); - } - - if (!Closable) - { - disp.AppendLayout(m_NoClose); - } - - if (!Disposable) - { - disp.AppendLayout(m_NoDispose); - } - - if (!Resizable) - { - disp.AppendLayout(m_NoResize); - } - - var count = Entries.Count; - - for (var i = 0; i < count; ++i) - { - var e = Entries[i]; - - disp.AppendLayout(m_BeginLayout); - e.AppendTo(ns, disp); - disp.AppendLayout(m_EndLayout); - } - - disp.WriteStrings(Strings); - - disp.Flush(); - - m_TextEntries = disp.TextEntries; - m_Switches = disp.Switches; - - return (Packet)disp; - } - public virtual void OnResponse(NetState sender, RelayInfo info) { } diff --git a/Projects/Server/Gumps/GumpAlphaRegion.cs b/Projects/Server/Gumps/GumpAlphaRegion.cs index 7b917d492..557b45e40 100644 --- a/Projects/Server/Gumps/GumpAlphaRegion.cs +++ b/Projects/Server/Gumps/GumpAlphaRegion.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpAlphaRegion : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("checkertrans"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("checkertrans"); public GumpAlphaRegion(int x, int y, int width, int height) { @@ -24,23 +24,13 @@ namespace Server.Gumps public int Height { get; set; } - public override string Compile(NetState ns) => $"{{ checkertrans {X} {Y} {Width} {Height} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ checkertrans {X} {Y} {Width} {Height} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpBackground.cs b/Projects/Server/Gumps/GumpBackground.cs index b793cddab..35c857a8f 100644 --- a/Projects/Server/Gumps/GumpBackground.cs +++ b/Projects/Server/Gumps/GumpBackground.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpBackground : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("resizepic"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("resizepic"); public GumpBackground(int x, int y, int width, int height, int gumpID) { @@ -27,24 +27,13 @@ namespace Server.Gumps public int GumpID { get; set; } - public override string Compile(NetState ns) => $"{{ resizepic {X} {Y} {GumpID} {Width} {Height} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ resizepic {X} {Y} {GumpID} {Width} {Height} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(GumpID); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpButton.cs b/Projects/Server/Gumps/GumpButton.cs index 4068589c7..0cbbd00ac 100644 --- a/Projects/Server/Gumps/GumpButton.cs +++ b/Projects/Server/Gumps/GumpButton.cs @@ -12,7 +12,7 @@ namespace Server.Gumps public class GumpButton : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("button"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("button"); public GumpButton( int x, int y, int normalID, int pressedID, int buttonID, @@ -42,28 +42,14 @@ namespace Server.Gumps public int Param { get; set; } - public override string Compile(NetState ns) => - $"{{ button {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ button {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(NormalID); - disp.AppendLayout(PressedID); - disp.AppendLayout((int)Type); - disp.AppendLayout(Param); - disp.AppendLayout(ButtonID); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpCheck.cs b/Projects/Server/Gumps/GumpCheck.cs index 0d4105c8f..9f490dd1c 100644 --- a/Projects/Server/Gumps/GumpCheck.cs +++ b/Projects/Server/Gumps/GumpCheck.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpCheck : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("checkbox"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("checkbox"); public GumpCheck(int x, int y, int inactiveID, int activeID, bool initialState, int switchID) { @@ -30,29 +30,14 @@ namespace Server.Gumps public int SwitchID { get; set; } - public override string Compile(NetState ns) => - $"{{ checkbox {X} {Y} {InactiveID} {ActiveID} {(InitialState ? 1 : 0)} {SwitchID} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ checkbox {X} {Y} {InactiveID} {ActiveID} {(InitialState ? 1 : 0)} {SwitchID} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(InactiveID); - disp.AppendLayout(ActiveID); - disp.AppendLayout(InitialState); - disp.AppendLayout(SwitchID); - - disp.Switches++; - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpECHandleInput.cs b/Projects/Server/Gumps/GumpECHandleInput.cs index 7981beb52..f8122e41c 100644 --- a/Projects/Server/Gumps/GumpECHandleInput.cs +++ b/Projects/Server/Gumps/GumpECHandleInput.cs @@ -21,15 +21,9 @@ namespace Server.Gumps { public class GumpECHandleInput : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("echandleinput"); - public override string Compile(NetState ns) => "{ echandleinput }"; + public static readonly byte[] LayoutName = Gump.StringToBuffer("echandleinput"); public override string Compile(OrderedHashSet strings) => "{ echandleinput }"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.WriteAscii("{ echandleinput }"); diff --git a/Projects/Server/Gumps/GumpEntry.cs b/Projects/Server/Gumps/GumpEntry.cs index e2d8701ed..fe669f390 100644 --- a/Projects/Server/Gumps/GumpEntry.cs +++ b/Projects/Server/Gumps/GumpEntry.cs @@ -1,6 +1,5 @@ using System.Buffers; using Server.Collections; -using Server.Network; namespace Server.Gumps { @@ -24,9 +23,7 @@ namespace Server.Gumps } } - public abstract string Compile(NetState ns); public abstract string Compile(OrderedHashSet strings); - public abstract void AppendTo(NetState ns, IGumpWriter disp); // TODO: Replace OrderedHashSet with InsertOnlyHashSet, a copy of HashSet that is ReadOnly compatible, but includes // a public AddIfNotPresent function that returns the index of the element diff --git a/Projects/Server/Gumps/GumpGroup.cs b/Projects/Server/Gumps/GumpGroup.cs index 85f0dffcc..cb7c6da4a 100644 --- a/Projects/Server/Gumps/GumpGroup.cs +++ b/Projects/Server/Gumps/GumpGroup.cs @@ -6,25 +6,18 @@ namespace Server.Gumps { public class GumpGroup : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("group"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("group"); public GumpGroup(int group) => Group = group; public int Group { get; set; } - - public override string Compile(NetState ns) => $"{{ group {Group} }}"; public override string Compile(OrderedHashSet strings) => $"{{ group {Group} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(Group); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(Group.ToString()); writer.Write((ushort)0x207D); // " }" } diff --git a/Projects/Server/Gumps/GumpHtml.cs b/Projects/Server/Gumps/GumpHtml.cs index d17074c84..e065c23d1 100644 --- a/Projects/Server/Gumps/GumpHtml.cs +++ b/Projects/Server/Gumps/GumpHtml.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpHtml : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("htmlgump"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("htmlgump"); public GumpHtml(int x, int y, int width, int height, string text, bool background, bool scrollbar) { @@ -33,28 +33,14 @@ namespace Server.Gumps public bool Scrollbar { get; set; } - public override string Compile(NetState ns) => - $"{{ htmlgump {X} {Y} {Width} {Height} {Parent.Intern(Text)} {(Background ? 1 : 0)} {(Scrollbar ? 1 : 0)} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ htmlgump {X} {Y} {Width} {Height} {strings.GetOrAdd(Text)} {(Background ? 1 : 0)} {(Scrollbar ? 1 : 0)} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Parent.Intern(Text)); - disp.AppendLayout(Background); - disp.AppendLayout(Scrollbar); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpHtmlLocalized.cs b/Projects/Server/Gumps/GumpHtmlLocalized.cs index cc79281ea..902bd0186 100644 --- a/Projects/Server/Gumps/GumpHtmlLocalized.cs +++ b/Projects/Server/Gumps/GumpHtmlLocalized.cs @@ -13,9 +13,9 @@ namespace Server.Gumps public class GumpHtmlLocalized : GumpEntry { - private static readonly byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump"); - private static readonly byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor"); - private static readonly byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok"); + public static readonly byte[] LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump"); + public static readonly byte[] LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor"); + public static readonly byte[] LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok"); public GumpHtmlLocalized( int x, int y, int width, int height, int number, @@ -90,17 +90,6 @@ namespace Server.Gumps public GumpHtmlLocalizedType Type { get; set; } - public override string Compile(NetState ns) => - Type switch - { - GumpHtmlLocalizedType.Plain => - $"{{ xmfhtmlgump {X} {Y} {Width} {Height} {Number} {(Background ? 1 : 0)} {(Scrollbar ? 1 : 0)} }}", - GumpHtmlLocalizedType.Color => - $"{{ xmfhtmlgumpcolor {X} {Y} {Width} {Height} {Number} {(Background ? 1 : 0)} {(Scrollbar ? 1 : 0)} {Color} }}", - _ => - $"{{ xmfhtmltok {X} {Y} {Width} {Height} {(Background ? 1 : 0)} {(Scrollbar ? 1 : 0)} {Color} {Number} @{Args}@ }}" - }; - public override string Compile(OrderedHashSet strings) => Type switch { @@ -112,60 +101,6 @@ namespace Server.Gumps $"{{ xmfhtmltok {X} {Y} {Width} {Height} {(Background ? 1 : 0)} {(Scrollbar ? 1 : 0)} {Color} {Number} @{Args}@ }}" }; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - switch (Type) - { - case GumpHtmlLocalizedType.Plain: - { - disp.AppendLayout(m_LayoutNamePlain); - - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Number); - disp.AppendLayout(Background); - disp.AppendLayout(Scrollbar); - - break; - } - - case GumpHtmlLocalizedType.Color: - { - disp.AppendLayout(m_LayoutNameColor); - - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Number); - disp.AppendLayout(Background); - disp.AppendLayout(Scrollbar); - disp.AppendLayout(Color); - - break; - } - - case GumpHtmlLocalizedType.Args: - { - disp.AppendLayout(m_LayoutNameArgs); - - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Background); - disp.AppendLayout(Scrollbar); - disp.AppendLayout(Color); - disp.AppendLayout(Number); - disp.AppendLayout(Args); - - break; - } - } - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " @@ -174,7 +109,8 @@ namespace Server.Gumps { case GumpHtmlLocalizedType.Plain: { - writer.Write(m_LayoutNamePlain); + writer.Write(LayoutNamePlain); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); @@ -193,7 +129,8 @@ namespace Server.Gumps } case GumpHtmlLocalizedType.Color: { - writer.Write(m_LayoutNameColor); + writer.Write(LayoutNameColor); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); @@ -214,7 +151,8 @@ namespace Server.Gumps } case GumpHtmlLocalizedType.Args: { - writer.Write(m_LayoutNameArgs); + writer.Write(LayoutNameArgs); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpImage.cs b/Projects/Server/Gumps/GumpImage.cs index 63dd29253..dd9b804a1 100644 --- a/Projects/Server/Gumps/GumpImage.cs +++ b/Projects/Server/Gumps/GumpImage.cs @@ -6,9 +6,9 @@ namespace Server.Gumps { public class GumpImage : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("gumppic"); - private static readonly byte[] m_HueEquals = Gump.StringToBuffer(" hue="); - private static readonly byte[] m_ClassEquals = Gump.StringToBuffer(" class="); + public static readonly byte[] LayoutName = Gump.StringToBuffer("gumppic"); + public static readonly byte[] HueEquals = Gump.StringToBuffer(" hue="); + public static readonly byte[] ClassEquals = Gump.StringToBuffer(" class="); public GumpImage(int x, int y, int gumpID, int hue = 0, string cls = null) { @@ -29,58 +29,33 @@ namespace Server.Gumps public string Class { get; set; } - public override string Compile(NetState ns) => - $"{{ gumppic {X} {Y} {GumpID}{(Hue == 0 ? "" : $"hue={Hue}")}{(string.IsNullOrEmpty(Class) ? "" : $"class={Class}")} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ gumppic {X} {Y} {GumpID}{(Hue == 0 ? "" : $"hue={Hue}")}{(string.IsNullOrEmpty(Class) ? "" : $"class={Class}")} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(GumpID); - - if (Hue != 0) - { - disp.AppendLayout(m_HueEquals); - disp.AppendLayoutNS(Hue); - } - - if (!string.IsNullOrEmpty(Class)) - { - disp.AppendLayout(m_ClassEquals); - disp.AppendLayoutNS(Class); - } - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(GumpID.ToString()); - writer.Write((byte)0x20); // ' ' if (Hue != 0) { - writer.Write(m_HueEquals); + writer.Write(HueEquals); writer.WriteAscii(Hue.ToString()); - writer.Write((byte)0x20); // ' ' } if (!string.IsNullOrWhiteSpace(Class)) { - writer.Write(m_ClassEquals); + writer.Write(ClassEquals); writer.WriteAscii(Class); - writer.Write((byte)0x20); // ' ' } - writer.Write((byte)0x7D); // '}' + writer.Write((ushort)0x207D); // " }" } } } diff --git a/Projects/Server/Gumps/GumpImageTileButton.cs b/Projects/Server/Gumps/GumpImageTileButton.cs index a2d2deb98..51ed6119d 100644 --- a/Projects/Server/Gumps/GumpImageTileButton.cs +++ b/Projects/Server/Gumps/GumpImageTileButton.cs @@ -6,8 +6,8 @@ namespace Server.Gumps { public class GumpImageTileButton : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("buttontileart"); - private static readonly byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("buttontileart"); + public static readonly byte[] LayoutTooltip = Gump.StringToBuffer(" }{ tooltip"); // Note, on OSI, the tooltip supports ONLY clilocs as far as I can figure out, // and the tooltip ONLY works after the buttonTileArt (as far as I can tell from testing) @@ -57,43 +57,16 @@ namespace Server.Gumps public int LocalizedTooltip { get; set; } - public override string Compile(NetState ns) => - LocalizedTooltip > 0 ? - $"{{ buttontileart {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} {ItemID} {Hue} {Width} {Height} }}{{ tooltip {LocalizedTooltip} }}" : - $"{{ buttontileart {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} {ItemID} {Hue} {Width} {Height} }}"; - public override string Compile(OrderedHashSet strings) => LocalizedTooltip > 0 ? $"{{ buttontileart {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} {ItemID} {Hue} {Width} {Height} }}{{ tooltip {LocalizedTooltip} }}" : $"{{ buttontileart {X} {Y} {NormalID} {PressedID} {(int)Type} {Param} {ButtonID} {ItemID} {Hue} {Width} {Height} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(NormalID); - disp.AppendLayout(PressedID); - disp.AppendLayout((int)Type); - disp.AppendLayout(Param); - disp.AppendLayout(ButtonID); - - disp.AppendLayout(ItemID); - disp.AppendLayout(Hue); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - - if (LocalizedTooltip > 0) - { - disp.AppendLayout(m_LayoutTooltip); - disp.AppendLayout(LocalizedTooltip); - } - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); @@ -115,16 +88,14 @@ namespace Server.Gumps writer.WriteAscii(Width.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Height.ToString()); - writer.Write((byte)0x20); // ' ' if (LocalizedTooltip > 0) { - writer.Write(m_LayoutTooltip); + writer.Write(LayoutTooltip); writer.WriteAscii(LocalizedTooltip.ToString()); - writer.Write((byte)0x20); // ' ' } - writer.Write((byte)0x7D); // " }" + writer.Write((ushort)0x207D); // " }" } } } diff --git a/Projects/Server/Gumps/GumpImageTiled.cs b/Projects/Server/Gumps/GumpImageTiled.cs index ea37a2b95..3e4b7e3e4 100644 --- a/Projects/Server/Gumps/GumpImageTiled.cs +++ b/Projects/Server/Gumps/GumpImageTiled.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpImageTiled : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("gumppictiled"); public GumpImageTiled(int x, int y, int width, int height, int gumpID) { @@ -26,24 +26,13 @@ namespace Server.Gumps public int Height { get; set; } public int GumpID { get; set; } - - public override string Compile(NetState ns) => $"{{ gumppictiled {X} {Y} {Width} {Height} {GumpID} }}"; public override string Compile(OrderedHashSet strings) => $"{{ gumppictiled {X} {Y} {Width} {Height} {GumpID} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(GumpID); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpItem.cs b/Projects/Server/Gumps/GumpItem.cs index 983bd6405..18cd3e59a 100644 --- a/Projects/Server/Gumps/GumpItem.cs +++ b/Projects/Server/Gumps/GumpItem.cs @@ -6,8 +6,8 @@ namespace Server.Gumps { public class GumpItem : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("tilepic"); - private static readonly byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("tilepic"); + public static readonly byte[] LayoutNameHue = Gump.StringToBuffer("tilepichue"); public GumpItem(int x, int y, int itemID, int hue = 0) { @@ -25,28 +25,13 @@ namespace Server.Gumps public int Hue { get; set; } - public override string Compile(NetState ns) => - Hue == 0 ? $"{{ tilepic {X} {Y} {ItemID} }}" : $"{{ tilepichue {X} {Y} {ItemID} {Hue} }}"; - public override string Compile(OrderedHashSet strings) => Hue == 0 ? $"{{ tilepic {X} {Y} {ItemID} }}" : $"{{ tilepichue {X} {Y} {ItemID} {Hue} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(Hue == 0 ? m_LayoutName : m_LayoutNameHue); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(ItemID); - - if (Hue != 0) - { - disp.AppendLayout(Hue); - } - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { - writer.Write(Hue == 0 ? m_LayoutName : m_LayoutNameHue); + writer.Write(Hue == 0 ? LayoutName : LayoutNameHue); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpItemProperty.cs b/Projects/Server/Gumps/GumpItemProperty.cs index e6eb2c8a9..fc030a23a 100644 --- a/Projects/Server/Gumps/GumpItemProperty.cs +++ b/Projects/Server/Gumps/GumpItemProperty.cs @@ -6,25 +6,19 @@ namespace Server.Gumps { public class GumpItemProperty : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("itemproperty"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("itemproperty"); public GumpItemProperty(uint serial) => Serial = serial; public uint Serial { get; set; } - public override string Compile(NetState ns) => $"{{ itemproperty {Serial} }}"; public override string Compile(OrderedHashSet strings) => $"{{ itemproperty {Serial} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(Serial); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(Serial.ToString()); writer.Write((ushort)0x207D); // " }" } diff --git a/Projects/Server/Gumps/GumpLabel.cs b/Projects/Server/Gumps/GumpLabel.cs index 749560be7..c4c9b3396 100644 --- a/Projects/Server/Gumps/GumpLabel.cs +++ b/Projects/Server/Gumps/GumpLabel.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpLabel : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("text"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("text"); public GumpLabel(int x, int y, int hue, string text) { @@ -23,23 +23,13 @@ namespace Server.Gumps public int Hue { get; set; } public string Text { get; set; } - - public override string Compile(NetState ns) => $"{{ text {X} {Y} {Hue} {Parent.Intern(Text)} }}"; public override string Compile(OrderedHashSet strings) => $"{{ text {X} {Y} {Hue} {strings.GetOrAdd(Text)} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Hue); - disp.AppendLayout(Parent.Intern(Text)); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpLabelCropped.cs b/Projects/Server/Gumps/GumpLabelCropped.cs index 053d83715..233dc59dd 100644 --- a/Projects/Server/Gumps/GumpLabelCropped.cs +++ b/Projects/Server/Gumps/GumpLabelCropped.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpLabelCropped : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("croppedtext"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("croppedtext"); public GumpLabelCropped(int x, int y, int width, int height, int hue, string text) { @@ -30,27 +30,14 @@ namespace Server.Gumps public string Text { get; set; } - public override string Compile(NetState ns) => - $"{{ croppedtext {X} {Y} {Width} {Height} {Hue} {Parent.Intern(Text)} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ croppedtext {X} {Y} {Width} {Height} {Hue} {strings.GetOrAdd(Text)} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Hue); - disp.AppendLayout(Parent.Intern(Text)); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpMasterGump.cs b/Projects/Server/Gumps/GumpMasterGump.cs index 7c422d5e8..fae0148b9 100644 --- a/Projects/Server/Gumps/GumpMasterGump.cs +++ b/Projects/Server/Gumps/GumpMasterGump.cs @@ -21,25 +21,19 @@ namespace Server.Gumps { public class GumpMasterGump : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("mastergump"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("mastergump"); public GumpMasterGump(int gumpID) => GumpID = gumpID; public int GumpID { get; set; } - public override string Compile(NetState ns) => $"{{ mastergump {GumpID} }}"; public override string Compile(OrderedHashSet strings) => $"{{ mastergump {GumpID} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(GumpID); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(GumpID.ToString()); writer.Write((ushort)0x207D); // " }" } diff --git a/Projects/Server/Gumps/GumpPage.cs b/Projects/Server/Gumps/GumpPage.cs index c1a36f99a..c48fa7c97 100644 --- a/Projects/Server/Gumps/GumpPage.cs +++ b/Projects/Server/Gumps/GumpPage.cs @@ -6,25 +6,18 @@ namespace Server.Gumps { public class GumpPage : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("page"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("page"); public GumpPage(int page) => Page = page; public int Page { get; set; } - - public override string Compile(NetState ns) => $"{{ page {Page} }}"; public override string Compile(OrderedHashSet strings) => $"{{ page {Page} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(Page); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(Page.ToString()); writer.Write((ushort)0x207D); // " }" } diff --git a/Projects/Server/Gumps/GumpRadio.cs b/Projects/Server/Gumps/GumpRadio.cs index 5aac49589..eb5e4e51a 100644 --- a/Projects/Server/Gumps/GumpRadio.cs +++ b/Projects/Server/Gumps/GumpRadio.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpRadio : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("radio"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("radio"); public GumpRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID) { @@ -30,29 +30,14 @@ namespace Server.Gumps public int SwitchID { get; set; } - public override string Compile(NetState ns) => - $"{{ radio {X} {Y} {InactiveID} {ActiveID} {(InitialState ? 1 : 0)} {SwitchID} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ radio {X} {Y} {InactiveID} {ActiveID} {(InitialState ? 1 : 0)} {SwitchID} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(InactiveID); - disp.AppendLayout(ActiveID); - disp.AppendLayout(InitialState); - disp.AppendLayout(SwitchID); - - disp.Switches++; - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpSpriteImage.cs b/Projects/Server/Gumps/GumpSpriteImage.cs index 45a6eb771..12acb5adc 100644 --- a/Projects/Server/Gumps/GumpSpriteImage.cs +++ b/Projects/Server/Gumps/GumpSpriteImage.cs @@ -21,7 +21,7 @@ namespace Server.Gumps { public class GumpSpriteImage : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("picinpic"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("picinpic"); public GumpSpriteImage(int x, int y, int gumpID, int width, int height, int sx, int sy) { @@ -47,27 +47,14 @@ namespace Server.Gumps public int SX { get; set; } public int SY { get; set; } - - public override string Compile(NetState ns) => $"{{ picinpic {X} {Y} {GumpID} {Width} {Height} {SX} {SY} }}"; public override string Compile(OrderedHashSet strings) => $"{{ picinpic {X} {Y} {GumpID} {Width} {Height} {SX} {SY} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(GumpID); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(SX); - disp.AppendLayout(SY); - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpTextEntry.cs b/Projects/Server/Gumps/GumpTextEntry.cs index 93f3b422a..9b5671aad 100644 --- a/Projects/Server/Gumps/GumpTextEntry.cs +++ b/Projects/Server/Gumps/GumpTextEntry.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpTextEntry : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("textentry"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("textentry"); public GumpTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText) { @@ -33,30 +33,14 @@ namespace Server.Gumps public string InitialText { get; set; } - public override string Compile(NetState ns) => - $"{{ textentry {X} {Y} {Width} {Height} {Hue} {EntryID} {Parent.Intern(InitialText)} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ textentry {X} {Y} {Width} {Height} {Hue} {EntryID} {strings.GetOrAdd(InitialText)} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Hue); - disp.AppendLayout(EntryID); - disp.AppendLayout(Parent.Intern(InitialText)); - - disp.TextEntries++; - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpTextEntryLimited.cs b/Projects/Server/Gumps/GumpTextEntryLimited.cs index 9d66ccc77..8e887ce0f 100644 --- a/Projects/Server/Gumps/GumpTextEntryLimited.cs +++ b/Projects/Server/Gumps/GumpTextEntryLimited.cs @@ -6,7 +6,7 @@ namespace Server.Gumps { public class GumpTextEntryLimited : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("textentrylimited"); public GumpTextEntryLimited( int x, int y, int width, int height, int hue, int entryID, string initialText, int size = 0 @@ -38,31 +38,14 @@ namespace Server.Gumps public int Size { get; set; } - public override string Compile(NetState ns) => - $"{{ textentrylimited {X} {Y} {Width} {Height} {Hue} {EntryID} {Parent.Intern(InitialText)} {Size} }}"; - public override string Compile(OrderedHashSet strings) => $"{{ textentrylimited {X} {Y} {Width} {Height} {Hue} {EntryID} {strings.GetOrAdd(InitialText)} {Size} }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(X); - disp.AppendLayout(Y); - disp.AppendLayout(Width); - disp.AppendLayout(Height); - disp.AppendLayout(Hue); - disp.AppendLayout(EntryID); - disp.AppendLayout(Parent.Intern(InitialText)); - disp.AppendLayout(Size); - - disp.TextEntries++; - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); diff --git a/Projects/Server/Gumps/GumpTooltip.cs b/Projects/Server/Gumps/GumpTooltip.cs index 4b9278f40..66ff5fb19 100644 --- a/Projects/Server/Gumps/GumpTooltip.cs +++ b/Projects/Server/Gumps/GumpTooltip.cs @@ -21,7 +21,7 @@ namespace Server.Gumps { public class GumpTooltip : GumpEntry { - private static readonly byte[] m_LayoutName = Gump.StringToBuffer("tooltip"); + public static readonly byte[] LayoutName = Gump.StringToBuffer("tooltip"); public GumpTooltip(int number, string args) { @@ -33,26 +33,14 @@ namespace Server.Gumps public string Args { get; set; } - public override string Compile(NetState ns) => - string.IsNullOrEmpty(Args) ? $"{{ tooltip {Number} }}" : $"{{ tooltip {Number} @{Args}@ }}"; public override string Compile(OrderedHashSet strings) => string.IsNullOrEmpty(Args) ? $"{{ tooltip {Number} }}" : $"{{ tooltip {Number} @{Args}@ }}"; - public override void AppendTo(NetState ns, IGumpWriter disp) - { - disp.AppendLayout(m_LayoutName); - disp.AppendLayout(Number); - - if (!string.IsNullOrEmpty(Args)) - { - disp.AppendLayout(Args); - } - } - public override void AppendTo(ref SpanWriter writer, OrderedHashSet strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " - writer.Write(m_LayoutName); + writer.Write(LayoutName); + writer.Write((byte)0x20); // ' ' writer.WriteAscii(Number.ToString()); if (!string.IsNullOrEmpty(Args)) diff --git a/Projects/Server/Network/Packets/OutgoingGumpPackets.cs b/Projects/Server/Network/Packets/OutgoingGumpPackets.cs index 00e5f38ae..699489c3f 100644 --- a/Projects/Server/Network/Packets/OutgoingGumpPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingGumpPackets.cs @@ -13,7 +13,13 @@ * along with this program. If not, see . * *************************************************************************/ +using System; using System.Buffers; +using System.IO; +using System.IO.Compression; +using System.Runtime.CompilerServices; +using Server.Collections; +using Server.Gumps; namespace Server.Network { @@ -36,5 +42,152 @@ namespace Server.Network ns.Send(writer.Span); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WritePacked(ref SpanWriter writer, ReadOnlySpan span) + { + var length = span.Length; + + if (length == 0) + { + writer.Write(0); + return; + } + + var wantLength = 1 + span.Length * 1024 / 1000; + + wantLength += 4095; + wantLength &= ~4095; + + var packBuffer = ArrayPool.Shared.Rent(wantLength); + var packLength = wantLength; + + Zlib.Pack(packBuffer, ref packLength, span, length, ZlibQuality.Default); + + writer.Write(4 + packLength); + writer.Write(length); + writer.Write(packBuffer.AsSpan(0, packLength)); + + ArrayPool.Shared.Return(packBuffer); + } + + public static void SendDisplayGump(this NetState ns, Gump gump, out int switches, out int entries) + { + switches = 0; + entries = 0; + + if (ns == null) + { + return; + } + + var packed = ns.Unpack; + + var writer = new SpanWriter(512, true); + writer.Write((byte)(packed ? 0xDD : 0xB0)); // Packet ID + writer.Seek(2, SeekOrigin.Current); + + writer.Write(gump.Serial); + writer.Write(gump.TypeID); + writer.Write(gump.X); + writer.Write(gump.Y); + + var spanWriter = new SpanWriter(512, true); + + if (!gump.Draggable) + { + spanWriter.Write(Gump.NoMove); + } + + if (!gump.Closable) + { + spanWriter.Write(Gump.NoClose); + } + + if (!gump.Disposable) + { + spanWriter.Write(Gump.NoDispose); + } + + if (!gump.Resizable) + { + spanWriter.Write(Gump.NoResize); + } + + var stringsList = new OrderedHashSet(11); + + foreach (var entry in gump.Entries) + { + entry.AppendTo(ref spanWriter, stringsList, ref entries, ref switches); + } + + if (packed) + { + spanWriter.Write((byte)0); // Layout text terminator + WritePacked(ref writer, spanWriter.Span); + } + else + { + writer.Write((ushort)spanWriter.BytesWritten); + writer.Write(spanWriter.Span); + } + + if (packed) + { + writer.Write(stringsList.Count); + } + else + { + writer.Write((ushort)stringsList.Count); + } + + spanWriter.Seek(0, SeekOrigin.Begin); + + foreach (var str in stringsList) + { + var s = str ?? ""; + spanWriter.Write((ushort)s.Length); + spanWriter.WriteBigUni(s); + } + + if (packed) + { + WritePacked(ref writer, spanWriter.Span); + } + else + { + writer.Write(spanWriter.Span); + } + + writer.WritePacketLength(); + + ns.Send(writer.Span); + spanWriter.Dispose(); // Can't use using and refs, so we dispose manually + } + + public static void SendDisplaySignGump(this NetState ns, Serial serial, int gumpId, string unknown, string caption) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + unknown ??= ""; + caption ??= ""; + + var length = 15 + unknown.Length + caption.Length; + var writer = new SpanWriter(stackalloc byte[length]); + writer.Write((byte)0x8B); // Packet ID + writer.Write((ushort)length); + + writer.Write(serial); + writer.Write((short)gumpId); + writer.Write((short)(unknown.Length + 1)); + writer.WriteAsciiNull(unknown); + writer.Write((short)(caption.Length + 1)); + writer.WriteAsciiNull(caption); + + ns.Send(writer.Span); + } } }