mirror of
https://github.com/ServUO/ServUO
synced 2026-08-11 20:23:04 -04:00
+ Add MONO to Makefile compile definitions. + Update Ultima SDK to support MONO compile definition. + Rename Properties Gump parent directory to prevent VS issues. + Console error messages will now use red instead of dark red font. + Add crash state handler function to Core. + AI optimizations and housekeeping. + Context Menu optimizations and housekeeping. + Add ability to drop throttled packets. + Add string parsing support to Rectangle3D. + Optimize guild messages and chat. + IAddon implements IChopable. + Add more flexibility for altering Mobile names. + Add ability to enable or disable OPL for individual mobiles. + Optimize damaging regions and ensure timers are removed properly. + Update Welcome Timer with more intuitive message groups. + Normalize all virtue related objects to the Server.Services.Virtues namespace. + Add ability for ISpawner to append OPL and Context Menus to their spawn. + Add EventSink events for obtaining items, equipping items, context menus, and world broadcasts. + Add ability to lock a creature's direction and movement regardless of AI manipulation. + Add ability to dynamically change a creature's approach range and wait state. + Add extended enumeration features for AOS attributes. + Add ability to control whether creatures have blood, and its color. + Expose corpse flag manipulation methods. + Add ability to prevent criminal action when looting a corpse. + Corpse will now be permanently tagged as murderer at time of death if owner is a murderer. + Add TextDefinition support for Commodity Deed descriptions. + House add-on and component optimizations and housekeeping. + Item light is no longer backed by the direction property. + ITool implements IEntity. + Prevent trading of Siege Bless items. + Guards are naturally be immune to guards. + Siege Shard initialization housekeeping. + Character Creation housekeeping. + Generic commands housekeeping. + Add Mark command for staff.
439 lines
No EOL
11 KiB
C#
439 lines
No EOL
11 KiB
C#
#region References
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
#endregion
|
|
|
|
namespace Server.Network
|
|
{
|
|
/// <summary>
|
|
/// Provides functionality for writing primitive binary data.
|
|
/// </summary>
|
|
public class PacketWriter
|
|
{
|
|
private static readonly Stack<PacketWriter> m_Pool = new Stack<PacketWriter>();
|
|
|
|
public static PacketWriter CreateInstance()
|
|
{
|
|
return CreateInstance(32);
|
|
}
|
|
|
|
public static PacketWriter CreateInstance(int capacity)
|
|
{
|
|
PacketWriter pw = null;
|
|
|
|
lock (m_Pool)
|
|
{
|
|
if (m_Pool.Count > 0)
|
|
{
|
|
pw = m_Pool.Pop();
|
|
|
|
if (pw != null)
|
|
{
|
|
pw.m_Capacity = capacity;
|
|
pw.m_Stream.SetLength(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pw == null)
|
|
{
|
|
pw = new PacketWriter(capacity);
|
|
}
|
|
|
|
return pw;
|
|
}
|
|
|
|
public static void ReleaseInstance(PacketWriter pw)
|
|
{
|
|
lock (m_Pool)
|
|
{
|
|
if (!m_Pool.Contains(pw))
|
|
{
|
|
m_Pool.Push(pw);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
using (StreamWriter op = new StreamWriter("neterr.log"))
|
|
{
|
|
op.WriteLine("{0}\tInstance pool contains writer", DateTime.UtcNow);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Console.WriteLine("net error");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Internal stream which holds the entire packet.
|
|
/// </summary>
|
|
private readonly MemoryStream m_Stream;
|
|
|
|
private int m_Capacity;
|
|
|
|
/// <summary>
|
|
/// Internal format buffer.
|
|
/// </summary>
|
|
private readonly byte[] m_Buffer = new byte[4];
|
|
|
|
/// <summary>
|
|
/// Instantiates a new PacketWriter instance with the default capacity of 4 bytes.
|
|
/// </summary>
|
|
public PacketWriter()
|
|
: this(32)
|
|
{ }
|
|
|
|
/// <summary>
|
|
/// Instantiates a new PacketWriter instance with a given capacity.
|
|
/// </summary>
|
|
/// <param name="capacity">Initial capacity for the internal stream.</param>
|
|
public PacketWriter(int capacity)
|
|
{
|
|
m_Stream = new MemoryStream(capacity);
|
|
m_Capacity = capacity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1.
|
|
/// </summary>
|
|
public void Write(bool value)
|
|
{
|
|
m_Stream.WriteByte((byte)(value ? 1 : 0));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
|
/// </summary>
|
|
public void Write(byte value)
|
|
{
|
|
m_Stream.WriteByte(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 1-byte signed integer value to the underlying stream.
|
|
/// </summary>
|
|
public void Write(sbyte value)
|
|
{
|
|
m_Stream.WriteByte((byte)value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 2-byte signed integer value to the underlying stream.
|
|
/// </summary>
|
|
public void Write(short value)
|
|
{
|
|
m_Buffer[0] = (byte)(value >> 8);
|
|
m_Buffer[1] = (byte)value;
|
|
|
|
m_Stream.Write(m_Buffer, 0, 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 2-byte unsigned integer value to the underlying stream.
|
|
/// </summary>
|
|
public void Write(ushort value)
|
|
{
|
|
m_Buffer[0] = (byte)(value >> 8);
|
|
m_Buffer[1] = (byte)value;
|
|
|
|
m_Stream.Write(m_Buffer, 0, 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 4-byte signed integer value to the underlying stream.
|
|
/// </summary>
|
|
public void Write(int value)
|
|
{
|
|
m_Buffer[0] = (byte)(value >> 24);
|
|
m_Buffer[1] = (byte)(value >> 16);
|
|
m_Buffer[2] = (byte)(value >> 8);
|
|
m_Buffer[3] = (byte)value;
|
|
|
|
m_Stream.Write(m_Buffer, 0, 4);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a 4-byte unsigned integer value to the underlying stream.
|
|
/// </summary>
|
|
public void Write(uint value)
|
|
{
|
|
m_Buffer[0] = (byte)(value >> 24);
|
|
m_Buffer[1] = (byte)(value >> 16);
|
|
m_Buffer[2] = (byte)(value >> 8);
|
|
m_Buffer[3] = (byte)value;
|
|
|
|
m_Stream.Write(m_Buffer, 0, 4);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a sequence of bytes to the underlying stream
|
|
/// </summary>
|
|
public void Write(byte[] buffer, int offset, int size)
|
|
{
|
|
m_Stream.Write(buffer, offset, size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
|
/// </summary>
|
|
public void WriteAsciiFixed(string value, int size)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Console.WriteLine("Network: Attempted to WriteAsciiFixed() with null value");
|
|
value = String.Empty;
|
|
}
|
|
|
|
int length = value.Length;
|
|
|
|
m_Stream.SetLength(m_Stream.Length + size);
|
|
|
|
if (length >= size)
|
|
{
|
|
m_Stream.Position += Encoding.ASCII.GetBytes(value, 0, size, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
}
|
|
else
|
|
{
|
|
Encoding.ASCII.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
m_Stream.Position += size;
|
|
}
|
|
|
|
/*byte[] buffer = Encoding.ASCII.GetBytes( value );
|
|
|
|
if ( buffer.Length >= size )
|
|
{
|
|
m_Stream.Write( buffer, 0, size );
|
|
}
|
|
else
|
|
{
|
|
m_Stream.Write( buffer, 0, buffer.Length );
|
|
Fill( size - buffer.Length );
|
|
}*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character.
|
|
/// </summary>
|
|
public void WriteAsciiNull(string value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Console.WriteLine("Network: Attempted to WriteAsciiNull() with null value");
|
|
value = String.Empty;
|
|
}
|
|
|
|
int length = value.Length;
|
|
|
|
m_Stream.SetLength(m_Stream.Length + length + 1);
|
|
|
|
Encoding.ASCII.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
m_Stream.Position += length + 1;
|
|
|
|
/*byte[] buffer = Encoding.ASCII.GetBytes( value );
|
|
|
|
m_Stream.Write( buffer, 0, buffer.Length );
|
|
m_Stream.WriteByte( 0 );*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
|
/// </summary>
|
|
public void WriteLittleUniNull(string value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Console.WriteLine("Network: Attempted to WriteLittleUniNull() with null value");
|
|
value = String.Empty;
|
|
}
|
|
|
|
int length = value.Length;
|
|
|
|
m_Stream.SetLength(m_Stream.Length + ((length + 1) * 2));
|
|
|
|
m_Stream.Position += Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
m_Stream.Position += 2;
|
|
|
|
/*byte[] buffer = Encoding.Unicode.GetBytes( value );
|
|
|
|
m_Stream.Write( buffer, 0, buffer.Length );
|
|
|
|
m_Buffer[0] = 0;
|
|
m_Buffer[1] = 0;
|
|
m_Stream.Write( m_Buffer, 0, 2 );*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
|
/// </summary>
|
|
public void WriteLittleUniFixed(string value, int size)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Console.WriteLine("Network: Attempted to WriteLittleUniFixed() with null value");
|
|
value = String.Empty;
|
|
}
|
|
|
|
size *= 2;
|
|
|
|
int length = value.Length;
|
|
|
|
m_Stream.SetLength(m_Stream.Length + size);
|
|
|
|
if ((length * 2) >= size)
|
|
{
|
|
m_Stream.Position += Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
}
|
|
else
|
|
{
|
|
Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
m_Stream.Position += size;
|
|
}
|
|
|
|
/*size *= 2;
|
|
|
|
byte[] buffer = Encoding.Unicode.GetBytes( value );
|
|
|
|
if ( buffer.Length >= size )
|
|
{
|
|
m_Stream.Write( buffer, 0, size );
|
|
}
|
|
else
|
|
{
|
|
m_Stream.Write( buffer, 0, buffer.Length );
|
|
Fill( size - buffer.Length );
|
|
}*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
|
/// </summary>
|
|
public void WriteBigUniNull(string value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Console.WriteLine("Network: Attempted to WriteBigUniNull() with null value");
|
|
value = String.Empty;
|
|
}
|
|
|
|
int length = value.Length;
|
|
|
|
m_Stream.SetLength(m_Stream.Length + ((length + 1) * 2));
|
|
|
|
m_Stream.Position += Encoding.BigEndianUnicode.GetBytes(
|
|
value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
m_Stream.Position += 2;
|
|
|
|
/*byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
|
|
|
m_Stream.Write( buffer, 0, buffer.Length );
|
|
|
|
m_Buffer[0] = 0;
|
|
m_Buffer[1] = 0;
|
|
m_Stream.Write( m_Buffer, 0, 2 );*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
|
/// </summary>
|
|
public void WriteBigUniFixed(string value, int size)
|
|
{
|
|
if (value == null)
|
|
{
|
|
Console.WriteLine("Network: Attempted to WriteBigUniFixed() with null value");
|
|
value = String.Empty;
|
|
}
|
|
|
|
size *= 2;
|
|
|
|
int length = value.Length;
|
|
|
|
m_Stream.SetLength(m_Stream.Length + size);
|
|
|
|
if ((length * 2) >= size)
|
|
{
|
|
m_Stream.Position += Encoding.BigEndianUnicode.GetBytes(
|
|
value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
}
|
|
else
|
|
{
|
|
Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
|
m_Stream.Position += size;
|
|
}
|
|
|
|
/*size *= 2;
|
|
|
|
byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
|
|
|
if ( buffer.Length >= size )
|
|
{
|
|
m_Stream.Write( buffer, 0, size );
|
|
}
|
|
else
|
|
{
|
|
m_Stream.Write( buffer, 0, buffer.Length );
|
|
Fill( size - buffer.Length );
|
|
}*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fills the stream from the current position up to (capacity) with 0x00's
|
|
/// </summary>
|
|
public void Fill()
|
|
{
|
|
Fill((int)(m_Capacity - m_Stream.Length));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a number of 0x00 byte values to the underlying stream.
|
|
/// </summary>
|
|
public void Fill(int length)
|
|
{
|
|
if (m_Stream.Position == m_Stream.Length)
|
|
{
|
|
m_Stream.SetLength(m_Stream.Length + length);
|
|
m_Stream.Seek(0, SeekOrigin.End);
|
|
}
|
|
else
|
|
{
|
|
m_Stream.Write(new byte[length], 0, length);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the total stream length.
|
|
/// </summary>
|
|
public long Length { get { return m_Stream.Length; } }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the current stream position.
|
|
/// </summary>
|
|
public long Position { get { return m_Stream.Position; } set { m_Stream.Position = value; } }
|
|
|
|
/// <summary>
|
|
/// The internal stream used by this PacketWriter instance.
|
|
/// </summary>
|
|
public MemoryStream UnderlyingStream { get { return m_Stream; } }
|
|
|
|
/// <summary>
|
|
/// Offsets the current position from an origin.
|
|
/// </summary>
|
|
public long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
return m_Stream.Seek(offset, origin);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the entire stream content as a byte array.
|
|
/// </summary>
|
|
public byte[] ToArray()
|
|
{
|
|
return m_Stream.ToArray();
|
|
}
|
|
}
|
|
} |