public void Basics() { Span <IBufferTransformation> transformations = s_transformations; Span <byte> buffer = stackalloc byte[256]; var writer = new SpanWriter(buffer); writer.Index = 0; writer.Write("AaBc", transformations.Slice(0, 2)); Assert.Equal("AABC", Encodings.Utf8.ToString(writer.Written)); writer.Index = 0; writer.Write("AaBc", transformations.Slice(0, 1)); Assert.Equal("aabc", Encodings.Utf8.ToString(writer.Written)); writer.Index = 0; writer.Write("AaBc", transformations.Slice(1, 1)); Assert.Equal("AABC", Encodings.Utf8.ToString(writer.Written)); writer.Index = 0; writer.Write("AaBc", transformations); Assert.Equal("AABC", Encodings.Utf8.ToString(writer.Written)); }
public override void AppendTo(ref SpanWriter writer, OrderedHashSet <string> strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " writer.Write(LayoutName); writer.WriteAscii(' '); writer.WriteAscii(X.ToString()); writer.WriteAscii(' '); writer.WriteAscii(Y.ToString()); writer.WriteAscii(' '); writer.WriteAscii(Width.ToString()); writer.WriteAscii(' '); writer.WriteAscii(Height.ToString()); writer.WriteAscii(' '); writer.WriteAscii(Hue.ToString()); writer.WriteAscii(' '); writer.WriteAscii(EntryID.ToString()); writer.WriteAscii(' '); writer.WriteAscii(strings.GetOrAdd(InitialText ?? "").ToString()); writer.Write((ushort)0x207D); // " }" entries++; }
public static void CreateSoundEffect(ref Span <byte> buffer, int soundID, IPoint3D target) { var writer = new SpanWriter(buffer); writer.Write((byte)0x54); // Packet ID writer.Write((byte)1); // flags writer.Write((short)soundID); writer.Write((short)0); // volume writer.Write((short)target.X); writer.Write((short)target.Y); writer.Write((short)target.Z); }
public void Add(int number, string?arguments = null) { if (number == 0) { return; } arguments ??= ""; if (Header == 0) { Header = number; HeaderArgs = arguments; } AddHash(number); if (arguments.Length > 0) { AddHash(arguments.GetHashCode(StringComparison.Ordinal)); } int strLength = arguments.Length * 2; int length = _bufferPos + 6 + strLength; while (length > _buffer.Length) { Flush(); } var writer = new SpanWriter(_buffer.AsSpan(_bufferPos)); writer.Write(number); writer.Write((ushort)strLength); writer.WriteLittleUni(arguments); _bufferPos += writer.BytesWritten; _pos = 0; }
public override void AppendTo(ref SpanWriter writer, OrderedHashSet <string> strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " 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); // ' ' writer.WriteAscii(Width.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Height.ToString()); writer.Write((ushort)0x207D); // " }" }
public static void CreateMobileMoving(Span <byte> buffer, Mobile m, int noto, bool stygianAbyss) { if (buffer[0] != 0) { return; } var loc = m.Location; var hue = m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.Hue; var writer = new SpanWriter(buffer); writer.Write((byte)0x77); // Packet ID writer.Write(m.Serial); writer.Write((short)m.Body); writer.Write((short)loc.m_X); writer.Write((short)loc.m_Y); writer.Write((sbyte)loc.m_Z); writer.Write((byte)m.Direction); writer.Write((short)hue); writer.Write((byte)m.GetPacketFlags(stygianAbyss)); writer.Write((byte)noto); }
private void InternalAdd( int number, [InterpolatedStringHandlerArgument("")] ref IPropertyList.InterpolatedStringHandler handler) { if (number == 0) { return; } var chars = _arrayToReturnToPool.AsSpan(0, _pos); if (Header == 0) { Header = number; HeaderArgs = chars.ToString(); } AddHash(number); AddHash(string.GetHashCode(chars, StringComparison.Ordinal)); int strLength = chars.Length * 2; int length = _bufferPos + 6 + strLength; while (length > _buffer.Length) { Flush(); } var writer = new SpanWriter(_buffer.AsSpan(_bufferPos)); writer.Write(number); writer.Write((ushort)strLength); writer.Write(chars, TextEncoding.UnicodeLE); _bufferPos += writer.BytesWritten; }
public void Add(int number, string arguments = null) { if (number == 0) { return; } arguments ??= ""; if (Header == 0) { Header = number; HeaderArgs = arguments; } AddHash(number); if (arguments.Length > 0) { AddHash(arguments.GetHashCode(StringComparison.Ordinal)); } int strLength = Utility.Unicode.GetByteCount(arguments); int length = _position + 6 + strLength; while (length > _buffer.Length) { Flush(); } var writer = new SpanWriter(_buffer); writer.Seek(_position, SeekOrigin.Begin); writer.Write(number); writer.Write((ushort)strLength); writer.WriteBigUni(arguments); }
public void Marshal(Span <byte> span, int protocolVersion) { var writer = new SpanWriter(span); var status = _character.Status; writer.WriteByte((byte)(status.Health * 100 / status.MaxHealth)); writer.WriteByte((byte)(status.Mana * 100 / status.MaxMana)); writer.WriteByte((byte)(_character.Sitting ? 0x02 : 0x00)); writer.WriteByte((byte)(status.Endurance * 100 / status.MaxEndurance)); writer.WriteByte((byte)(status.Concentration * 100 / status.MaxConcentration)); // DoL represents "alive" as a separate property, but elsewhere uses health > 0 // DoL hard codes 0x00 for alive - some doubt in comments about how to represent dead writer.WriteByte((byte)(status.Health > 0 ? 0x00 : 0x0F)); writer.Write(status); }
public override void AppendTo(ref SpanWriter writer, OrderedHashSet <string> strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " 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(Hue.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(strings.GetOrAdd(Text).ToString()); writer.Write((ushort)0x207D); // " }" }
public const int MobileMovingPacketCacheLength = MobileMovingPacketLength * 8 * 2; // 8 notoriety, 2 client versions public static void CreateBondedStatus(Span <byte> buffer, Serial serial, bool bonded) { var writer = new SpanWriter(buffer); writer.Write((byte)0xBF); // Packet ID writer.Write((ushort)11); // Length writer.Write((ushort)0x19); // Subpacket ID writer.Write((byte)0); // Command writer.Write(serial); writer.Write(bonded); }
public static int CreateMessage( Span <byte> buffer, Serial serial, int graphic, MessageType type, int hue, int font, bool ascii, string lang, string name, string text ) { if (buffer[0] != 0) { return(buffer.Length); } name ??= ""; text ??= ""; lang ??= "ENU"; if (hue == 0) { hue = 0x3B2; } var writer = new SpanWriter(buffer); writer.Write((byte)(ascii ? 0x1C : 0xAE)); // Packet ID writer.Seek(2, SeekOrigin.Current); writer.Write(serial); writer.Write((short)graphic); writer.Write((byte)type); writer.Write((short)hue); writer.Write((short)font); if (ascii) { writer.WriteAscii(name, 30); writer.WriteAsciiNull(text); } else { writer.WriteAscii(lang, 4); writer.WriteAscii(name, 30); writer.WriteBigUniNull(text); } writer.WritePacketLength(); return(writer.Position); }
public override void AppendTo(ref SpanWriter writer, OrderedHashSet <string> strings, ref int entries, ref int switches) { writer.Write((ushort)0x7B20); // "{ " writer.Write(LayoutName); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Number.ToString()); if (!string.IsNullOrEmpty(Args)) { writer.Write((byte)0x20); // ' ' writer.Write((byte)0x40); // '@' writer.WriteAscii(Args); writer.Write((byte)0x40); // '@' } writer.Write((ushort)0x207D); // " }" }
public unsafe void TestSpanWriterOnlyStackAlloc() { Span <byte> smallStack = stackalloc byte[8]; using var writer = new SpanWriter(smallStack, true); writer.Write(0x1024L); var span = writer.RawBuffer; fixed(byte *spanPtr = span) { fixed(byte *stackPtr = smallStack) { Assert.True(spanPtr == stackPtr); } } Assert.True(span.Length == smallStack.Length); AssertThat.Equal(smallStack, stackalloc byte[] { 0, 0, 0, 0, 0, 0, 0x10, 0x24 });
public static void CreateHairEquipUpdatePacket(Span <byte> buffer, Mobile m, uint hairSerial, int itemId, int hue, Layer layer) { if (buffer[0] != 0) { return; } var writer = new SpanWriter(buffer); writer.Write((byte)0x2E); // Packet ID writer.Write(hairSerial); writer.Write((short)itemId); writer.Write((byte)0); writer.Write((byte)layer); writer.Write(m.Serial); writer.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : hue)); }
private void CalculateChecksumAndWriteOggHeaderToBinaryWriter(OggHeader oggHeader, byte[] data) { var oggHeaderBytes = ArrayPool <byte> .Shared.Rent(oggHeader.Size); try { var spanWriter = new SpanWriter(oggHeaderBytes); spanWriter.WriteOggHeader(oggHeader); var checkSum = OggCRC32.CalculateCRC(0, oggHeaderBytes.AsSpan().Slice(0, oggHeader.Size), data); spanWriter.Write(checkSum, OggHeader.CheckSumLocation); _writer.Write(oggHeaderBytes, 0, oggHeader.Size); } finally { ArrayPool <byte> .Shared.Return(oggHeaderBytes); } _writer.Write(data); }
public static int CreateMessageLocalizedAffix( Span <byte> buffer, Serial serial, int graphic, MessageType type, int hue, int font, int number, string name, AffixType affixType, string affix = "", string args = "" ) { if (buffer[0] != 0) { return(buffer.Length); } name ??= ""; affix ??= ""; args ??= ""; if (hue == 0) { hue = 0x3B2; } var writer = new SpanWriter(buffer); writer.Write((byte)0xCC); writer.Seek(2, SeekOrigin.Current); writer.Write(serial); writer.Write((short)graphic); writer.Write((byte)type); writer.Write((short)hue); writer.Write((short)font); writer.Write(number); writer.Write((byte)affixType); writer.WriteAscii(name, 30); writer.WriteAsciiNull(affix); writer.WriteBigUniNull(args); writer.WritePacketLength(); return(writer.Position); }
public static void CreateHairEquipUpdatePacket(Span <byte> buffer, Mobile m, Serial hairSerial, Layer layer) { if (buffer[0] != 0) { return; } var hue = m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.HairHue; var writer = new SpanWriter(buffer); writer.Write((byte)0x2E); // Packet ID writer.Write(hairSerial); writer.Write((short)m.HairItemID); writer.Write((byte)0); writer.Write((byte)layer); writer.Write(m.Serial); writer.Write((short)hue); }
public override void AppendTo(ref SpanWriter writer, OrderedHashSet <string> strings, ref int entries, ref int switches) { writer.Write(Hue == 0 ? LayoutName : LayoutNameHue); writer.Write((byte)0x20); // ' ' writer.WriteAscii(X.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(Y.ToString()); writer.Write((byte)0x20); // ' ' writer.WriteAscii(ItemID.ToString()); if (Hue != 0) { writer.Write((byte)0x20); // ' ' writer.WriteAscii(Hue.ToString()); } writer.Write((ushort)0x207D); // " }" }
private static void WritePacked(ReadOnlySpan <byte> span, ref SpanWriter writer) { var length = span.Length; if (length == 0) { writer.Write(0); return; } var wantLength = Zlib.MaxPackSize(length); var packBuffer = _packBuffer; byte[] rentedBuffer = null; if (wantLength > packBuffer.Length) { packBuffer = rentedBuffer = ArrayPool <byte> .Shared.Rent(wantLength); } var packLength = wantLength; var error = Zlib.Pack(packBuffer, ref packLength, span, length, ZlibQuality.Default); if (error != ZlibError.Okay) { Utility.PushColor(ConsoleColor.Red); Core.WriteConsoleLine($"Gump compression failed {error}"); Utility.PopColor(); writer.Write(4); writer.Write(0); return; } writer.Write(4 + packLength); writer.Write(length); writer.Write(packBuffer.AsSpan(0, packLength)); if (rentedBuffer != null) { ArrayPool <byte> .Shared.Return(rentedBuffer); } }
public static void CreatePartyMemberList(Span <byte> buffer, Party p) { if (buffer[0] != 0) { return; } var length = GetPartyMemberListPacketLength(p); var writer = new SpanWriter(buffer); writer.Write((byte)0xBF); // Packet ID writer.Write((ushort)length); writer.Write((ushort)0x06); // Sub-packet writer.Write((byte)0x01); // Command writer.Write((byte)p.Count); for (var i = 0; i < p.Count; ++i) { writer.Write(p[i].Mobile.Serial); } }
public static void CreatePartyRemoveMember(Span <byte> buffer, Serial removed, Party p = null) { if (buffer[0] != 0) { return; } var length = GetPartyRemoveMemberPacketLength(p); var writer = new SpanWriter(buffer); writer.Write((byte)0xBF); // Packet ID writer.Write((ushort)length); writer.Write((ushort)0x06); // Sub-packet writer.Write((byte)0x02); // Command var count = p?.Count ?? 0; writer.Write((byte)count); writer.Write(removed); for (var i = 0; i < count; ++i) { writer.Write(p ![i].Mobile.Serial);
public static bool TryWrite(Span <byte> output, Sha256 hash, string keyType, string verb, string resourceId, string resourceType, string tokenVersion, DateTime utc, out int bytesWritten) { Span <byte> buffer = stackalloc byte[AuthenticationHeaderBufferSize]; var writer = new SpanWriter(buffer); writer.Enlarge = (minumumSize) => { return(new byte[minumumSize * 2]); }; // compute signature hash writer.WriteLine(verb, Ascii.ToLowercase); writer.WriteLine(resourceType, Ascii.ToLowercase); writer.WriteLine(resourceId, Ascii.ToLowercase); writer.WriteLine(utc, 'l'); writer.Write('\n'); hash.Append(writer.Written); // combine token writer.Index = 0; // reuse writer and buffer writer.Write("type="); writer.Write(keyType); writer.Write("&ver="); writer.Write(tokenVersion); writer.Write("&sig="); writer.WriteBytes(hash, default, Base64Experimental.BytesToUtf8Encoder);
public static Span <byte> EncodeVersion(Version version) { var array = new byte[4096]; var buffer = new Span <byte>(array); var writer = new SpanWriter(buffer); // case Manifest.LogTagType.Comparator: if (!string.IsNullOrEmpty(version.Comparator)) { writer.WriteVarLong((ulong)LogTagType.Comparator); writer.Write(version.Comparator); } // case Manifest.LogTagType.LogNumber: { writer.WriteVarLong((ulong)LogTagType.LogNumber); writer.WriteVarLong((ulong)version.LogNumber); } // case Manifest.LogTagType.PrevLogNumber: { writer.WriteVarLong((ulong)LogTagType.PrevLogNumber); writer.WriteVarLong((ulong)version.PreviousLogNumber); } // case Manifest.LogTagType.NextFileNumber: { writer.WriteVarLong((ulong)LogTagType.NextFileNumber); writer.WriteVarLong((ulong)version.NextFileNumber); } // case Manifest.LogTagType.LastSequence: { writer.WriteVarLong((ulong)LogTagType.LastSequence); writer.WriteVarLong((ulong)version.LastSequenceNumber); } // case Manifest.LogTagType.CompactPointer: if (version.CompactPointers.Count > 0) { foreach (KeyValuePair <int, byte[]> pointer in version.CompactPointers) { writer.WriteVarLong((ulong)LogTagType.CompactPointer); writer.WriteVarLong((ulong)pointer.Key); writer.WriteLengthPrefixed(pointer.Value); } } // case Manifest.LogTagType.DeletedFile: //if (version.DeletedFiles.Count > 0) //{ // foreach (KeyValuePair<int, List<ulong>> files in version.DeletedFiles) // { // foreach (ulong fileNumber in files.Value) // { // writer.WriteVarLong((ulong) LogTagType.DeletedFile); // writer.WriteVarLong((ulong) files.Key); // writer.WriteVarLong(fileNumber); // } // } //} // case Manifest.LogTagType.NewFile: if (version.Levels.Count > 0) { foreach (KeyValuePair <int, List <FileMetadata> > files in version.Levels) { int level = files.Key; foreach (FileMetadata fileMeta in files.Value) { writer.WriteVarLong((ulong)LogTagType.NewFile); //int level = (int) reader.ReadVarLong(); writer.WriteVarLong((ulong)level); //ulong fileNumber = reader.ReadVarLong(); writer.WriteVarLong((ulong)fileMeta.FileNumber); //ulong fileSize = reader.ReadVarLong(); writer.WriteVarLong((ulong)fileMeta.FileSize); //var smallest = reader.ReadLengthPrefixedBytes(); writer.WriteLengthPrefixed(fileMeta.SmallestKey); //var largest = reader.ReadLengthPrefixedBytes(); writer.WriteLengthPrefixed(fileMeta.LargestKey); } } } int length = writer.Position; return(buffer.Slice(0, length).ToArray()); }
public static int CreateWorldItem(Span <byte> buffer, Item item) { if (buffer[0] != 0) { return(buffer.Length); } var itemID = item is BaseMulti ? item.ItemID | 0x4000 : item.ItemID & 0x3FFF; var hasAmount = item.Amount != 0; var amount = item.Amount; var serial = hasAmount ? item.Serial | 0x80000000 : item.Serial & 0x7FFFFFFF; var loc = item.Location; var hue = item.Hue; var flags = item.GetPacketFlags(); var direction = (int)item.Direction; var hasDirection = direction != 0; var hasHue = hue != 0; var hasFlags = flags != 0; var x = hasDirection ? loc.X | 0x8000 : loc.X & 0x7FFF; var y = (loc.Y & 0x3FFF) | (hasHue ? 0x8000 : 0) | (hasFlags ? 0x4000 : 0); var length = 14 + (hasAmount ? 2 : 0) + (hasDirection ? 1 : 0) + (hasHue ? 2 : 0) + (hasFlags ? 1 : 0); var writer = new SpanWriter(buffer); writer.Write((byte)0x1A); // Packet ID writer.Write((ushort)length); writer.Write(serial); writer.Write((ushort)itemID); if (amount != 0) { writer.Write((ushort)amount); } writer.Write((ushort)x); writer.Write((ushort)y); if (direction != 0) { writer.Write((byte)direction); } writer.Write((sbyte)loc.Z); if (hue != 0) { writer.Write((ushort)hue); } if (flags != 0) { writer.Write((byte)flags); } return(writer.Position); }
public static int CreateWorldEntity(Span <byte> buffer, IEntity entity, bool isHS) { if (buffer[0] != 0) { return(buffer.Length); } var writer = new SpanWriter(buffer); writer.Write((byte)0xF3); // Packet ID writer.Write((short)0x1); // command int type = 0; int gfx = 0; int amount = 1; int hue = 0; byte light = 0; int flags = 0; if (entity is BaseMulti multi) { type = 2; gfx = multi.ItemID & (isHS ? 0xFFFF : 0x7FFF); hue = multi.Hue; amount = multi.Amount; } else if (entity is Item item) { // type = 3 if is damageable gfx = item.ItemID & (isHS ? 0xFFFF : 0x7FFF); hue = item.Hue; amount = item.Amount; light = (byte)item.Light; flags = item.GetPacketFlags(); } else if (entity is Mobile mobile) { type = 1; gfx = mobile.Body; hue = mobile.Hue; flags = mobile.GetPacketFlags(true); } writer.Write((byte)type); writer.Write(entity.Serial); writer.Write((ushort)gfx); writer.Write((byte)0); writer.Write((short)amount); // Min writer.Write((short)amount); // Max writer.Write((short)(entity.X & 0x7FFF)); writer.Write((short)(entity.Y & 0x3FFF)); writer.Write((sbyte)entity.Z); writer.Write(light); writer.Write((short)hue); writer.Write((byte)flags); if (isHS) { writer.Write((short)0); } return(writer.Position); }
public static void CreateParticleEffect( Span <byte> buffer, EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, Serial serial, int layer, int unknown ) { if (buffer[0] != 0) { return; } var writer = new SpanWriter(buffer); writer.Write((byte)0xC7); // Packet ID writer.Write((byte)type); writer.Write(from); writer.Write(to); writer.Write((short)itemID); writer.Write((short)fromPoint.X); writer.Write((short)fromPoint.Y); writer.Write((sbyte)fromPoint.Z); writer.Write((short)toPoint.X); writer.Write((short)toPoint.Y); writer.Write((sbyte)toPoint.Z); writer.Write((byte)speed); writer.Write((byte)duration); writer.Write((byte)0); writer.Write((byte)0); writer.Write(fixedDirection); writer.Write(explode); writer.Write(hue); writer.Write(renderMode); writer.Write((short)effect); writer.Write((short)explodeEffect); writer.Write((short)explodeSound); writer.Write(serial); writer.Write((byte)layer); writer.Write((short)unknown); }
public static void CreateHuedEffect( Span <byte> buffer, EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode ) { if (buffer[0] != 0) { return; } var writer = new SpanWriter(buffer); writer.Write((byte)0xC0); // Packet ID writer.Write((byte)type); writer.Write(from); writer.Write(to); writer.Write((short)itemID); writer.Write((short)fromPoint.X); writer.Write((short)fromPoint.Y); writer.Write((sbyte)fromPoint.Z); writer.Write((short)toPoint.X); writer.Write((short)toPoint.Y); writer.Write((sbyte)toPoint.Z); writer.Write((byte)speed); writer.Write((byte)duration); writer.Write((byte)0); writer.Write((byte)0); writer.Write(fixedDirection); writer.Write(explode); writer.Write(hue); writer.Write(renderMode); }
public void Marshal(Span <byte> span, int protocolVersion) { var writer = new SpanWriter(span); writer.Write(_points); }
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 layoutWriter = new SpanWriter(_layoutBuffer); if (!gump.Draggable) { layoutWriter.Write(Gump.NoMove); } if (!gump.Closable) { layoutWriter.Write(Gump.NoClose); } if (!gump.Disposable) { layoutWriter.Write(Gump.NoDispose); } if (!gump.Resizable) { layoutWriter.Write(Gump.NoResize); } var stringsList = new OrderedHashSet <string>(11); foreach (var entry in gump.Entries) { entry.AppendTo(ref layoutWriter, stringsList, ref entries, ref switches); } var stringsWriter = new SpanWriter(_stringsBuffer); foreach (var str in stringsList) { var s = str ?? ""; stringsWriter.Write((ushort)s.Length); stringsWriter.WriteBigUni(s); } int maxLength; if (packed) { var worstLayoutLength = Zlib.MaxPackSize(layoutWriter.BytesWritten); var worstStringsLength = Zlib.MaxPackSize(stringsWriter.BytesWritten); maxLength = 40 + worstLayoutLength + worstStringsLength; } else { maxLength = 23 + layoutWriter.BytesWritten + stringsWriter.BytesWritten; } var writer = new SpanWriter(stackalloc byte[maxLength]); 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); if (packed) { layoutWriter.Write((byte)0); // Layout text terminator WritePacked(layoutWriter.Span, ref writer); writer.Write(stringsList.Count); WritePacked(stringsWriter.Span, ref writer); } else { writer.Write((ushort)layoutWriter.BytesWritten); writer.Write(layoutWriter.Span); writer.Write((ushort)stringsList.Count); writer.Write(stringsWriter.Span); } writer.WritePacketLength(); ns.Send(writer.Span); }