This reverts commit 179cb50557.
This commit is contained in:
parent
179cb50557
commit
c2ecc76457
588 changed files with 16260 additions and 10926 deletions
|
|
@ -76,7 +76,7 @@ namespace Server.Network
|
|||
|
||||
DisplayListener();
|
||||
|
||||
while (!Core.Closing)
|
||||
while (true)
|
||||
{
|
||||
Socket s;
|
||||
try
|
||||
|
|
@ -90,7 +90,7 @@ namespace Server.Network
|
|||
}
|
||||
|
||||
if (VerifySocket(s))
|
||||
new NetState(s, pump);
|
||||
_ = new NetState(s, pump);
|
||||
else
|
||||
Release(s);
|
||||
}
|
||||
|
|
@ -105,9 +105,12 @@ namespace Server.Network
|
|||
{
|
||||
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface adapter in adapters)
|
||||
foreach (UnicastIPAddressInformation unicast in adapter.GetIPProperties().UnicastAddresses)
|
||||
if (ipep.AddressFamily == unicast.Address.AddressFamily)
|
||||
Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port);
|
||||
{
|
||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||
foreach (UnicastIPAddressInformation unicast in properties.UnicastAddresses)
|
||||
if (ipep.AddressFamily == unicast.Address.AddressFamily)
|
||||
Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,13 +26,14 @@ using System.IO;
|
|||
using System.IO.Pipelines;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Accounting;
|
||||
using Server.Diagnostics;
|
||||
using Server.Gumps;
|
||||
using Server.HuePickers;
|
||||
using Server.Items;
|
||||
using Server.Menus;
|
||||
using NetworkPackets = Server.Network.Packets;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
|
|
@ -92,6 +93,7 @@ namespace Server.Network
|
|||
{
|
||||
private string m_ToString;
|
||||
private ClientVersion m_Version;
|
||||
private SendQueue<Packet> m_SendQueue = new SendQueue<Packet>();
|
||||
|
||||
public DateTime ConnectedOn { get; }
|
||||
|
||||
|
|
@ -109,8 +111,6 @@ namespace Server.Network
|
|||
|
||||
private static AsyncState m_AsyncState = m_ResumeState;
|
||||
|
||||
public bool UseCompression { get; set; }
|
||||
|
||||
public IPacketEncoder PacketEncoder { get; set; }
|
||||
|
||||
public static NetStateCreatedCallback CreatedCallback { get; set; }
|
||||
|
|
@ -158,8 +158,7 @@ namespace Server.Network
|
|||
ProtocolChanges = ProtocolChanges.Version500a;
|
||||
else if (value >= m_Version407a)
|
||||
ProtocolChanges = ProtocolChanges.Version407a;
|
||||
else if (value >= m_Version400a)
|
||||
ProtocolChanges = ProtocolChanges.Version400a;
|
||||
else if (value >= m_Version400a) ProtocolChanges = ProtocolChanges.Version400a;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +272,9 @@ namespace Server.Network
|
|||
|
||||
public Socket Socket { get; private set; }
|
||||
|
||||
public byte Sequence { get; set; }
|
||||
public bool CompressionEnabled { get; set; }
|
||||
|
||||
public int Sequence { get; set; }
|
||||
|
||||
public List<Gump> Gumps { get; private set; }
|
||||
|
||||
|
|
@ -299,7 +300,8 @@ namespace Server.Network
|
|||
|
||||
public void AddMenu(IMenu menu)
|
||||
{
|
||||
Menus ??= new List<IMenu>();
|
||||
if (Menus == null)
|
||||
Menus = new List<IMenu>();
|
||||
|
||||
if (Menus.Count < MenuCap)
|
||||
Menus.Add(menu);
|
||||
|
|
@ -327,7 +329,8 @@ namespace Server.Network
|
|||
|
||||
public void AddHuePicker(HuePicker huePicker)
|
||||
{
|
||||
HuePickers ??= new List<HuePicker>();
|
||||
if (HuePickers == null)
|
||||
HuePickers = new List<HuePicker>();
|
||||
|
||||
if (HuePickers.Count < HuePickerCap)
|
||||
HuePickers.Add(huePicker);
|
||||
|
|
@ -355,7 +358,8 @@ namespace Server.Network
|
|||
|
||||
public void AddGump(Gump gump)
|
||||
{
|
||||
Gumps ??= new List<Gump>();
|
||||
if (Gumps == null)
|
||||
Gumps = new List<Gump>();
|
||||
|
||||
if (Gumps.Count < GumpCap)
|
||||
Gumps.Add(gump);
|
||||
|
|
@ -383,8 +387,8 @@ namespace Server.Network
|
|||
|
||||
public void LaunchBrowser(string url)
|
||||
{
|
||||
NetworkPackets.SendMessageLocalized(this, Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231);
|
||||
NetworkPackets.SendLaunchBrowser(this, url);
|
||||
Send(new MessageLocalized(Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", ""));
|
||||
Send(new LaunchBrowser(url));
|
||||
}
|
||||
|
||||
public CityInfo[] CityInfo { get; set; }
|
||||
|
|
@ -442,6 +446,17 @@ namespace Server.Network
|
|||
m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_ResumeState);
|
||||
}
|
||||
|
||||
public virtual void Send(Packet p)
|
||||
{
|
||||
if (Socket == null || BlockAllPackets)
|
||||
{
|
||||
p.OnSend();
|
||||
return;
|
||||
}
|
||||
|
||||
m_SendQueue.Enqueue(p);
|
||||
}
|
||||
|
||||
public bool CheckEncrypted(int packetID)
|
||||
{
|
||||
if (!SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 &&
|
||||
|
|
@ -455,35 +470,32 @@ namespace Server.Network
|
|||
return false;
|
||||
}
|
||||
|
||||
public Pipe RecvdPipe { get; private set; }
|
||||
public Pipe SendPipe { get; private set; }
|
||||
private Pipe m_RecvdPipe;
|
||||
|
||||
private async Task Start(MessagePump pump)
|
||||
{
|
||||
RecvdPipe = new Pipe();
|
||||
SendPipe = new Pipe();
|
||||
m_RecvdPipe = new Pipe();
|
||||
Running = true;
|
||||
|
||||
await Task.WhenAll(HandlePackets(pump), ProcessSends(), ProcessRecvs());
|
||||
await Task.WhenAll(ProcessSends(), ProcessRecvs(), HandlePackets(pump)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ProcessRecvs()
|
||||
{
|
||||
PipeWriter w = RecvdPipe.Writer;
|
||||
PipeWriter w = m_RecvdPipe.Writer;
|
||||
|
||||
while (!Core.Closing)
|
||||
while (true)
|
||||
{
|
||||
if (m_AsyncState.Paused)
|
||||
{
|
||||
Interlocked.Exchange(ref m_NextCheckActivity, Core.TickCount + 90000);
|
||||
await Timer.Pause(50);
|
||||
await Timer.Pause(50).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Memory<byte> memory = w.GetMemory();
|
||||
int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None);
|
||||
int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false);
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
|
||||
|
|
@ -491,7 +503,7 @@ namespace Server.Network
|
|||
|
||||
w.Advance(bytesRead);
|
||||
|
||||
FlushResult result = await w.FlushAsync();
|
||||
FlushResult result = await w.FlushAsync().ConfigureAwait(false);
|
||||
if (result.IsCompleted || result.IsCanceled)
|
||||
break;
|
||||
}
|
||||
|
|
@ -505,7 +517,7 @@ namespace Server.Network
|
|||
Dispose();
|
||||
}
|
||||
|
||||
private async Task HandlePackets(MessagePump pump)
|
||||
private async Task ProcessSends()
|
||||
{
|
||||
while (true)
|
||||
try
|
||||
|
|
@ -514,31 +526,26 @@ namespace Server.Network
|
|||
if (p == null)
|
||||
break;
|
||||
|
||||
long pos = PacketHandlers.ProcessPacket(pump, this, seq);
|
||||
ReadOnlyMemory<byte> buffer = p.Compile(CompressionEnabled, out int length);
|
||||
|
||||
if (pos <= 0)
|
||||
break;
|
||||
if (buffer.Length <= 0 || length <= 0)
|
||||
{
|
||||
p.OnSend();
|
||||
return;
|
||||
}
|
||||
|
||||
pr.AdvanceTo(seq.GetPosition(pos, seq.Start));
|
||||
buffer = buffer.Slice(0, length);
|
||||
|
||||
if (result.IsCompleted || result.IsCanceled)
|
||||
break;
|
||||
}
|
||||
PacketSendProfile prof = null;
|
||||
|
||||
pr.Complete();
|
||||
}
|
||||
if (Core.Profiling)
|
||||
prof = PacketSendProfile.Acquire(p.GetType());
|
||||
|
||||
public async Task Flush(int bytesWritten)
|
||||
{
|
||||
if (IsDisposing || BlockAllPackets)
|
||||
return;
|
||||
prof?.Start();
|
||||
|
||||
SendPipe.Writer.Advance(bytesWritten);
|
||||
FlushResult result = await SendPipe.Writer.FlushAsync();
|
||||
await Socket.SendAsync(buffer, SocketFlags.None).ConfigureAwait(false);
|
||||
|
||||
if (result.IsCompleted || result.IsCanceled)
|
||||
Dispose();
|
||||
}
|
||||
p.OnSend();
|
||||
|
||||
prof?.Finish(length);
|
||||
}
|
||||
|
|
@ -555,44 +562,29 @@ namespace Server.Network
|
|||
}
|
||||
}
|
||||
|
||||
private async Task ProcessSends()
|
||||
private async Task HandlePackets(MessagePump pump)
|
||||
{
|
||||
PipeReader pr = SendPipe.Reader;
|
||||
PipeReader pr = m_RecvdPipe.Reader;
|
||||
|
||||
while (!Core.Closing)
|
||||
while (true)
|
||||
{
|
||||
if (m_AsyncState.Paused)
|
||||
{
|
||||
await Timer.Pause(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadResult result = await pr.ReadAsync();
|
||||
ReadOnlySequence<byte> seq = result.Buffer;
|
||||
if (seq.Length == 0)
|
||||
break;
|
||||
|
||||
if (!SequenceMarshal.TryGetReadOnlyMemory(seq, out ReadOnlyMemory<byte> memory))
|
||||
long pos = PacketHandlers.ProcessPacket(pump, this, seq);
|
||||
|
||||
if (pos <= 0)
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
int bytesWritten = await Socket.SendAsync(memory, SocketFlags.None);
|
||||
|
||||
pr.AdvanceTo(seq.GetPosition(bytesWritten));
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
TraceException(ex);
|
||||
break;
|
||||
}
|
||||
pr.AdvanceTo(seq.GetPosition(pos, seq.Start));
|
||||
|
||||
if (result.IsCompleted || result.IsCanceled)
|
||||
break;
|
||||
}
|
||||
|
||||
Dispose();
|
||||
pr.Complete();
|
||||
}
|
||||
|
||||
public PacketHandler GetHandler(int packetID) =>
|
||||
|
|
@ -647,17 +639,17 @@ namespace Server.Network
|
|||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
RecvdPipe.Reader.CancelPendingRead();
|
||||
RecvdPipe.Reader.Complete();
|
||||
await SendPipe.Writer.FlushAsync();
|
||||
SendPipe.Writer.Complete();
|
||||
m_RecvdPipe.Reader.CancelPendingRead();
|
||||
m_RecvdPipe.Reader.Complete();
|
||||
await m_RecvdPipe.Writer.FlushAsync().ConfigureAwait(false);
|
||||
m_RecvdPipe.Writer.Complete();
|
||||
|
||||
try { Socket.Shutdown(SocketShutdown.Both); } catch (Exception ex) { TraceException(ex); }
|
||||
try { Socket.Close(); } catch (Exception ex) { TraceException(ex); }
|
||||
|
||||
Socket = null;
|
||||
RecvdPipe = null;
|
||||
SendPipe = null;
|
||||
m_RecvdPipe = null;
|
||||
m_SendQueue = null;
|
||||
m_Disposed.Enqueue(this);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
267
Projects/Server/Network/Packet.cs
Normal file
267
Projects/Server/Network/Packet.cs
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/***************************************************************************
|
||||
* Packet.cs
|
||||
* -------------------
|
||||
* begin : August 2, 2019
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using Server.Diagnostics;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public abstract class Packet
|
||||
{
|
||||
private const int CompressorBufferSize = 0x10000;
|
||||
|
||||
private const int BufferSize = 4096;
|
||||
|
||||
private byte[] m_CompiledBuffer;
|
||||
private int m_CompiledLength;
|
||||
private int m_Length;
|
||||
private State m_State;
|
||||
|
||||
protected PacketWriter m_Stream;
|
||||
|
||||
protected Packet(int packetID)
|
||||
{
|
||||
PacketID = packetID;
|
||||
|
||||
if (Core.Profiling)
|
||||
{
|
||||
PacketSendProfile prof = PacketSendProfile.Acquire(GetType());
|
||||
prof.Increment();
|
||||
}
|
||||
}
|
||||
|
||||
protected Packet(int packetID, int length)
|
||||
{
|
||||
PacketID = packetID;
|
||||
m_Length = length;
|
||||
|
||||
m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length );
|
||||
m_Stream.Write((byte)packetID);
|
||||
|
||||
if (Core.Profiling)
|
||||
{
|
||||
PacketSendProfile prof = PacketSendProfile.Acquire(GetType());
|
||||
prof.Increment();
|
||||
}
|
||||
}
|
||||
|
||||
public int PacketID { get; }
|
||||
|
||||
public PacketWriter UnderlyingStream => m_Stream;
|
||||
|
||||
public void EnsureCapacity(int length)
|
||||
{
|
||||
m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length );
|
||||
m_Stream.Write((byte)PacketID);
|
||||
m_Stream.Write((short)0);
|
||||
}
|
||||
|
||||
public static Packet SetStatic(Packet p)
|
||||
{
|
||||
p.SetStatic();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Packet Acquire(Packet p)
|
||||
{
|
||||
p.Acquire();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static void Release(ref Packet p)
|
||||
{
|
||||
p?.Release();
|
||||
p = null;
|
||||
}
|
||||
|
||||
public static void Release(Packet p)
|
||||
{
|
||||
p?.Release();
|
||||
}
|
||||
|
||||
public void SetStatic()
|
||||
{
|
||||
m_State |= State.Static | State.Acquired;
|
||||
}
|
||||
|
||||
public void Acquire()
|
||||
{
|
||||
m_State |= State.Acquired;
|
||||
}
|
||||
|
||||
public void OnSend()
|
||||
{
|
||||
Core.Set(); // Is this still needed if this is done async?
|
||||
|
||||
if ((m_State & (State.Acquired | State.Static)) == 0)
|
||||
Free();
|
||||
}
|
||||
|
||||
private void Free()
|
||||
{
|
||||
if (m_CompiledBuffer == null)
|
||||
return;
|
||||
|
||||
if ((m_State & State.Buffered) != 0)
|
||||
ArrayPool<byte>.Shared.Return(m_CompiledBuffer);
|
||||
|
||||
m_State &= ~(State.Static | State.Acquired | State.Buffered);
|
||||
|
||||
m_CompiledBuffer = null;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
if ((m_State & State.Acquired) != 0)
|
||||
Free();
|
||||
}
|
||||
|
||||
public byte[] Compile(bool compress, out int length)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (m_CompiledBuffer == null)
|
||||
{
|
||||
if ((m_State & State.Accessed) == 0)
|
||||
{
|
||||
m_State |= State.Accessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_State & State.Warned) == 0)
|
||||
{
|
||||
m_State |= State.Warned;
|
||||
|
||||
try
|
||||
{
|
||||
using StreamWriter op = new StreamWriter("net_opt.log", true);
|
||||
op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", GetType());
|
||||
op.WriteLine(new StackTrace());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
m_CompiledBuffer = new byte[0];
|
||||
m_CompiledLength = 0;
|
||||
|
||||
length = m_CompiledLength;
|
||||
return m_CompiledBuffer;
|
||||
}
|
||||
|
||||
InternalCompile(compress);
|
||||
}
|
||||
|
||||
length = m_CompiledLength;
|
||||
return m_CompiledBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalCompile(bool compress)
|
||||
{
|
||||
if (m_Length == 0)
|
||||
{
|
||||
long streamLen = m_Stream.Length;
|
||||
|
||||
m_Stream.Seek(1, SeekOrigin.Begin);
|
||||
m_Stream.Write((ushort)streamLen);
|
||||
}
|
||||
else if (m_Stream.Length != m_Length)
|
||||
{
|
||||
int diff = (int)m_Stream.Length - m_Length;
|
||||
|
||||
Console.WriteLine("Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)", PacketID, diff >= 0 ? "+" : "",
|
||||
diff);
|
||||
}
|
||||
|
||||
MemoryStream ms = m_Stream.UnderlyingStream;
|
||||
|
||||
m_CompiledBuffer = ms.GetBuffer();
|
||||
int length = (int)ms.Length;
|
||||
|
||||
if (compress)
|
||||
{
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(CompressorBufferSize);
|
||||
|
||||
Compression.Compress(m_CompiledBuffer, 0, length, buffer, out length);
|
||||
|
||||
if (length <= 0)
|
||||
{
|
||||
Console.WriteLine("Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})",
|
||||
PacketID, GetType().Name, length);
|
||||
using StreamWriter op = new StreamWriter("compression_overflow.log", true);
|
||||
op.WriteLine("{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})",
|
||||
DateTime.UtcNow, PacketID, GetType().Name, length);
|
||||
op.WriteLine(new StackTrace());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CompiledLength = length;
|
||||
|
||||
if ((m_State & State.Static) != 0)
|
||||
{
|
||||
m_CompiledBuffer = new byte[length];
|
||||
Buffer.BlockCopy(buffer, 0, m_CompiledBuffer, 0, length);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CompiledBuffer = buffer;
|
||||
m_State |= State.Buffered;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (length > 0)
|
||||
{
|
||||
byte[] old = m_CompiledBuffer;
|
||||
m_CompiledLength = length;
|
||||
|
||||
if ((m_State & State.Static) != 0)
|
||||
m_CompiledBuffer = new byte[length];
|
||||
else
|
||||
{
|
||||
m_CompiledBuffer = ArrayPool<byte>.Shared.Rent(length);
|
||||
m_State |= State.Buffered;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length);
|
||||
}
|
||||
|
||||
PacketWriter.ReleaseInstance(m_Stream);
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum State
|
||||
{
|
||||
Inactive = 0x00,
|
||||
Static = 0x01,
|
||||
Acquired = 0x02,
|
||||
Accessed = 0x04,
|
||||
Buffered = 0x08,
|
||||
Warned = 0x10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ using Server.Accounting;
|
|||
using Server.ContextMenus;
|
||||
using Server.Diagnostics;
|
||||
using Server.Gumps;
|
||||
using Server.HuePickers;
|
||||
using Server.Items;
|
||||
using Server.Menus;
|
||||
using Server.Prompts;
|
||||
|
|
@ -55,6 +56,11 @@ namespace Server.Network
|
|||
|
||||
public static class PacketHandlers
|
||||
{
|
||||
public delegate void PlayCharCallback(NetState state, bool val);
|
||||
|
||||
private const int BadFood = unchecked((int)0xBAADF00D);
|
||||
private const int BadUOTD = unchecked((int)0xFFCEFFCE);
|
||||
|
||||
private const int m_AuthIDWindowSize = 128;
|
||||
private static PacketHandler[] m_6017Handlers;
|
||||
|
||||
|
|
@ -103,32 +109,43 @@ namespace Server.Network
|
|||
Register(0x01, 5, false, Disconnect);
|
||||
Register(0x02, 7, true, MovementReq);
|
||||
Register(0x03, 0, true, AsciiSpeech);
|
||||
Register(0x04, 2, true, GodModeRequest);
|
||||
Register(0x05, 5, true, AttackReq);
|
||||
Register(0x06, 5, true, UseReq);
|
||||
Register(0x07, 7, true, LiftReq);
|
||||
Register(0x08, 14, true, DropReq);
|
||||
Register(0x09, 5, true, LookReq);
|
||||
Register(0x0A, 11, true, Edit);
|
||||
Register(0x12, 0, true, TextCommand);
|
||||
Register(0x13, 10, true, EquipReq);
|
||||
Register(0x14, 6, true, ChangeZ);
|
||||
Register(0x22, 3, true, Resynchronize);
|
||||
Register(0x2C, 2, true, DeathStatusResponse);
|
||||
Register(0x34, 10, true, MobileQuery);
|
||||
Register(0x3A, 0, true, ChangeSkillLock);
|
||||
Register(0x3B, 0, true, VendorBuyReply);
|
||||
Register(0x47, 11, true, NewTerrain);
|
||||
Register(0x48, 73, true, NewAnimData);
|
||||
Register(0x58, 106, true, NewRegion);
|
||||
Register(0x5D, 73, false, PlayCharacter);
|
||||
Register(0x61, 9, true, DeleteStatic);
|
||||
Register(0x6C, 19, true, TargetResponse);
|
||||
Register(0x6F, 0, true, SecureTrade);
|
||||
Register(0x72, 5, true, SetWarMode);
|
||||
Register(0x73, 2, false, PingReq);
|
||||
Register(0x75, 35, true, RenameRequest);
|
||||
Register(0x79, 9, true, ResourceQuery);
|
||||
Register(0x7E, 2, true, GodviewQuery);
|
||||
Register(0x7D, 13, true, MenuResponse);
|
||||
Register(0x80, 62, false, AccountLogin);
|
||||
Register(0x83, 39, false, DeleteCharacter);
|
||||
Register(0x91, 65, false, GameLogin);
|
||||
Register(0x95, 9, true, HuePickerResponse);
|
||||
Register(0x96, 0, true, GameCentralMoniter);
|
||||
Register(0x98, 0, true, MobileNameRequest);
|
||||
Register(0x9A, 0, true, AsciiPromptResponse);
|
||||
Register(0x9B, 258, true, HelpRequest);
|
||||
Register(0x9D, 51, true, GMSingle);
|
||||
Register(0x9F, 0, true, VendorSellReply);
|
||||
Register(0xA0, 3, false, PlayServer);
|
||||
Register(0xA4, 149, false, SystemInfo);
|
||||
|
|
@ -144,6 +161,8 @@ namespace Server.Network
|
|||
Register(0xBF, 0, true, ExtendedCommand);
|
||||
Register(0xC2, 0, true, UnicodePromptResponse);
|
||||
Register(0xC8, 2, true, SetUpdateRange);
|
||||
Register(0xC9, 6, true, TripTime);
|
||||
Register(0xCA, 6, true, UTripTime);
|
||||
Register(0xCF, 0, false, AccountLogin);
|
||||
Register(0xD0, 0, true, ConfigurationFile);
|
||||
Register(0xD1, 2, true, LogoutReq);
|
||||
|
|
@ -195,7 +214,9 @@ namespace Server.Network
|
|||
public static void Register(int packetID, int length, bool ingame, OnPacketReceive onReceive)
|
||||
{
|
||||
Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive);
|
||||
m_6017Handlers[packetID] ??= new PacketHandler(packetID, length, ingame, onReceive);
|
||||
|
||||
if (m_6017Handlers[packetID] == null)
|
||||
m_6017Handlers[packetID] = new PacketHandler(packetID, length, ingame, onReceive);
|
||||
}
|
||||
|
||||
public static PacketHandler GetHandler(int packetID) => Handlers[packetID];
|
||||
|
|
@ -321,8 +342,6 @@ namespace Server.Network
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Console.WriteLine("Packet Handler {0:X}", handler.PacketID);
|
||||
|
||||
long packetLength = handler.Length;
|
||||
if (handler.Length <= 0 && r.Length >= 3)
|
||||
{
|
||||
|
|
@ -394,9 +413,9 @@ namespace Server.Network
|
|||
public static void EncodedCommand(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
IEntity e = World.FindEntity(pvSrc.ReadUInt32());
|
||||
int packetId = pvSrc.ReadUInt16();
|
||||
int packetID = pvSrc.ReadUInt16();
|
||||
|
||||
EncodedPacketHandler ph = GetEncodedHandler(packetId);
|
||||
EncodedPacketHandler ph = GetEncodedHandler(packetID);
|
||||
|
||||
if (ph != null)
|
||||
{
|
||||
|
|
@ -404,7 +423,7 @@ namespace Server.Network
|
|||
{
|
||||
Console.WriteLine(
|
||||
"Client: {0}: Sent ingame packet (0xD7x{1:X2}) before having been attached to a mobile", state,
|
||||
packetId);
|
||||
packetID);
|
||||
state.Dispose();
|
||||
}
|
||||
else if (ph.Ingame && state.Mobile.Deleted)
|
||||
|
|
@ -517,30 +536,37 @@ namespace Server.Network
|
|||
if (vendor == null)
|
||||
return;
|
||||
|
||||
if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10) || flag != 0x02)
|
||||
if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10))
|
||||
{
|
||||
Packets.SendEndVendorBuyOrSell(state, vendor.Serial);
|
||||
state.Send(new EndVendorBuy(vendor));
|
||||
return;
|
||||
}
|
||||
|
||||
msgSize -= 1 + 2 + 4 + 1;
|
||||
|
||||
if (msgSize / 7 > 100)
|
||||
return;
|
||||
|
||||
List<BuyItemResponse> buyList = new List<BuyItemResponse>(msgSize / 7);
|
||||
while (msgSize > 0)
|
||||
if (flag == 0x02)
|
||||
{
|
||||
pvSrc.ReadByte(); // layer
|
||||
Serial serial = pvSrc.ReadUInt32();
|
||||
int amount = pvSrc.ReadInt16();
|
||||
msgSize -= 1 + 2 + 4 + 1;
|
||||
|
||||
buyList.Add(new BuyItemResponse(serial, amount));
|
||||
msgSize -= 7;
|
||||
if (msgSize / 7 > 100)
|
||||
return;
|
||||
|
||||
List<BuyItemResponse> buyList = new List<BuyItemResponse>(msgSize / 7);
|
||||
while (msgSize > 0)
|
||||
{
|
||||
byte layer = pvSrc.ReadByte();
|
||||
Serial serial = pvSrc.ReadUInt32();
|
||||
int amount = pvSrc.ReadInt16();
|
||||
|
||||
buyList.Add(new BuyItemResponse(serial, amount));
|
||||
msgSize -= 7;
|
||||
}
|
||||
|
||||
if (buyList.Count > 0 && vendor is IVendor v && v.OnBuyItems(state.Mobile, buyList))
|
||||
state.Send(new EndVendorBuy(vendor));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Send(new EndVendorBuy(vendor));
|
||||
}
|
||||
|
||||
if (buyList.Count > 0 && vendor is IVendor v && v.OnBuyItems(state.Mobile, buyList))
|
||||
Packets.SendEndVendorBuyOrSell(state, vendor.Serial);
|
||||
}
|
||||
|
||||
public static void VendorSellReply(NetState state, PacketReader pvSrc)
|
||||
|
|
@ -552,7 +578,7 @@ namespace Server.Network
|
|||
|
||||
if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10))
|
||||
{
|
||||
Packets.SendEndVendorBuyOrSell(state, vendor.Serial);
|
||||
state.Send(new EndVendorSell(vendor));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -564,14 +590,14 @@ namespace Server.Network
|
|||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Item item = World.FindItem(pvSrc.ReadUInt32());
|
||||
int amount = pvSrc.ReadInt16();
|
||||
int Amount = pvSrc.ReadInt16();
|
||||
|
||||
if (item != null && amount > 0)
|
||||
sellList.Add(new SellItemResponse(item, amount));
|
||||
if (item != null && Amount > 0)
|
||||
sellList.Add(new SellItemResponse(item, Amount));
|
||||
}
|
||||
|
||||
if (sellList.Count > 0 && vendor is IVendor v && v.OnSellItems(state.Mobile, sellList))
|
||||
Packets.SendEndVendorBuyOrSell(state, vendor.Serial);
|
||||
state.Send(new EndVendorSell(vendor));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -583,6 +609,39 @@ namespace Server.Network
|
|||
EventSink.InvokeDeleteRequest(new DeleteRequestEventArgs(state, index));
|
||||
}
|
||||
|
||||
public static void ResourceQuery(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static void GameCentralMoniter(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
int type = pvSrc.ReadByte();
|
||||
int num1 = pvSrc.ReadInt32();
|
||||
|
||||
Console.WriteLine("God Client: {0}: Game central moniter", state);
|
||||
Console.WriteLine(" - Type: {0}", type);
|
||||
Console.WriteLine(" - Number: {0}", num1);
|
||||
|
||||
pvSrc.Trace(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static void GodviewQuery(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state)) Console.WriteLine("God Client: {0}: Godview query 0x{1:X}", state, pvSrc.ReadByte());
|
||||
}
|
||||
|
||||
public static void GMSingle(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
pvSrc.Trace(state);
|
||||
}
|
||||
|
||||
public static void DeathStatusResponse(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
// Ignored
|
||||
|
|
@ -618,7 +677,7 @@ namespace Server.Network
|
|||
Mobile m = World.FindMobile(pvSrc.ReadUInt32());
|
||||
|
||||
if (m != null && Utility.InUpdateRange(state.Mobile, m) && state.Mobile.CanSee(m))
|
||||
Packets.SendMobileName(state, m);
|
||||
state.Send(new MobileName(m));
|
||||
}
|
||||
|
||||
public static void RequestScrollWindow(NetState state, PacketReader pvSrc)
|
||||
|
|
@ -655,6 +714,34 @@ namespace Server.Network
|
|||
}
|
||||
}
|
||||
|
||||
public static void TripTime(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
int unk1 = pvSrc.ReadByte();
|
||||
int unk2 = pvSrc.ReadInt32();
|
||||
|
||||
state.Send(new TripTimeResponse(unk1));
|
||||
}
|
||||
|
||||
public static void UTripTime(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
int unk1 = pvSrc.ReadByte();
|
||||
int unk2 = pvSrc.ReadInt32();
|
||||
|
||||
state.Send(new UTripTimeResponse(unk1));
|
||||
}
|
||||
|
||||
public static void ChangeZ(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
int x = pvSrc.ReadInt16();
|
||||
int y = pvSrc.ReadInt16();
|
||||
int z = pvSrc.ReadSByte();
|
||||
|
||||
Console.WriteLine("God Client: {0}: Change Z ({1}, {2}, {3})", state, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SystemInfo(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
int v1 = pvSrc.ReadByte();
|
||||
|
|
@ -671,6 +758,83 @@ namespace Server.Network
|
|||
int v8 = pvSrc.ReadInt32();
|
||||
}
|
||||
|
||||
public static void Edit(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
int type = pvSrc.ReadByte(); // 10 = static, 7 = npc, 4 = dynamic
|
||||
int x = pvSrc.ReadInt16();
|
||||
int y = pvSrc.ReadInt16();
|
||||
int id = pvSrc.ReadInt16();
|
||||
int z = pvSrc.ReadSByte();
|
||||
int hue = pvSrc.ReadUInt16();
|
||||
|
||||
Console.WriteLine("God Client: {0}: Edit {6} ({1}, {2}, {3}) 0x{4:X} (0x{5:X})", state, x, y, z, id, hue,
|
||||
type);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeleteStatic(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
int x = pvSrc.ReadInt16();
|
||||
int y = pvSrc.ReadInt16();
|
||||
int z = pvSrc.ReadInt16();
|
||||
int id = pvSrc.ReadUInt16();
|
||||
|
||||
Console.WriteLine("God Client: {0}: Delete Static ({1}, {2}, {3}) 0x{4:X}", state, x, y, z, id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void NewAnimData(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
Console.WriteLine("God Client: {0}: New tile animation", state);
|
||||
|
||||
pvSrc.Trace(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static void NewTerrain(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
int x = pvSrc.ReadInt16();
|
||||
int y = pvSrc.ReadInt16();
|
||||
int id = pvSrc.ReadUInt16();
|
||||
int width = pvSrc.ReadInt16();
|
||||
int height = pvSrc.ReadInt16();
|
||||
|
||||
Console.WriteLine("God Client: {0}: New Terrain ({1}, {2})+({3}, {4}) 0x{5:X4}", state, x, y, width, height,
|
||||
id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void NewRegion(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
{
|
||||
string name = pvSrc.ReadString(40);
|
||||
int unk = pvSrc.ReadInt32();
|
||||
int x = pvSrc.ReadInt16();
|
||||
int y = pvSrc.ReadInt16();
|
||||
int width = pvSrc.ReadInt16();
|
||||
int height = pvSrc.ReadInt16();
|
||||
int zStart = pvSrc.ReadInt16();
|
||||
int zEnd = pvSrc.ReadInt16();
|
||||
string desc = pvSrc.ReadString(40);
|
||||
int soundFX = pvSrc.ReadInt16();
|
||||
int music = pvSrc.ReadInt16();
|
||||
int nightFX = pvSrc.ReadInt16();
|
||||
int dungeon = pvSrc.ReadByte();
|
||||
int light = pvSrc.ReadInt16();
|
||||
|
||||
Console.WriteLine("God Client: {0}: New Region '{1}' ('{2}')", state, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AccountID(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
}
|
||||
|
|
@ -806,6 +970,12 @@ namespace Server.Network
|
|||
}
|
||||
}
|
||||
|
||||
public static void GodModeRequest(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
state.Send(new GodModeReply(pvSrc.ReadBoolean()));
|
||||
}
|
||||
|
||||
public static void AsciiPromptResponse(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
uint serial = pvSrc.ReadUInt32();
|
||||
|
|
@ -1030,12 +1200,14 @@ namespace Server.Network
|
|||
|
||||
public static void LogoutReq(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
Packets.SendLogoutAck(state);
|
||||
state.Send(new LogoutAck());
|
||||
}
|
||||
|
||||
public static void ChangeSkillLock(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
state.Mobile.Skills[pvSrc.ReadInt16()]?.SetLockNoRelay((SkillLock)pvSrc.ReadByte());
|
||||
Skill s = state.Mobile.Skills[pvSrc.ReadInt16()];
|
||||
|
||||
s?.SetLockNoRelay((SkillLock)pvSrc.ReadByte());
|
||||
}
|
||||
|
||||
public static void HelpRequest(NetState state, PacketReader pvSrc)
|
||||
|
|
@ -1046,13 +1218,13 @@ namespace Server.Network
|
|||
public static void TargetResponse(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
int type = pvSrc.ReadByte();
|
||||
int targetId = pvSrc.ReadInt32();
|
||||
int targetID = pvSrc.ReadInt32();
|
||||
int flags = pvSrc.ReadByte();
|
||||
Serial serial = pvSrc.ReadUInt32();
|
||||
int x = pvSrc.ReadInt16(), y = pvSrc.ReadInt16(), z = pvSrc.ReadInt16();
|
||||
int graphic = pvSrc.ReadUInt16();
|
||||
|
||||
if (targetId == unchecked((int)0xDEADBEEF))
|
||||
if (targetID == unchecked((int)0xDEADBEEF))
|
||||
return;
|
||||
|
||||
Mobile from = state.Mobile;
|
||||
|
|
@ -1072,7 +1244,7 @@ namespace Server.Network
|
|||
// User pressed escape
|
||||
t.Cancel(from, TargetCancelType.Canceled);
|
||||
}
|
||||
else if (t.TargetID != targetId)
|
||||
else if (t.TargetID != targetID)
|
||||
{
|
||||
// Sanity, prevent fake target
|
||||
}
|
||||
|
|
@ -1095,28 +1267,42 @@ namespace Server.Network
|
|||
t.Cancel(from, TargetCancelType.Canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y, !t.DisallowMultis);
|
||||
|
||||
if (state.HighSeas)
|
||||
else
|
||||
{
|
||||
ItemData id = TileData.ItemTable[graphic & TileData.MaxItemValue];
|
||||
if (id.Surface) z -= id.Height;
|
||||
}
|
||||
StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y, !t.DisallowMultis);
|
||||
|
||||
if (tiles.All(tile => tile.Z != z || tile.ID != graphic))
|
||||
{
|
||||
t.Cancel(from, TargetCancelType.Canceled);
|
||||
return;
|
||||
}
|
||||
bool valid = false;
|
||||
|
||||
toTarget = new StaticTarget(new Point3D(x, y, z), graphic);
|
||||
if (state.HighSeas)
|
||||
{
|
||||
ItemData id = TileData.ItemTable[graphic & TileData.MaxItemValue];
|
||||
if (id.Surface) z -= id.Height;
|
||||
}
|
||||
|
||||
for (int i = 0; !valid && i < tiles.Length; ++i)
|
||||
if (tiles[i].Z == z && tiles[i].ID == graphic)
|
||||
valid = true;
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
t.Cancel(from, TargetCancelType.Canceled);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
toTarget = new StaticTarget(new Point3D(x, y, z), graphic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (serial.IsMobile)
|
||||
{
|
||||
toTarget = World.FindMobile(serial);
|
||||
}
|
||||
else if (serial.IsItem)
|
||||
{
|
||||
toTarget = World.FindItem(serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
t.Cancel(from, TargetCancelType.Canceled);
|
||||
|
|
@ -1252,8 +1438,13 @@ namespace Server.Network
|
|||
{
|
||||
Mobile m = state.Mobile;
|
||||
|
||||
Packets.SendMobileUpdate(state, m);
|
||||
Packets.SendMobileIncoming(state, m, m);
|
||||
if (state.StygianAbyss)
|
||||
state.Send(new MobileUpdate(m));
|
||||
else
|
||||
state.Send(new MobileUpdateOld(m));
|
||||
|
||||
state.Send(MobileIncoming.Create(state, m, m));
|
||||
|
||||
m.SendEverything();
|
||||
|
||||
state.Sequence = 0;
|
||||
|
|
@ -1305,24 +1496,24 @@ namespace Server.Network
|
|||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
int speechId;
|
||||
int speechID;
|
||||
|
||||
if ((i & 1) == 0)
|
||||
{
|
||||
hold <<= 8;
|
||||
hold |= pvSrc.ReadByte();
|
||||
speechId = hold;
|
||||
speechID = hold;
|
||||
hold = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = pvSrc.ReadInt16();
|
||||
speechId = (value & 0xFFF0) >> 4;
|
||||
speechID = (value & 0xFFF0) >> 4;
|
||||
hold = value & 0xF;
|
||||
}
|
||||
|
||||
if (!keyList.Contains(speechId))
|
||||
keyList.Add(speechId);
|
||||
if (!keyList.Contains(speechID))
|
||||
keyList.Add(speechID);
|
||||
}
|
||||
|
||||
text = pvSrc.ReadUTF8StringSafe();
|
||||
|
|
@ -1359,7 +1550,9 @@ namespace Server.Network
|
|||
uint value = pvSrc.ReadUInt32();
|
||||
|
||||
if ((value & ~0x7FFFFFFF) != 0)
|
||||
{
|
||||
from.OnPaperdollRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial s = value;
|
||||
|
|
@ -1383,7 +1576,9 @@ namespace Server.Network
|
|||
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendActionMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public static void LookReq(NetState state, PacketReader pvSrc)
|
||||
|
|
@ -1399,7 +1594,9 @@ namespace Server.Network
|
|||
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m))
|
||||
{
|
||||
if (SingleClickProps)
|
||||
{
|
||||
m.OnAosSingleClick(from);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.Region.OnSingleClick(from, m))
|
||||
|
|
@ -1415,7 +1612,9 @@ namespace Server.Network
|
|||
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
|
||||
{
|
||||
if (SingleClickProps)
|
||||
{
|
||||
item.OnAosSingleClick(from);
|
||||
}
|
||||
else if (from.Region.OnSingleClick(from, item))
|
||||
{
|
||||
if (item.Parent is Item item1)
|
||||
|
|
@ -1429,25 +1628,25 @@ namespace Server.Network
|
|||
|
||||
public static void PingReq(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
Packets.SendPingAck(state, pvSrc.ReadByte());
|
||||
state.Send(PingAck.Instantiate(pvSrc.ReadByte()));
|
||||
}
|
||||
|
||||
public static void SetUpdateRange(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
Packets.SendChangeUpdateRange(state);
|
||||
state.Send(ChangeUpdateRange.Instantiate(18));
|
||||
}
|
||||
|
||||
public static void MovementReq(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
Direction dir = (Direction)pvSrc.ReadByte();
|
||||
byte seq = pvSrc.ReadByte();
|
||||
pvSrc.ReadInt32(); // key
|
||||
int seq = pvSrc.ReadByte();
|
||||
int key = pvSrc.ReadInt32();
|
||||
|
||||
Mobile m = state.Mobile;
|
||||
|
||||
if (state.Sequence == 0 && seq != 0 || !m.Move(dir))
|
||||
{
|
||||
Packets.SendMovementRej(state, seq, m);
|
||||
state.Send(new MovementRej(seq, m));
|
||||
state.Sequence = 0;
|
||||
|
||||
m.ClearFastwalkStack();
|
||||
|
|
@ -1456,7 +1655,7 @@ namespace Server.Network
|
|||
{
|
||||
++seq;
|
||||
|
||||
if (seq == 0)
|
||||
if (seq == 256)
|
||||
seq = 1;
|
||||
|
||||
state.Sequence = seq;
|
||||
|
|
@ -1489,7 +1688,7 @@ namespace Server.Network
|
|||
{
|
||||
int packetID = pvSrc.ReadUInt16();
|
||||
|
||||
// Console.WriteLine("Extended Packet: {0:X}", packetID);
|
||||
Console.WriteLine("Extended Packet: {0:X}", packetID);
|
||||
PacketHandler ph = GetExtendedHandler(packetID);
|
||||
|
||||
if (ph == null)
|
||||
|
|
@ -1863,6 +2062,13 @@ namespace Server.Network
|
|||
if (m != null)
|
||||
switch (type)
|
||||
{
|
||||
case 0x00: // Unknown, sent by godclient
|
||||
{
|
||||
if (VerifyGC(state))
|
||||
Console.WriteLine("God Client: {0}: Query 0x{1:X2} on {2} '{3}'", state, type, m.Serial, m.Name);
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x04: // Stats
|
||||
{
|
||||
m.OnStatsQuery(from);
|
||||
|
|
@ -1887,17 +2093,47 @@ namespace Server.Network
|
|||
|
||||
string name = pvSrc.ReadString(30);
|
||||
|
||||
pvSrc.ReadInt16(); // Unknown
|
||||
|
||||
pvSrc.Seek(2, SeekOrigin.Current);
|
||||
int flags = pvSrc.ReadInt32();
|
||||
|
||||
pvSrc.Seek(24, SeekOrigin.Current);
|
||||
/* if (FeatureProtection.DisabledFeatures != 0 && ThirdPartyAuthCallback != null)
|
||||
{
|
||||
bool authOK = false;
|
||||
|
||||
ulong razorFeatures = ((ulong)pvSrc.ReadUInt32() << 32) | pvSrc.ReadUInt32();
|
||||
|
||||
if (razorFeatures == (ulong)FeatureProtection.DisabledFeatures)
|
||||
{
|
||||
bool doesNotMatch = false;
|
||||
for (int i = 0; !doesNotMatch && i < m_ThirdPartyAuthKey.Length; i++)
|
||||
doesNotMatch = pvSrc.ReadByte() != m_ThirdPartyAuthKey[i];
|
||||
|
||||
if (!doesNotMatch)
|
||||
authOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pvSrc.Seek(16, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
ThirdPartyAuthCallback(state, authOK);
|
||||
}*/
|
||||
/* else
|
||||
{*/
|
||||
pvSrc.Seek(24, SeekOrigin.Current);
|
||||
/* }*/
|
||||
|
||||
/* if (ThirdPartyHackedCallback != null)
|
||||
{
|
||||
pvSrc.Seek(-2, SeekOrigin.Current);
|
||||
if (pvSrc.ReadUInt16() == 0xDEAD)
|
||||
ThirdPartyHackedCallback(state, true);
|
||||
}*/
|
||||
|
||||
if (!state.Running)
|
||||
return;
|
||||
|
||||
int charSlot = pvSrc.ReadInt32();
|
||||
// TODO: Handle IP address.
|
||||
int clientIP = pvSrc.ReadInt32();
|
||||
|
||||
IAccount a = state.Account;
|
||||
|
|
@ -1916,7 +2152,7 @@ namespace Server.Network
|
|||
if (check != null && check.Map != Map.Internal && check != m)
|
||||
{
|
||||
Console.WriteLine("Login: {0}: Account in use", state);
|
||||
Packets.SendPopupMessage(state, PMMessage.CharInWorld);
|
||||
state.Send(new PopupMessage(PMMessage.CharInWorld));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1931,9 +2167,11 @@ namespace Server.Network
|
|||
|
||||
// TODO: Make this wait one tick so we don't have to call it unnecessarily
|
||||
NetState.ProcessDisposedQueue();
|
||||
Packets.SendClientVersionReq(state);
|
||||
|
||||
state.Send(new ClientVersionReq());
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
state.Flags = (ClientFlags)flags;
|
||||
|
||||
state.Mobile = m;
|
||||
|
|
@ -1945,38 +2183,93 @@ namespace Server.Network
|
|||
|
||||
public static void DoLogin(NetState state, Mobile m)
|
||||
{
|
||||
Packets.SendLoginConfirm(state, m);
|
||||
state.Send(new LoginConfirm(m));
|
||||
|
||||
if (m.Map != null)
|
||||
Packets.SendMapChange(state, m.Map);
|
||||
state.Send(new MapChange(m));
|
||||
|
||||
Packets.SendMapPatches(state);
|
||||
Packets.SendSeasonChange(state, m.GetSeason(), 1);
|
||||
Packets.SendSupportedFeatures(state);
|
||||
state.Send(new MapPatches());
|
||||
|
||||
state.Send(SeasonChange.Instantiate(m.GetSeason(), true));
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
|
||||
state.Sequence = 0;
|
||||
|
||||
// TODO: Verify if we need this twice
|
||||
Packets.SendMobileUpdate(state, m);
|
||||
m.CheckLightLevels(true);
|
||||
Packets.SendMobileUpdate(state, m);
|
||||
if (state.NewMobileIncoming)
|
||||
{
|
||||
state.Send(new MobileUpdate(m));
|
||||
state.Send(new MobileUpdate(m));
|
||||
|
||||
Packets.SendMobileIncoming(state, m, m);
|
||||
Packets.SendMobileStatus(state, m, m);
|
||||
Packets.SendSetWarMode(state, m.Warmode);
|
||||
m.CheckLightLevels(true);
|
||||
|
||||
m.SendEverything();
|
||||
state.Send(new MobileUpdate(m));
|
||||
|
||||
Packets.SendSupportedFeatures(state);
|
||||
Packets.SendMobileUpdate(state, m);
|
||||
Packets.SendMobileStatus(state, m, m);
|
||||
Packets.SendSetWarMode(state, m.Warmode);
|
||||
Packets.SendMobileIncoming(state, m, m);
|
||||
state.Send(new MobileIncoming(m, m));
|
||||
//state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
state.Send(Network.SetWarMode.Instantiate(m.Warmode));
|
||||
|
||||
Packets.SendLoginComplete(state);
|
||||
Packets.SendCurrentTime(state);
|
||||
Packets.SendMapChange(state, m.Map);
|
||||
Packets.SendSeasonChange(state, m.GetSeason(), 1);
|
||||
m.SendEverything();
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
state.Send(new MobileUpdate(m));
|
||||
//state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
state.Send(Network.SetWarMode.Instantiate(m.Warmode));
|
||||
state.Send(new MobileIncoming(m, m));
|
||||
}
|
||||
else if (state.StygianAbyss)
|
||||
{
|
||||
state.Send(new MobileUpdate(m));
|
||||
state.Send(new MobileUpdate(m));
|
||||
|
||||
m.CheckLightLevels(true);
|
||||
|
||||
state.Send(new MobileUpdate(m));
|
||||
|
||||
state.Send(new MobileIncomingSA(m, m));
|
||||
//state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
state.Send(Network.SetWarMode.Instantiate(m.Warmode));
|
||||
|
||||
m.SendEverything();
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
state.Send(new MobileUpdate(m));
|
||||
//state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
state.Send(Network.SetWarMode.Instantiate(m.Warmode));
|
||||
state.Send(new MobileIncomingSA(m, m));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Send(new MobileUpdateOld(m));
|
||||
state.Send(new MobileUpdateOld(m));
|
||||
|
||||
m.CheckLightLevels(true);
|
||||
|
||||
state.Send(new MobileUpdateOld(m));
|
||||
|
||||
state.Send(new MobileIncomingOld(m, m));
|
||||
//state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
state.Send(Network.SetWarMode.Instantiate(m.Warmode));
|
||||
|
||||
m.SendEverything();
|
||||
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
state.Send(new MobileUpdateOld(m));
|
||||
//state.Send( new MobileAttributes( m ) );
|
||||
state.Send(new MobileStatus(m, m));
|
||||
state.Send(Network.SetWarMode.Instantiate(m.Warmode));
|
||||
state.Send(new MobileIncomingOld(m, m));
|
||||
}
|
||||
|
||||
state.Send(LoginComplete.Instance);
|
||||
state.Send(new CurrentTime());
|
||||
state.Send(SeasonChange.Instantiate(m.GetSeason(), true));
|
||||
state.Send(new MapChange(m));
|
||||
|
||||
EventSink.InvokeLogin(new LoginEventArgs(m));
|
||||
|
||||
|
|
@ -2041,14 +2334,20 @@ namespace Server.Network
|
|||
race = Race.Races[raceID];
|
||||
}
|
||||
else
|
||||
{
|
||||
race = Race.Races[(byte)(genderRace / 2)];
|
||||
}
|
||||
|
||||
if (race == null)
|
||||
race = Race.DefaultRace;
|
||||
|
||||
race ??= Race.DefaultRace;
|
||||
CityInfo[] info = state.CityInfo;
|
||||
IAccount a = state.Account;
|
||||
|
||||
if (info == null || a == null || cityIndex < 0 || cityIndex >= info.Length)
|
||||
{
|
||||
state.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if anyone is using this account
|
||||
|
|
@ -2059,7 +2358,7 @@ namespace Server.Network
|
|||
if (check != null && check.Map != Map.Internal)
|
||||
{
|
||||
Console.WriteLine("Login: {0}: Account in use", state);
|
||||
Packets.SendPopupMessage(state, PMMessage.CharInWorld);
|
||||
state.Send(new PopupMessage(PMMessage.CharInWorld));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2084,7 +2383,7 @@ namespace Server.Network
|
|||
race
|
||||
);
|
||||
|
||||
Packets.SendClientVersionReq(state);
|
||||
state.Send(new ClientVersionReq());
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
|
|
@ -2154,8 +2453,10 @@ namespace Server.Network
|
|||
|
||||
bool female = genderRace % 2 != 0;
|
||||
|
||||
byte raceId = (byte)(genderRace < 4 ? 0 : genderRace / 2 - 1);
|
||||
Race race = Race.Races[raceId] ?? Race.DefaultRace;
|
||||
Race race;
|
||||
|
||||
byte raceID = (byte)(genderRace < 4 ? 0 : genderRace / 2 - 1);
|
||||
race = Race.Races[raceID] ?? Race.DefaultRace;
|
||||
|
||||
CityInfo[] info = state.CityInfo;
|
||||
IAccount a = state.Account;
|
||||
|
|
@ -2174,7 +2475,7 @@ namespace Server.Network
|
|||
if (check != null && check.Map != Map.Internal)
|
||||
{
|
||||
Console.WriteLine("Login: {0}: Account in use", state);
|
||||
Packets.SendPopupMessage(state, PMMessage.CharInWorld);
|
||||
state.Send(new PopupMessage(PMMessage.CharInWorld));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2200,20 +2501,25 @@ namespace Server.Network
|
|||
race
|
||||
);
|
||||
|
||||
Packets.SendClientVersionReq(state);
|
||||
state.Send(new ClientVersionReq());
|
||||
|
||||
state.BlockAllPackets = true;
|
||||
|
||||
EventSink.InvokeCharacterCreated(args);
|
||||
|
||||
Mobile m = args.Mobile;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
state.BlockAllPackets = true;
|
||||
state.Mobile = m;
|
||||
m.NetState = state;
|
||||
new LoginTimer(state, m).Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.BlockAllPackets = false;
|
||||
state.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2224,11 +2530,11 @@ namespace Server.Network
|
|||
int oldestID = 0;
|
||||
DateTime oldest = DateTime.MaxValue;
|
||||
|
||||
foreach (var (key, value) in m_AuthIDWindow)
|
||||
if (value.Age < oldest)
|
||||
foreach (KeyValuePair<int, AuthIDPersistence> kvp in m_AuthIDWindow)
|
||||
if (kvp.Value.Age < oldest)
|
||||
{
|
||||
oldestID = key;
|
||||
oldest = value.Age;
|
||||
oldestID = kvp.Key;
|
||||
oldest = kvp.Value.Age;
|
||||
}
|
||||
|
||||
m_AuthIDWindow.Remove(oldestID);
|
||||
|
|
@ -2258,13 +2564,13 @@ namespace Server.Network
|
|||
}
|
||||
|
||||
state.SentFirstPacket = true;
|
||||
state.UseCompression = true;
|
||||
|
||||
int authID = pvSrc.ReadInt32();
|
||||
|
||||
if (m_AuthIDWindow.TryGetValue(authID, out AuthIDPersistence ap))
|
||||
{
|
||||
m_AuthIDWindow.Remove(authID);
|
||||
|
||||
state.Version = ap.Version;
|
||||
}
|
||||
else if (ClientVerification)
|
||||
|
|
@ -2298,12 +2604,19 @@ namespace Server.Network
|
|||
if (e.Accepted)
|
||||
{
|
||||
state.CityInfo = e.CityInfo;
|
||||
state.CompressionEnabled = true;
|
||||
|
||||
Packets.SendSupportedFeatures(state);
|
||||
Packets.SendCharacterList(state, state.CityInfo);
|
||||
state.Send(SupportedFeatures.Instantiate(state));
|
||||
|
||||
if (state.NewCharacterList)
|
||||
state.Send(new CharacterList(state.Account, state.CityInfo));
|
||||
else
|
||||
state.Send(new CharacterListOld(state.Account, state.CityInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static void PlayServer(NetState state, PacketReader pvSrc)
|
||||
|
|
@ -2313,15 +2626,17 @@ namespace Server.Network
|
|||
IAccount a = state.Account;
|
||||
|
||||
if (info == null || a == null || index < 0 || index >= info.Length)
|
||||
{
|
||||
state.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerInfo si = info[index];
|
||||
|
||||
state.m_AuthID = GenerateAuthID(state);
|
||||
state.m_AuthID = PlayServerAck.m_AuthID = GenerateAuthID(state);
|
||||
|
||||
state.SentFirstPacket = false;
|
||||
Packets.SendPlayServerAck(state, si);
|
||||
state.Send(new PlayServerAck(si));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2419,13 +2734,13 @@ namespace Server.Network
|
|||
|
||||
state.ServerInfo = info;
|
||||
|
||||
Packets.SendAccountLoginAck(state, info);
|
||||
state.Send(new AccountLoginAck(info));
|
||||
}
|
||||
}
|
||||
|
||||
public static void AccountLogin_ReplyRej(NetState state, ALRReason reason)
|
||||
{
|
||||
Packets.SendAccountLoginRej(state, reason);
|
||||
state.Send(new AccountLoginRej(reason));
|
||||
state.Dispose();
|
||||
}
|
||||
|
||||
|
|
@ -2443,10 +2758,7 @@ namespace Server.Network
|
|||
protected override void OnTick()
|
||||
{
|
||||
if (m_State == null)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_State.Version != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,206 +104,31 @@ namespace Server.Network
|
|||
|
||||
public sbyte ReadSByte() => (sbyte)ReadByte();
|
||||
|
||||
public bool ReadBoolean() => ReadByte() != 0;
|
||||
public bool ReadBoolean() => ReadByte() > 0;
|
||||
|
||||
public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE;
|
||||
|
||||
public string ReadUTF8StringSafe()
|
||||
public string ReadUnicodeStringLE()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool end = false;
|
||||
|
||||
while (!(end |= m_Reader.End))
|
||||
{
|
||||
ReadOnlySpan<byte> span = m_Reader.UnreadSpan;
|
||||
int count = 0;
|
||||
bool safe = true;
|
||||
while (count < span.Length)
|
||||
{
|
||||
byte chr = span[count];
|
||||
if (chr == 0)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsSafeChar(chr))
|
||||
{
|
||||
safe = false;
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
sb.Append(Encoding.UTF8.GetString(span.Slice(0, count)));
|
||||
m_Reader.Advance(count + (safe ? 1 : 0));
|
||||
}
|
||||
while (m_Reader.TryReadLittleEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUTF8String()
|
||||
public string ReadUnicodeStringLE(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool end = false;
|
||||
|
||||
while (!(end |= m_Reader.End))
|
||||
{
|
||||
ReadOnlySpan<byte> span = m_Reader.UnreadSpan;
|
||||
int count = 0;
|
||||
while (count < span.Length)
|
||||
{
|
||||
if (span[count] == 0)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadLittleEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
sb.Append(Encoding.UTF8.GetString(span.Slice(0, count)));
|
||||
m_Reader.Advance(count);
|
||||
}
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool end = false;
|
||||
|
||||
while (!(end |= m_Reader.End))
|
||||
{
|
||||
ReadOnlySpan<byte> span = m_Reader.UnreadSpan;
|
||||
int count = 0;
|
||||
while (count < span.Length)
|
||||
{
|
||||
if (span[count] == 0)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
sb.Append(Encoding.ASCII.GetString(span.Slice(0, count)));
|
||||
m_Reader.Advance(count);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadString(int size)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool end = false;
|
||||
|
||||
while (!(end |= m_Reader.End) && size > 0)
|
||||
{
|
||||
ReadOnlySpan<byte> span = m_Reader.UnreadSpan;
|
||||
int count = 0;
|
||||
while (count < span.Length && size > 0)
|
||||
{
|
||||
if (span[count] == 0)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
size--;
|
||||
}
|
||||
|
||||
sb.Append(Encoding.ASCII.GetString(span.Slice(0, count)));
|
||||
m_Reader.Advance(count);
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
m_Reader.Advance(size);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE;
|
||||
|
||||
public string ReadUTF8StringSafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool end = false;
|
||||
|
||||
while (!(end |= m_Reader.End))
|
||||
{
|
||||
ReadOnlySpan<byte> span = m_Reader.UnreadSpan;
|
||||
int count = 0;
|
||||
bool safe = true;
|
||||
while (count < span.Length)
|
||||
{
|
||||
byte chr = span[count];
|
||||
if (chr == 0)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsSafeChar(chr))
|
||||
{
|
||||
safe = false;
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
sb.Append(Encoding.ASCII.GetString(span.Slice(0, count)));
|
||||
m_Reader.Advance(count + (safe ? 1 : 0));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe(int size)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool end = false;
|
||||
|
||||
while (!(end |= m_Reader.End) && size > 0)
|
||||
{
|
||||
ReadOnlySpan<byte> span = m_Reader.UnreadSpan;
|
||||
int count = 0;
|
||||
bool safe = true;
|
||||
while (count < span.Length && size > 0)
|
||||
{
|
||||
byte chr = span[count];
|
||||
if (chr == 0)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsSafeChar(chr))
|
||||
{
|
||||
safe = false;
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
size--;
|
||||
}
|
||||
|
||||
sb.Append(Encoding.ASCII.GetString(span.Slice(0, count)));
|
||||
m_Reader.Advance(size + (safe ? 1 : 0));
|
||||
}
|
||||
|
||||
public string ReadUTF8String() =>
|
||||
Utility.UTF8.GetString(
|
||||
m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true) ? span :
|
||||
m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray()
|
||||
);
|
||||
|
||||
public string ReadUnicodeStringLESafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
|
@ -329,6 +154,17 @@ namespace Server.Network
|
|||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
|
@ -339,24 +175,72 @@ namespace Server.Network
|
|||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString(int fixedLength)
|
||||
public bool IsSafeChar(int c) => c >= 0x20 && c < 0xFFFE;
|
||||
|
||||
public string ReadUTF8StringSafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
string s;
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true))
|
||||
s = Utility.UTF8.GetString(span.Length > fixedLength ? span.Slice(0, fixedLength) : span);
|
||||
else
|
||||
{
|
||||
long size = Math.Min(m_Reader.Remaining, fixedLength);
|
||||
s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, size).ToArray());
|
||||
m_Reader.Advance(size);
|
||||
}
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength * 2);
|
||||
StringBuilder sb = new StringBuilder(s.Length);
|
||||
|
||||
for (int i = 0; i < s.Length; ++i)
|
||||
if (IsSafeChar(s[i]))
|
||||
sb.Append(s[i]);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
public string ReadUTF8StringSafe()
|
||||
{
|
||||
string s;
|
||||
|
||||
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true))
|
||||
s = Utility.UTF8.GetString(span);
|
||||
else
|
||||
{
|
||||
s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray());
|
||||
m_Reader.Advance(m_Reader.Remaining);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(s.Length);
|
||||
|
||||
for (int i = 0; i < s.Length; ++i)
|
||||
if (IsSafeChar(s[i]))
|
||||
sb.Append(s[i]);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUTF8String() =>
|
||||
Utility.UTF8.GetString(
|
||||
m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true) ? span :
|
||||
m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray()
|
||||
);
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
while (m_Reader.TryRead(out byte c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryRead(out byte c))
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
|
|
@ -376,5 +260,45 @@ namespace Server.Network
|
|||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength * 2);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadString(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
346
Projects/Server/Network/PacketWriter.cs
Normal file
346
Projects/Server/Network/PacketWriter.cs
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/***************************************************************************
|
||||
* PacketWriter.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public class PacketWriter
|
||||
{
|
||||
private static ConcurrentQueue<PacketWriter> m_Pool = new ConcurrentQueue<PacketWriter>();
|
||||
|
||||
/// <summary>
|
||||
/// Internal format buffer.
|
||||
/// </summary>
|
||||
private byte[] m_Buffer = new byte[4];
|
||||
|
||||
private int m_Capacity;
|
||||
|
||||
/// <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 = 32)
|
||||
{
|
||||
UnderlyingStream = new MemoryStream(capacity);
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total stream length.
|
||||
/// </summary>
|
||||
public long Length => UnderlyingStream.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current stream position.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get => UnderlyingStream.Position;
|
||||
set => UnderlyingStream.Position = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The internal stream used by this PacketWriter instance.
|
||||
/// </summary>
|
||||
public MemoryStream UnderlyingStream { get; private set; }
|
||||
|
||||
public static PacketWriter CreateInstance(int capacity = 32)
|
||||
{
|
||||
if (m_Pool.TryDequeue(out PacketWriter pw))
|
||||
{
|
||||
pw.m_Capacity = capacity;
|
||||
pw.UnderlyingStream.SetLength(0);
|
||||
return pw;
|
||||
}
|
||||
|
||||
return new PacketWriter(capacity);
|
||||
}
|
||||
|
||||
public static void ReleaseInstance(PacketWriter pw)
|
||||
{
|
||||
m_Pool.Enqueue(pw);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
UnderlyingStream.WriteByte((byte)(value ? 1 : 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(byte value)
|
||||
{
|
||||
UnderlyingStream.WriteByte(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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)
|
||||
{
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.ASCII.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + length + 1);
|
||||
|
||||
Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += length + 1;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2);
|
||||
|
||||
UnderlyingStream.Position += Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += 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;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
size *= 2;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length * 2 >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.Unicode.GetBytes(value, 0, size / 2, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2);
|
||||
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += 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;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
size *= 2;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length * 2 >= size )
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, size / 2, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the stream from the current position up to (capacity) with 0x00's
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
Fill(m_Capacity - UnderlyingStream.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number of 0x00 byte values to the underlying stream.
|
||||
/// </summary>
|
||||
public void Fill(long length)
|
||||
{
|
||||
if (UnderlyingStream.Position == UnderlyingStream.Length)
|
||||
{
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + length);
|
||||
UnderlyingStream.Seek(0, SeekOrigin.End);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnderlyingStream.Write(new byte[length], 0, (int)length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the current position from an origin.
|
||||
/// </summary>
|
||||
public long Seek(long offset, SeekOrigin origin) => UnderlyingStream.Seek(offset, origin);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entire stream content as a byte array.
|
||||
/// </summary>
|
||||
public byte[] ToArray() => UnderlyingStream.ToArray();
|
||||
}
|
||||
}
|
||||
4170
Projects/Server/Network/Packets.cs
Normal file
4170
Projects/Server/Network/Packets.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,325 +0,0 @@
|
|||
using System;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public enum DeleteResultType : byte
|
||||
{
|
||||
PasswordInvalid,
|
||||
CharNotExist,
|
||||
CharBeingPlayed,
|
||||
CharTooYoung,
|
||||
CharQueued,
|
||||
BadRequest
|
||||
}
|
||||
|
||||
public enum PMMessage : byte
|
||||
{
|
||||
CharNoExist = 1,
|
||||
CharExists = 2,
|
||||
CharInWorld = 5,
|
||||
LoginSyncError = 6,
|
||||
IdleWarning = 7
|
||||
}
|
||||
|
||||
public enum ALRReason : byte
|
||||
{
|
||||
Invalid = 0x00,
|
||||
InUse = 0x01,
|
||||
Blocked = 0x02,
|
||||
BadPass = 0x03,
|
||||
Idle = 0xFE,
|
||||
BadComm = 0xFF
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDeleteResult(NetState ns, DeleteResultType res)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
Span<byte> span = ns.SendPipe.Writer.GetSpan(2);
|
||||
span[0] = 0x85; // Packet ID
|
||||
span[1] = (byte)res;
|
||||
|
||||
// Not compressed with Huffman
|
||||
_ = ns.Flush(2);
|
||||
}
|
||||
|
||||
public static void SendPopupMessage(NetState ns, PMMessage msg)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x53, // Packet ID
|
||||
(byte)msg
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendAccountLoginRej(NetState ns, ALRReason reason)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
Span<byte> span = ns.SendPipe.Writer.GetSpan(2);
|
||||
span[0] = 0x82; // Packet ID
|
||||
span[1] = (byte)reason;
|
||||
|
||||
// Not compressed with Huffman
|
||||
_ = ns.Flush(2);
|
||||
}
|
||||
|
||||
public static void SendSupportedFeatures(NetState ns)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = ns.ExtendedSupportedFeatures ? 5 : 3;
|
||||
|
||||
Span<byte> bytes = stackalloc byte[length];
|
||||
|
||||
SpanWriter w = new SpanWriter(bytes);
|
||||
w.Write((byte)0xB9); // Packet ID
|
||||
|
||||
FeatureFlags flags = ExpansionInfo.CoreExpansion.SupportedFeatures;
|
||||
|
||||
if (ns.Account?.Limit >= 6)
|
||||
{
|
||||
flags &= ~FeatureFlags.UOTD;
|
||||
flags |= FeatureFlags.LiveAccount |
|
||||
(ns.Account.Limit > 6 ? FeatureFlags.SeventhCharacterSlot : FeatureFlags.SixthCharacterSlot);
|
||||
}
|
||||
|
||||
if (ns.ExtendedSupportedFeatures)
|
||||
w.Write((uint)flags);
|
||||
else
|
||||
w.Write((ushort)flags);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendCharacterList(NetState ns, CityInfo[] info)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.NewCharacterList)
|
||||
SendCharacterListNew(ns, ns.Account, info);
|
||||
else
|
||||
SendCharacterListOld(ns, ns.Account, info);
|
||||
}
|
||||
|
||||
public static void SendCharacterListNew(NetState ns, IAccount a, CityInfo[] info)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int highSlot = -1;
|
||||
|
||||
for (int i = 0; i < a.Length; ++i)
|
||||
if (a[i] != null)
|
||||
highSlot = i;
|
||||
|
||||
int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
int length = 11 + count * 60 + info.Length * 89;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xA9); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write((byte)count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (a[i] != null)
|
||||
{
|
||||
w.WriteAsciiFixed(a[i].Name, 30);
|
||||
w.Position += 30;
|
||||
}
|
||||
else
|
||||
w.Position += 60;
|
||||
|
||||
w.Write((byte)info.Length);
|
||||
|
||||
for (int i = 0; i < info.Length; ++i)
|
||||
{
|
||||
CityInfo ci = info[i];
|
||||
|
||||
w.Write((byte)i);
|
||||
w.WriteAsciiFixed(ci.City, 32);
|
||||
w.WriteAsciiFixed(ci.Building, 32);
|
||||
w.Write(ci.X);
|
||||
w.Write(ci.Y);
|
||||
w.Write(ci.Z);
|
||||
w.Write(ci.Map.MapID);
|
||||
w.Write(ci.Description);
|
||||
w.Position += 4; // w.Write(0);
|
||||
}
|
||||
|
||||
CharacterListFlags flags = ExpansionInfo.CoreExpansion.CharacterListFlags;
|
||||
|
||||
if (count > 6)
|
||||
flags |= CharacterListFlags.SeventhCharacterSlot |
|
||||
CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required?
|
||||
else if (count == 6)
|
||||
flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
|
||||
else if (a.Limit == 1)
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
|
||||
w.Write((int)flags);
|
||||
|
||||
w.Write((short)-1);
|
||||
|
||||
ns.Send(w.Span);
|
||||
|
||||
// TODO: Razor support?
|
||||
}
|
||||
|
||||
public static void SendCharacterListOld(NetState ns, IAccount a, CityInfo[] info)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int highSlot = -1;
|
||||
|
||||
for (int i = 0; i < a.Length; ++i)
|
||||
if (a[i] != null)
|
||||
highSlot = i;
|
||||
|
||||
int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
int length = 9 + count * 60 + info.Length * 63;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xA9); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write((byte)count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (a[i] != null)
|
||||
{
|
||||
w.WriteAsciiFixed(a[i].Name, 30);
|
||||
w.Position += 30;
|
||||
}
|
||||
else
|
||||
w.Position += 60;
|
||||
|
||||
w.Write((byte)info.Length);
|
||||
|
||||
for (int i = 0; i < info.Length; ++i)
|
||||
{
|
||||
CityInfo ci = info[i];
|
||||
|
||||
w.Write((byte)i);
|
||||
w.WriteAsciiFixed(ci.City, 31);
|
||||
w.WriteAsciiFixed(ci.Building, 31);
|
||||
}
|
||||
|
||||
CharacterListFlags flags = ExpansionInfo.CoreExpansion.CharacterListFlags;
|
||||
|
||||
if (count > 6)
|
||||
flags |= CharacterListFlags.SeventhCharacterSlot |
|
||||
CharacterListFlags.SixthCharacterSlot; // 7th Character Slot - TODO: Is SixthCharacterSlot Required?
|
||||
else if (count == 6)
|
||||
flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot
|
||||
else if (a.Limit == 1)
|
||||
flags |= CharacterListFlags.SlotLimit &
|
||||
CharacterListFlags.OneCharacterSlot; // Limit Characters & One Character
|
||||
|
||||
w.Write((int)flags);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
|
||||
// TODO: Razor support?
|
||||
}
|
||||
|
||||
public static void SendCharacterListUpdate(NetState ns, IAccount a)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int highSlot = -1;
|
||||
|
||||
for (int i = 0; i < a.Length; ++i)
|
||||
if (a[i] != null)
|
||||
highSlot = i;
|
||||
|
||||
int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5);
|
||||
|
||||
int length = 4 + count * 60;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x86); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write((byte)count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
Mobile m = a[i];
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
w.WriteAsciiFixed(m.Name, 30);
|
||||
w.Position += 30;
|
||||
}
|
||||
else
|
||||
w.Position += 60;
|
||||
}
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendPlayServerAck(NetState ns, ServerInfo si)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(ns.SendPipe.Writer.GetSpan(11));
|
||||
w.Write((byte)0x8C); // Packet ID
|
||||
|
||||
int addr = Utility.GetAddressValue(si.Address.Address);
|
||||
|
||||
w.Write((byte)addr);
|
||||
w.Write((byte)(addr >> 8));
|
||||
w.Write((byte)(addr >> 16));
|
||||
w.Write((byte)(addr >> 24));
|
||||
|
||||
w.Write((short)si.Address.Port);
|
||||
w.Write(ns.m_AuthID);
|
||||
|
||||
// Not compressed with Huffman
|
||||
_ = ns.Flush(11);
|
||||
}
|
||||
|
||||
public static void SendAccountLoginAck(NetState ns, ServerInfo[] info)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 6 + info.Length * 40;
|
||||
|
||||
SpanWriter w = new SpanWriter(ns.SendPipe.Writer.GetSpan(length));
|
||||
w.Write((byte)0xA8); // Packet ID
|
||||
w.Write((short)length);
|
||||
|
||||
w.Write((byte)0x5D); // Unknown
|
||||
|
||||
w.Write((ushort)info.Length);
|
||||
|
||||
for (int i = 0; i < info.Length; ++i)
|
||||
{
|
||||
ServerInfo si = info[i];
|
||||
|
||||
w.Write((ushort)i);
|
||||
w.WriteAsciiFixed(si.Name, 32, true);
|
||||
w.Write((byte)si.FullPercent);
|
||||
w.Write((sbyte)si.TimeZone);
|
||||
w.Write(Utility.GetAddressValue(si.Address.Address));
|
||||
}
|
||||
|
||||
// Not compressed with Huffman
|
||||
_ = ns.Flush(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendSetArrow(NetState ns, short x, short y)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[6]);
|
||||
w.Write((byte)0xBA); // Packet ID
|
||||
|
||||
w.Write((byte)1);
|
||||
w.Write(x);
|
||||
w.Write(y);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
private static byte[] _cancelArrowPacket;
|
||||
|
||||
public static void SendCancelArrow(NetState ns)
|
||||
{
|
||||
ns?.Send(_cancelArrowPacket ??= new byte[]
|
||||
{
|
||||
0xBA, // Packet ID
|
||||
0x00,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendSetArrowHS(NetState ns, Serial s, short x, short y)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[10]);
|
||||
w.Write((byte)0xBA); // Packet ID
|
||||
|
||||
w.Write((byte)1);
|
||||
w.Write(x);
|
||||
w.Write(y);
|
||||
w.Write(s);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendCancelArrowHS(NetState ns, Serial s, short x, short y)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[10]);
|
||||
w.Write((byte)0xBA); // Packet ID
|
||||
|
||||
w.Position++;
|
||||
w.Write(x);
|
||||
w.Write(y);
|
||||
w.Write(s);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static class AttributeNormalizer
|
||||
{
|
||||
public static int Maximum { get; set; } = 25;
|
||||
|
||||
public static bool Enabled { get; set; } = true;
|
||||
|
||||
public static void Write(SpanWriter w, int cur, int max)
|
||||
{
|
||||
if (Enabled && max != 0)
|
||||
{
|
||||
w.Write((short)Maximum);
|
||||
w.Write((short)(cur * Maximum / max));
|
||||
}
|
||||
else
|
||||
{
|
||||
w.Write((short)max);
|
||||
w.Write((short)cur);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteReverse(SpanWriter w, int cur, int max)
|
||||
{
|
||||
if (Enabled && max != 0)
|
||||
{
|
||||
w.Write((short)(cur * Maximum / max));
|
||||
w.Write((short)Maximum);
|
||||
}
|
||||
else
|
||||
{
|
||||
w.Write((short)cur);
|
||||
w.Write((short)max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendMobileHits(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xA1); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.HitsMax);
|
||||
w.Write((short)m.Hits);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendNormalizedMobileHits(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xA1); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
AttributeNormalizer.Write(w, m.Hits, m.HitsMax);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendMobileMana(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xA2); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.ManaMax);
|
||||
w.Write((short)m.Mana);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendNormalizedMobileMana(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xA2); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
AttributeNormalizer.Write(w, m.Mana, m.ManaMax);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendMobileStam(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xA3); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.StamMax);
|
||||
w.Write((short)m.Stam);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendNormalizedMobileStam(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xA3); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
AttributeNormalizer.Write(w, m.Stam, m.StamMax);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendMobileAttributes(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[17]);
|
||||
w.Write((byte)0x2D); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
|
||||
w.Write((short)m.HitsMax);
|
||||
w.Write((short)m.Hits);
|
||||
|
||||
w.Write((short)m.ManaMax);
|
||||
w.Write((short)m.Mana);
|
||||
|
||||
w.Write((short)m.StamMax);
|
||||
w.Write((short)m.Stam);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendNormalizedMobileAttributes(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[17]);
|
||||
w.Write((byte)0x2D); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
|
||||
AttributeNormalizer.Write(w, m.Hits, m.HitsMax);
|
||||
AttributeNormalizer.Write(w, m.Mana, m.ManaMax);
|
||||
AttributeNormalizer.Write(w, m.Stam, m.StamMax);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDisplayContainer(NetState ns, Serial s, short gumpId = -1)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.HighSeas)
|
||||
SendDisplayContainerHS(ns, s, gumpId);
|
||||
else
|
||||
SendDisplayContainerOld(ns, s, gumpId);
|
||||
}
|
||||
|
||||
public static void SendDisplayContainerOld(NetState ns, Serial s, short gumpId = -1)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[7]);
|
||||
w.Write((byte)0x24); // Packet ID
|
||||
|
||||
w.Write(s);
|
||||
w.Write(gumpId);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendDisplayContainerHS(NetState ns, Serial s, short gumpId = -1)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0x24); // Packet ID
|
||||
|
||||
w.Write(s);
|
||||
w.Write(gumpId);
|
||||
w.Write((short)0x7D);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendContainerContentUpdate(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.ContainerGridLines)
|
||||
SendContainerContentUpdateNew(ns, item);
|
||||
else
|
||||
SendContainerContentUpdateOld(ns, item);
|
||||
}
|
||||
|
||||
public static void SendContainerContentUpdateOld(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[20]);
|
||||
w.Write((byte)0x25); // Packet ID
|
||||
|
||||
Serial parentSerial;
|
||||
|
||||
if (item.Parent is Item parentItem)
|
||||
parentSerial = parentItem.Serial;
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: ContainerContentUpdate on item with !(parent is Item)");
|
||||
parentSerial = Serial.Zero;
|
||||
}
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((ushort)item.ItemID);
|
||||
w.Position++; // w.Write((byte)0); // signed, itemID offset
|
||||
w.Write((ushort)item.Amount);
|
||||
w.Write((short)item.X);
|
||||
w.Write((short)item.Y);
|
||||
w.Write(parentSerial);
|
||||
w.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue));
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendContainerContentUpdateNew(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[21]);
|
||||
w.Write((byte)0x25); // Packet ID
|
||||
|
||||
Serial parentSerial;
|
||||
|
||||
if (item.Parent is Item parentItem)
|
||||
parentSerial = parentItem.Serial;
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: ContainerContentUpdate on item with !(parent is Item)");
|
||||
parentSerial = Serial.Zero;
|
||||
}
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((ushort)item.ItemID);
|
||||
w.Position++; // signed, itemID offset
|
||||
w.Write((ushort)item.Amount);
|
||||
w.Write((short)item.X);
|
||||
w.Write((short)item.Y);
|
||||
w.Position++; // Grid Location?
|
||||
w.Write(parentSerial);
|
||||
w.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue));
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendContainerContent(NetState ns, Mobile beholder, Item beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.ContainerGridLines)
|
||||
SendContainerContentNew(ns, beholder, beheld);
|
||||
else
|
||||
SendContainerContentOld(ns, beholder, beheld);
|
||||
}
|
||||
|
||||
public static void SendContainerContentOld(NetState ns, Mobile beholder, Item beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[5 + beheld.Items.Count * 19]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Position += 4; // Dynamic Length, Item Count
|
||||
|
||||
List<Item> items = beheld.Items;
|
||||
int count = items.Count;
|
||||
|
||||
ushort written = 0;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
Item child = items[i];
|
||||
|
||||
if (!child.Deleted && beholder.CanSee(child))
|
||||
{
|
||||
Point3D loc = child.Location;
|
||||
|
||||
w.Write(child.Serial);
|
||||
w.Write((ushort)child.ItemID);
|
||||
w.Position++; // signed, itemID offset
|
||||
w.Write((ushort)child.Amount);
|
||||
w.Write((short)loc.m_X);
|
||||
w.Write((short)loc.m_Y);
|
||||
w.Write(beheld.Serial);
|
||||
w.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue));
|
||||
|
||||
++written;
|
||||
}
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
w.Write(written);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendContainerContentNew(NetState ns, Mobile beholder, Item beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[5 + beheld.Items.Count * 20]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Position += 4; // Dynamic Length, Item Count
|
||||
|
||||
List<Item> items = beheld.Items;
|
||||
int count = items.Count;
|
||||
|
||||
ushort written = 0;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
Item child = items[i];
|
||||
|
||||
if (!child.Deleted && beholder.CanSee(child))
|
||||
{
|
||||
Point3D loc = child.Location;
|
||||
|
||||
w.Write(child.Serial);
|
||||
w.Write((ushort)child.ItemID);
|
||||
w.Position++; // signed, itemID offset
|
||||
w.Write((ushort)child.Amount);
|
||||
w.Write((short)loc.m_X);
|
||||
w.Write((short)loc.m_Y);
|
||||
w.Position++; // Grid Location?
|
||||
w.Write(beheld.Serial);
|
||||
w.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue));
|
||||
|
||||
++written;
|
||||
}
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
w.Write(written);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDamage(NetState ns, Serial m, int amount)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.DamagePacket)
|
||||
SendDamageNew(ns, m, amount);
|
||||
else
|
||||
SendDamageOld(ns, m, amount);
|
||||
}
|
||||
public static void SendDamageOld(NetState ns, Serial m, int amount)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[11]);
|
||||
w.Write((byte)0xBF); // Extended Packet ID
|
||||
w.Write((ushort)11); // Length
|
||||
|
||||
w.Write((short)0x22);
|
||||
w.Write((byte)1);
|
||||
w.Write(m);
|
||||
|
||||
if (amount > 255)
|
||||
amount = 255;
|
||||
else if (amount < 0)
|
||||
amount = 0;
|
||||
|
||||
w.Write((byte)amount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDamageNew(NetState ns, Serial m, int amount)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0xBF); // Extended Packet ID
|
||||
w.Write((ushort)9); // Length
|
||||
|
||||
w.Write(m);
|
||||
|
||||
if (amount > 0xFFFF)
|
||||
amount = 0xFFFF;
|
||||
else if (amount < 0)
|
||||
amount = 0;
|
||||
|
||||
w.Write((ushort)amount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public enum EffectType : byte
|
||||
{
|
||||
Moving,
|
||||
Lightning,
|
||||
FixedXYZ,
|
||||
FixedFrom,
|
||||
Screen
|
||||
}
|
||||
|
||||
public enum ScreenEffectType : short
|
||||
{
|
||||
FadeOut,
|
||||
FadeIn,
|
||||
LightFlash,
|
||||
FadeInOut,
|
||||
DarkFlash
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
private static readonly int ParticleEffectPacketLength = 49;
|
||||
private static readonly int HuedEffectPacketLength = 36;
|
||||
private static readonly int OldEffectPacketLength = 28;
|
||||
|
||||
public static void SendParticalEffect(NetState ns, 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 (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[ParticleEffectPacketLength]);
|
||||
w.Write((byte)0xC7); // Packet ID
|
||||
|
||||
w.Write((byte)type);
|
||||
w.Write(from);
|
||||
w.Write(to);
|
||||
w.Write((short)itemId);
|
||||
w.Write((short)fromPoint.X);
|
||||
w.Write((short)fromPoint.Y);
|
||||
w.Write((sbyte)fromPoint.Z);
|
||||
w.Write((short)toPoint.X);
|
||||
w.Write((short)toPoint.Y);
|
||||
w.Write((sbyte)toPoint.Z);
|
||||
w.Write((byte)speed);
|
||||
w.Write((byte)duration);
|
||||
w.Position += 2;
|
||||
// w.Write((byte)0);
|
||||
// w.Write((byte)0);
|
||||
w.Write(fixedDirection);
|
||||
w.Write(explode);
|
||||
w.Write(hue);
|
||||
w.Write(renderMode);
|
||||
w.Write((short)effect);
|
||||
w.Write((short)explodeEffect);
|
||||
w.Write((short)explodeSound);
|
||||
w.Write(serial);
|
||||
w.Write((byte)layer);
|
||||
w.Write((short)unknown);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendHuedEffect(NetState ns, EffectType type, Serial from, Serial to, int itemId,
|
||||
IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue,
|
||||
int renderMode)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]);
|
||||
w.Write((byte)0xC0); // Packet ID
|
||||
|
||||
w.Write((byte)type);
|
||||
w.Write(from);
|
||||
w.Write(to);
|
||||
w.Write((short)itemId);
|
||||
w.Write((short)fromPoint.X);
|
||||
w.Write((short)fromPoint.Y);
|
||||
w.Write((sbyte)fromPoint.Z);
|
||||
w.Write((short)toPoint.X);
|
||||
w.Write((short)toPoint.Y);
|
||||
w.Write((sbyte)toPoint.Z);
|
||||
w.Write((byte)speed);
|
||||
w.Write((byte)duration);
|
||||
w.Position += 2;
|
||||
// w.Write((byte)0);
|
||||
// w.Write((byte)0);
|
||||
w.Write(fixedDirection);
|
||||
w.Write(explode);
|
||||
w.Write(hue);
|
||||
w.Write(renderMode);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendScreenEffect(NetState ns, ScreenEffectType screen)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]);
|
||||
w.Write((byte)0xC0); // Packet ID
|
||||
|
||||
w.Write((byte)0x04);
|
||||
w.Position += 8;
|
||||
w.Write((short)screen);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendScreenOldEffect(NetState ns, ScreenEffectType screen)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[OldEffectPacketLength]);
|
||||
w.Write((byte)0x70); // Packet ID
|
||||
|
||||
w.Write((byte)0x04);
|
||||
w.Position += 8;
|
||||
w.Write((short)screen);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(NetState ns, IEntity target)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]);
|
||||
w.Write((byte)0xC0); // Packet ID
|
||||
|
||||
w.Write((byte)0x01);
|
||||
w.Write(target.Serial);
|
||||
w.Position += 6;
|
||||
w.Write((short)target.X);
|
||||
w.Write((short)target.Y);
|
||||
w.Write((sbyte)target.Z);
|
||||
w.Write((short)target.X);
|
||||
w.Write((short)target.Y);
|
||||
w.Write((sbyte)target.Z);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendOldBoltEffect(NetState ns, IEntity target)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[OldEffectPacketLength]);
|
||||
w.Write((byte)0x70); // Packet ID
|
||||
|
||||
w.Write((byte)0x01);
|
||||
w.Write(target.Serial);
|
||||
w.Position += 6;
|
||||
w.Write((short)target.X);
|
||||
w.Write((short)target.Y);
|
||||
w.Write((sbyte)target.Z);
|
||||
w.Write((short)target.X);
|
||||
w.Write((short)target.Y);
|
||||
w.Write((sbyte)target.Z);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendEffect(NetState ns, EffectType type, Serial from, Serial to, int itemId,
|
||||
IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[HuedEffectPacketLength]);
|
||||
w.Write((byte)0xC0); // Packet ID
|
||||
|
||||
w.Write((byte)type);
|
||||
w.Write(from);
|
||||
w.Write(to);
|
||||
w.Write((short)itemId);
|
||||
w.Write((short)fromPoint.X);
|
||||
w.Write((short)fromPoint.Y);
|
||||
w.Write((sbyte)fromPoint.Z);
|
||||
w.Write((short)toPoint.X);
|
||||
w.Write((short)toPoint.Y);
|
||||
w.Write((sbyte)toPoint.Z);
|
||||
w.Write((byte)speed);
|
||||
w.Write((byte)duration);
|
||||
w.Position += 2;
|
||||
// w.Write((byte)0);
|
||||
// w.Write((byte)0);
|
||||
w.Write(fixedDirection);
|
||||
w.Write(explode);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendOldEffect(NetState ns, EffectType type, Serial from, Serial to, int itemId,
|
||||
IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[OldEffectPacketLength]);
|
||||
w.Write((byte)0x70); // Packet ID
|
||||
|
||||
w.Write((byte)type);
|
||||
w.Write(from);
|
||||
w.Write(to);
|
||||
w.Write((short)itemId);
|
||||
w.Write((short)fromPoint.X);
|
||||
w.Write((short)fromPoint.Y);
|
||||
w.Write((sbyte)fromPoint.Z);
|
||||
w.Write((short)toPoint.X);
|
||||
w.Write((short)toPoint.Y);
|
||||
w.Write((sbyte)toPoint.Z);
|
||||
w.Write((byte)speed);
|
||||
w.Write((byte)duration);
|
||||
w.Position += 2;
|
||||
// w.Write((byte)0);
|
||||
// w.Write((byte)0);
|
||||
w.Write(fixedDirection);
|
||||
w.Write(explode);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendLocationParticleEffect(NetState ns, IEntity e, int itemId, int speed, int duration, int hue, int renderMode,
|
||||
int effect, int unknown)
|
||||
{
|
||||
SendParticalEffect(ns, EffectType.FixedXYZ, e.Serial, Serial.Zero, itemId, e.Location, e.Location, speed, duration,
|
||||
true, false, hue, renderMode, effect, 1, 0, e.Serial, 255, unknown);
|
||||
}
|
||||
|
||||
public static void SendLocationHuedEffect(NetState ns, IPoint3D p, int itemId, int speed, int duration, int hue, int renderMode)
|
||||
{
|
||||
SendHuedEffect(ns, EffectType.FixedXYZ, Serial.Zero, Serial.Zero, itemId, p, p, speed, duration, true, false,
|
||||
hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendMovingParticleEffect(NetState ns, IEntity from, IEntity to, int itemId, int speed, int duration, bool fixedDirection,
|
||||
bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer,
|
||||
int unknown)
|
||||
{
|
||||
SendParticalEffect(ns, EffectType.Moving, from.Serial, to.Serial, itemId, from.Location, to.Location, speed,
|
||||
duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, Serial.Zero,
|
||||
(int)layer, unknown);
|
||||
}
|
||||
|
||||
public static void SendMovingHuedEffect(NetState ns, IEntity from, IEntity to, int itemId, int speed, int duration, bool fixedDirection,
|
||||
bool explodes, int hue, int renderMode)
|
||||
{
|
||||
SendHuedEffect(ns, EffectType.Moving, from.Serial, to.Serial, itemId, from.Location,
|
||||
to.Location, speed, duration, fixedDirection, explodes, hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendMovingHuedEffect(NetState ns, IPoint3D from, IPoint3D to, int itemId, int speed, int duration, bool fixedDirection,
|
||||
bool explodes, int hue, int renderMode)
|
||||
{
|
||||
SendHuedEffect(ns, EffectType.Moving, Serial.Zero, Serial.Zero, itemId, from,
|
||||
to, speed, duration, fixedDirection, explodes, hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendTargetParticleEffect(NetState ns, IEntity e, int itemId, int speed, int duration, int hue, int renderMode,
|
||||
int effect, int layer, int unknown)
|
||||
{
|
||||
SendParticalEffect(ns, EffectType.FixedFrom, e.Serial, Serial.Zero, itemId, e.Location, e.Location,
|
||||
speed, duration, true, false, hue, renderMode, effect, 1, 0, e.Serial, layer, unknown);
|
||||
}
|
||||
|
||||
public static void SendTargetHuedEffect(NetState ns, IEntity e, int itemId, int speed, int duration, int hue, int renderMode)
|
||||
{
|
||||
SendHuedEffect(ns, EffectType.FixedFrom, e.Serial, Serial.Zero, itemId, e.Location, e.Location, speed, duration,
|
||||
true, false, hue, renderMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using Server.Buffers;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public interface IGumpWriter
|
||||
{
|
||||
int TextEntries { get; set; }
|
||||
int Switches { get; set; }
|
||||
ArrayBufferWriter<byte> Layout { get; }
|
||||
|
||||
int Intern(string value);
|
||||
void WriteStrings(List<string> strings);
|
||||
void Flush(NetState ns);
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendCloseGump(NetState ns, int typeId, int buttonId)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[13]);
|
||||
w.Write((byte)0xBF); // Packet ID
|
||||
w.Write((short)13); // Length
|
||||
|
||||
w.Write((short)0x04); // Command
|
||||
w.Write(typeId);
|
||||
w.Write(buttonId);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplayGump(NetState ns, Gump g, string layout, string[] text)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
layout ??= "";
|
||||
|
||||
// Assume no longer than 128 characters per text element
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[20 + layout.Length + 1 + (258 * text?.Length ?? 0)]);
|
||||
w.Write((byte)0xB0); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
w.Write(g.Serial);
|
||||
w.Write(g.TypeID);
|
||||
w.Write(g.X);
|
||||
w.Write(g.Y);
|
||||
w.Write((ushort)(layout.Length + 1));
|
||||
w.WriteAsciiNull(layout);
|
||||
|
||||
w.Write((ushort)(text?.Length ?? 0));
|
||||
|
||||
for (int i = 0; i < text?.Length; ++i)
|
||||
{
|
||||
string v = text[i] ?? "";
|
||||
|
||||
ushort length = (ushort)v.Length;
|
||||
|
||||
w.Write(length);
|
||||
w.WriteBigUni(v);
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplaySignGump(NetState ns, Serial serial, int gumpId, string unknown, string caption)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 14 + caption.Length + unknown.Length;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x8B); // Packet ID
|
||||
w.Write((short)length);
|
||||
|
||||
w.Write(serial);
|
||||
w.Write((short)gumpId);
|
||||
w.Write((short)unknown.Length);
|
||||
w.WriteAsciiFixed(unknown, unknown.Length);
|
||||
w.Write((short)(caption.Length + 1));
|
||||
w.WriteAsciiFixed(caption, caption.Length);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,330 +0,0 @@
|
|||
using Server.Buffers;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public enum LRReason : byte
|
||||
{
|
||||
CannotLift,
|
||||
OutOfRange,
|
||||
OutOfSight,
|
||||
TryToSteal,
|
||||
AreHolding,
|
||||
Unspecific
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendWorldItem(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.HighSeas)
|
||||
SendWorldItemHS(ns, item);
|
||||
else if (ns.StygianAbyss)
|
||||
SendWorldItemSA(ns, item);
|
||||
else
|
||||
SendWorldItemOld(ns, item);
|
||||
}
|
||||
|
||||
public static void SendWorldItemOld(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[20]);
|
||||
w.Write((byte)0x1A); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
uint serial = item.Serial.Value;
|
||||
int itemId = item.ItemID & 0x3FFF;
|
||||
int amount = item.Amount;
|
||||
Point3D loc = item.Location;
|
||||
int x = loc.m_X;
|
||||
int y = loc.m_Y;
|
||||
int hue = item.Hue;
|
||||
int flags = item.GetPacketFlags();
|
||||
int direction = (int)item.Direction;
|
||||
|
||||
if (amount != 0)
|
||||
serial |= 0x80000000;
|
||||
else
|
||||
serial &= 0x7FFFFFFF;
|
||||
|
||||
w.Write(serial);
|
||||
|
||||
if (item is BaseMulti)
|
||||
w.Write((short)(itemId | 0x4000));
|
||||
else
|
||||
w.Write((short)itemId);
|
||||
|
||||
if (amount != 0)
|
||||
w.Write((short)amount);
|
||||
|
||||
x &= 0x7FFF;
|
||||
|
||||
if (direction != 0) x |= 0x8000;
|
||||
|
||||
w.Write((short)x);
|
||||
|
||||
y &= 0x3FFF;
|
||||
|
||||
if (hue != 0) y |= 0x8000;
|
||||
|
||||
if (flags != 0) y |= 0x4000;
|
||||
|
||||
w.Write((short)y);
|
||||
|
||||
if (direction != 0)
|
||||
w.Write((byte)direction);
|
||||
|
||||
w.Write((sbyte)loc.m_Z);
|
||||
|
||||
if (hue != 0)
|
||||
w.Write((ushort)hue);
|
||||
|
||||
if (flags != 0)
|
||||
w.Write((byte)flags);
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendWorldItemSA(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[24]);
|
||||
w.Write((byte)0xF3); // Packet ID
|
||||
|
||||
w.Write((short)0x01);
|
||||
|
||||
int itemId = item.ItemID;
|
||||
|
||||
if (item is BaseMulti)
|
||||
{
|
||||
w.Write((byte)0x02);
|
||||
|
||||
w.Write(item.Serial);
|
||||
|
||||
itemId &= 0x3FFF;
|
||||
|
||||
w.Write((short)itemId);
|
||||
|
||||
w.Position++; // w.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
w.Position++; // w.Write((byte)0);
|
||||
|
||||
w.Write(item.Serial);
|
||||
|
||||
itemId &= 0x7FFF;
|
||||
|
||||
w.Write((short)itemId);
|
||||
|
||||
w.Write((byte)item.Direction);
|
||||
}
|
||||
|
||||
short amount = (short)item.Amount;
|
||||
w.Write(amount);
|
||||
w.Write(amount);
|
||||
|
||||
Point3D loc = item.Location;
|
||||
w.Write((short)(loc.m_X & 0x7FFF));
|
||||
w.Write((short)(loc.m_Y & 0x3FFF));
|
||||
w.Write((sbyte)loc.m_Z);
|
||||
|
||||
w.Write((byte)item.Light);
|
||||
w.Write((short)item.Hue);
|
||||
w.Write((byte)item.GetPacketFlags());
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendWorldItemHS(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[26]);
|
||||
w.Write((byte)0xF3); // Packet ID
|
||||
|
||||
w.Write((short)0x01);
|
||||
|
||||
int itemId = item.ItemID;
|
||||
|
||||
if (item is BaseMulti)
|
||||
{
|
||||
w.Write((byte)0x02);
|
||||
|
||||
w.Write(item.Serial);
|
||||
|
||||
itemId &= 0x3FFF;
|
||||
|
||||
w.Write((short)itemId);
|
||||
|
||||
w.Position++; // w.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
w.Position++; // w.Write((byte)0);
|
||||
|
||||
w.Write(item.Serial);
|
||||
|
||||
itemId &= 0x7FFF;
|
||||
|
||||
w.Write((short)itemId);
|
||||
|
||||
w.Write((byte)item.Direction);
|
||||
}
|
||||
|
||||
short amount = (short)item.Amount;
|
||||
w.Write(amount);
|
||||
w.Write(amount);
|
||||
|
||||
Point3D loc = item.Location;
|
||||
w.Write((short)(loc.m_X & 0x7FFF));
|
||||
w.Write((short)(loc.m_Y & 0x3FFF));
|
||||
w.Write((sbyte)loc.m_Z);
|
||||
|
||||
w.Write((byte)item.Light);
|
||||
w.Write((short)item.Hue);
|
||||
w.Write((byte)item.GetPacketFlags());
|
||||
w.Position += 2;
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendLiftRej(NetState ns, LRReason reason)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x27, // Packet ID
|
||||
(byte)reason
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendSpellbookContent(NetState ns, Serial s, int count, int offset, ulong content)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ObjectPropertyList.Enabled && ns.NewSpellbook)
|
||||
SendSpellbookContentNew(ns, s, count, offset, content);
|
||||
else if (ns.ContainerGridLines)
|
||||
SendSpellbookContent6017(ns, s, count, offset, content);
|
||||
else
|
||||
SendSpellbookContentOld(ns, s, count, offset, content);
|
||||
}
|
||||
|
||||
public static void SendSpellbookContentOld(NetState ns, Serial s, int count, int offset, ulong content)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 5 + count * 19;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
// This should always be the same as written
|
||||
w.Write((ushort)count);
|
||||
|
||||
ulong mask = 1;
|
||||
|
||||
for (int i = 0; i < 64; ++i, mask <<= 1)
|
||||
if ((content & mask) != 0)
|
||||
{
|
||||
w.Write(0x7FFFFFFF - i);
|
||||
w.Position += 3;
|
||||
w.Write((ushort)(i + offset));
|
||||
w.Position += 4;
|
||||
w.Write(s);
|
||||
w.Position += 2;
|
||||
}
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSpellbookContent6017(NetState ns, Serial s, int count, int offset, ulong content)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 5 + count * 20;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
// This should always be the same as written
|
||||
w.Write((ushort)count);
|
||||
|
||||
ulong mask = 1;
|
||||
|
||||
for (int i = 0; i < 64; ++i, mask <<= 1)
|
||||
if ((content & mask) != 0)
|
||||
{
|
||||
w.Write(0x7FFFFFFF - i);
|
||||
w.Position += 3;
|
||||
w.Write((ushort)(i + offset));
|
||||
w.Position += 5; // Grid Location?
|
||||
w.Write(s);
|
||||
w.Position += 2;
|
||||
}
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSpellbookContentNew(NetState ns, Serial s, int graphic, int offset, ulong content)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[23]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Write((short)23); // Length
|
||||
|
||||
|
||||
w.Write((short)0x1B);
|
||||
w.Write((short)0x01);
|
||||
|
||||
w.Write(s);
|
||||
w.Write((short)graphic);
|
||||
w.Write((short)offset);
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
w.Write((byte)(content >> (i * 8)));
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDragEffect(NetState ns, IEntity src, IEntity trg, int itemID, int hue, int amount)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[26]);
|
||||
w.Write((byte)0x23); // Packet ID
|
||||
|
||||
w.Write((short)itemID);
|
||||
w.Position++; // w.Write((byte)0);
|
||||
w.Write((short)hue);
|
||||
w.Write((short)amount);
|
||||
w.Write(src.Serial);
|
||||
w.Write((short)src.X);
|
||||
w.Write((short)src.Y);
|
||||
w.Write((sbyte)src.Z);
|
||||
w.Write(trg.Serial);
|
||||
w.Write((short)trg.X);
|
||||
w.Write((short)trg.Y);
|
||||
w.Write((sbyte)trg.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
private static byte[] m_MapPatchesPacket;
|
||||
|
||||
public static void SendMapPatches(NetState ns)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (m_MapPatchesPacket == null)
|
||||
{
|
||||
SpanWriter w = new SpanWriter(m_MapPatchesPacket = new byte[57]);
|
||||
w.Write((byte)0xBF); // Extended Packet ID
|
||||
w.Write((ushort)57); // Dynamic Length
|
||||
|
||||
w.Write((short)0x18); // Map Patches
|
||||
w.Write(6); // Map count
|
||||
|
||||
w.Write(Map.Felucca.Tiles.Patch.StaticBlocks);
|
||||
w.Write(Map.Felucca.Tiles.Patch.LandBlocks);
|
||||
|
||||
w.Write(Map.Trammel.Tiles.Patch.StaticBlocks);
|
||||
w.Write(Map.Trammel.Tiles.Patch.LandBlocks);
|
||||
|
||||
w.Write(Map.Ilshenar.Tiles.Patch.StaticBlocks);
|
||||
w.Write(Map.Ilshenar.Tiles.Patch.LandBlocks);
|
||||
|
||||
w.Write(Map.Malas.Tiles.Patch.StaticBlocks);
|
||||
w.Write(Map.Malas.Tiles.Patch.LandBlocks);
|
||||
|
||||
w.Write(Map.Tokuno.Tiles.Patch.StaticBlocks);
|
||||
w.Write(Map.Tokuno.Tiles.Patch.LandBlocks);
|
||||
|
||||
w.Write(Map.TerMur.Tiles.Patch.StaticBlocks);
|
||||
w.Write(Map.TerMur.Tiles.Patch.LandBlocks);
|
||||
}
|
||||
|
||||
ns.Send(m_MapPatchesPacket);
|
||||
}
|
||||
|
||||
private static readonly byte[][][] _seasonChangePackets = {
|
||||
new byte[2][], new byte[2][], new byte[2][], new byte[2][], new byte[2][]
|
||||
};
|
||||
|
||||
public static void SendSeasonChange(NetState ns, byte season, byte playSound)
|
||||
{
|
||||
ns?.Send(_seasonChangePackets[season][playSound] ??= new byte[]
|
||||
{
|
||||
0xBC, // Packet ID
|
||||
season,
|
||||
playSound
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendMapChange(NetState ns, Map map)
|
||||
{
|
||||
ns?.Send(stackalloc byte[6]
|
||||
{
|
||||
0xBF, // Extended Packet ID
|
||||
0x00,
|
||||
0x06, // Length
|
||||
0x00,
|
||||
0x08, // Command
|
||||
(byte)(map?.MapID ?? 0)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,235 +0,0 @@
|
|||
using System;
|
||||
using Server.Buffers;
|
||||
using Server.ContextMenus;
|
||||
using Server.Menus;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
[Flags]
|
||||
public enum CMEFlags
|
||||
{
|
||||
None = 0x00,
|
||||
Disabled = 0x01,
|
||||
Arrow = 0x02,
|
||||
Highlighted = 0x04,
|
||||
Colored = 0x20
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDisplayItemListMenu(NetState ns, ItemListMenu menu)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
// 10 + 128 + (255 * (128 + 5))
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[138 + menu.Entries.Length * 133]);
|
||||
w.Write((byte)0x7C); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
w.Write(menu.Serial);
|
||||
w.Position += 2; // w.Write((short)0);
|
||||
|
||||
string question = menu.Question;
|
||||
|
||||
if (question == null)
|
||||
w.Position++; // w.Write((byte)0);
|
||||
else
|
||||
{
|
||||
int questionLength = question.Length;
|
||||
w.Write((byte)questionLength);
|
||||
w.WriteAsciiFixed(question, questionLength);
|
||||
}
|
||||
|
||||
ItemListEntry[] entries = menu.Entries;
|
||||
|
||||
int entriesLength = (byte)entries.Length;
|
||||
|
||||
w.Write((byte)entriesLength);
|
||||
|
||||
for (int i = 0; i < entriesLength; ++i)
|
||||
{
|
||||
ItemListEntry e = entries[i];
|
||||
|
||||
w.Write((ushort)e.ItemID);
|
||||
w.Write((short)e.Hue);
|
||||
|
||||
string name = e.Name;
|
||||
|
||||
if (name == null)
|
||||
w.Position++; // w.Write((byte)0);
|
||||
else
|
||||
{
|
||||
int nameLength = name.Length;
|
||||
w.Write((byte)nameLength);
|
||||
w.WriteAsciiFixed(name, nameLength);
|
||||
}
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplayQuestionMenu(NetState ns, QuestionMenu menu)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
// 10 + 128 + (255 * (128 + 5))
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[138 + menu.Answers.Length * 133]);
|
||||
w.Write((byte)0x7C); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
w.Write(menu.Serial);
|
||||
w.Position += 2; // w.Write((short)0);
|
||||
|
||||
string question = menu.Question;
|
||||
|
||||
if (question == null)
|
||||
w.Position++; // w.Write((byte)0);
|
||||
else
|
||||
{
|
||||
int questionLength = question.Length;
|
||||
w.Write((byte)questionLength);
|
||||
w.WriteAsciiFixed(question, questionLength);
|
||||
}
|
||||
|
||||
string[] answers = menu.Answers;
|
||||
|
||||
int answersLength = (byte)answers.Length;
|
||||
|
||||
w.Write((byte)answersLength);
|
||||
|
||||
for (int i = 0; i < answersLength; ++i)
|
||||
{
|
||||
w.Position += 4; // w.Write(0);
|
||||
|
||||
string answer = answers[i];
|
||||
|
||||
if (answer == null)
|
||||
w.Position++; // w.Write((byte)0);
|
||||
else
|
||||
{
|
||||
int answerLength = answer.Length;
|
||||
w.Write((byte)answerLength);
|
||||
w.WriteAsciiFixed(answer, answerLength);
|
||||
}
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplayContextMenu(NetState ns, ContextMenu menu)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
ContextMenuEntry[] entries = menu.Entries;
|
||||
|
||||
int length = 12 + entries.Length * 8;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xBF); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write((short)0x14); // Command
|
||||
w.Write((short)0x02);
|
||||
|
||||
IEntity target = menu.Target as IEntity;
|
||||
|
||||
w.Write(target?.Serial ?? Serial.MinusOne);
|
||||
|
||||
w.Write((byte)entries.Length);
|
||||
|
||||
Point3D p;
|
||||
|
||||
if (target is Mobile)
|
||||
p = target.Location;
|
||||
else if (target is Item item)
|
||||
p = item.GetWorldLocation();
|
||||
else
|
||||
p = Point3D.Zero;
|
||||
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
ContextMenuEntry e = entries[i];
|
||||
|
||||
w.Write(e.Number);
|
||||
w.Write((short)i);
|
||||
|
||||
int range = e.Range;
|
||||
|
||||
if (range == -1)
|
||||
range = 18;
|
||||
|
||||
w.Write((short)(e.Flags | (e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled)));
|
||||
}
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplayContextMenuOld(NetState ns, ContextMenu menu)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
ContextMenuEntry[] entries = menu.Entries;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[12 + entries.Length * 8]);
|
||||
w.Write((byte)0xBF); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
w.Write((short)0x14); // Command
|
||||
w.Write((short)0x01); // Old!
|
||||
|
||||
IEntity target = menu.Target as IEntity;
|
||||
|
||||
w.Write(target?.Serial ?? Serial.MinusOne);
|
||||
|
||||
w.Write((byte)entries.Length);
|
||||
|
||||
Point3D p;
|
||||
|
||||
if (target is Mobile)
|
||||
p = target.Location;
|
||||
else if (target is Item item)
|
||||
p = item.GetWorldLocation();
|
||||
else
|
||||
p = Point3D.Zero;
|
||||
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
ContextMenuEntry e = entries[i];
|
||||
|
||||
w.Write((short)i);
|
||||
w.Write((ushort)(e.Number - 3000000));
|
||||
|
||||
int range = e.Range;
|
||||
|
||||
if (range == -1)
|
||||
range = 18;
|
||||
|
||||
CMEFlags flags = e.Flags | (e.Enabled && menu.From.InRange(p, range) ? CMEFlags.None : CMEFlags.Disabled);
|
||||
|
||||
int color = e.Color & 0xFFFF;
|
||||
|
||||
if (color != 0xFFFF)
|
||||
flags |= CMEFlags.Colored;
|
||||
|
||||
w.Write((short)flags);
|
||||
|
||||
if ((flags & CMEFlags.Colored) != 0)
|
||||
w.Write((short)color);
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
[Flags]
|
||||
public enum AffixType : byte
|
||||
{
|
||||
Append = 0x00,
|
||||
Prepend = 0x01,
|
||||
System = 0x02
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
private static readonly Dictionary<int, byte[]> _messageLocalizedPackets = new Dictionary<int, byte[]>();
|
||||
|
||||
public static void SendMessageLocalized(NetState ns, int number)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (_messageLocalizedPackets.TryGetValue(number, out byte[] packet))
|
||||
{
|
||||
ns.Send(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
SpanWriter w = new SpanWriter(packet = new byte[50]);
|
||||
w.Write((byte)0xC1); // Packet ID
|
||||
w.Write((short)50); // Length
|
||||
|
||||
w.Write(Serial.MinusOne);
|
||||
w.Write((short)-1);
|
||||
w.Position++; // w.Write((byte)MessageType.Regular);
|
||||
w.Write((short)0x3B2);
|
||||
w.Write((short)3);
|
||||
w.Write(number);
|
||||
w.WriteAsciiFixed("System", 30);
|
||||
|
||||
_messageLocalizedPackets[number] = packet;
|
||||
|
||||
ns.Send(packet);
|
||||
}
|
||||
|
||||
public static void SendMessageLocalized(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, int number, string name = "",
|
||||
string args = "")
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 50 + args.Length * 2;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xC1); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
if (hue == 0) hue = 0x3B2;
|
||||
|
||||
w.Write(serial);
|
||||
w.Write((short)graphic);
|
||||
w.Write((byte)type);
|
||||
w.Write((short)hue);
|
||||
w.Write((short)font);
|
||||
w.Write(number);
|
||||
w.WriteAsciiFixed(name ?? "", 30);
|
||||
w.WriteLittleUniNull(args);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMessageLocalizedAffix(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, int number,
|
||||
string name = "", AffixType affixType = AffixType.System, string affix = "", string args = "")
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
affix ??= "";
|
||||
args ??= "";
|
||||
|
||||
if (hue == 0) hue = 0x3B2;
|
||||
|
||||
int length = 52 + affix.Length + args.Length * 2;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xCC); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write(serial);
|
||||
w.Write((short)graphic);
|
||||
w.Write((byte)type);
|
||||
w.Write((short)hue);
|
||||
w.Write((short)font);
|
||||
w.Write(number);
|
||||
w.Write((byte)affixType);
|
||||
w.WriteAsciiFixed(name ?? "", 30);
|
||||
w.WriteAsciiNull(affix);
|
||||
w.WriteBigUniNull(args); // Not little endian? Ugh
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
// TODO: Handle IEnumerable<NetState>
|
||||
public static void SendAsciiMessage(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, string name, string text)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
text ??= "";
|
||||
|
||||
if (hue == 0) hue = 0x3B2;
|
||||
|
||||
int length = 45 + text.Length;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x1C); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write(serial);
|
||||
w.Write((short)graphic);
|
||||
w.Write((byte)type);
|
||||
w.Write((short)hue);
|
||||
w.Write((short)font);
|
||||
w.WriteAsciiFixed(name ?? "", 30);
|
||||
w.WriteAsciiNull(text);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
// TODO: Handle IEnumerable<NetState>
|
||||
public static void SendUnicodeMessage(NetState ns, Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name,
|
||||
string text)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(lang)) lang = "ENU";
|
||||
name ??= "";
|
||||
text ??= "";
|
||||
if (hue == 0) hue = 0x3B2;
|
||||
|
||||
int length = 50 + text.Length * 2;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xAE); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write(serial);
|
||||
w.Write((short)graphic);
|
||||
w.Write((byte)type);
|
||||
w.Write((short)hue);
|
||||
w.Write((short)font);
|
||||
w.WriteAsciiFixed(lang, 4);
|
||||
w.WriteAsciiFixed(name, 30);
|
||||
w.WriteBigUniNull(text);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,959 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Buffers;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDeathAnimation(NetState ns, Serial killed, Serial corpse)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[13]);
|
||||
w.Write((byte)0xAF); // Packet ID
|
||||
|
||||
w.Write(killed);
|
||||
w.Write(corpse);
|
||||
w.Position++; w.Write(0);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendStatLockInfo(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[12]);
|
||||
w.Write((byte)0xBF); // Extended Packet ID
|
||||
w.Write((short)12); // Length
|
||||
|
||||
w.Write((short)0x19); // Subcommand
|
||||
w.Write((byte)2);
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)((int)m.StrLock << 4 | (int)m.DexLock << 2 | (int)m.IntLock));
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendBondStatus(NetState ns, Serial m, bool bonded)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[11]);
|
||||
w.Write((byte)0xBF); // Extended Packet ID
|
||||
w.Write((short)11); // Length
|
||||
|
||||
w.Write((short)0x19); // Command
|
||||
w.Position++; // w.Write((byte)0); // Subcommand
|
||||
w.Write(m);
|
||||
w.Write(bonded);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendPersonalLightLevel(NetState ns, Serial m, sbyte level)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[6]);
|
||||
w.Write((byte)0x4E); // Packet ID
|
||||
|
||||
w.Write(m);
|
||||
w.Write(level);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendPersonalLightLevelZero(NetState ns, Serial m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[6]);
|
||||
w.Write((byte)0x4E); // Packet ID
|
||||
|
||||
w.Write(m);
|
||||
w.Position++; // level 0
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendEquipUpdate(NetState ns, Item item)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[15]);
|
||||
w.Write((byte)0x2E); // Packet ID
|
||||
|
||||
Serial parentSerial = Serial.Zero;
|
||||
int hue = item.Hue;
|
||||
|
||||
if (item.Parent is Mobile parent)
|
||||
{
|
||||
parentSerial = parent.Serial;
|
||||
if (parent.SolidHueOverride >= 0)
|
||||
hue = parent.SolidHueOverride;
|
||||
}
|
||||
else
|
||||
Console.WriteLine("Warning: EquipUpdate on item with an invalid parent");
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((short)item.ItemID);
|
||||
w.Write((short)item.Layer);
|
||||
w.Write(parentSerial);
|
||||
w.Write((short)hue);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSwing(NetState ns, Serial attacker, Serial defender)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[10]);
|
||||
w.Write((byte)0x2F); // Packet ID
|
||||
|
||||
w.Position++; // ?
|
||||
w.Write(attacker);
|
||||
w.Write(defender);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileMoving(NetState ns, Mobile m, int noto)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
SendMobileMovingNew(ns, m, noto);
|
||||
else
|
||||
SendMobileMovingOld(ns, m, noto);
|
||||
}
|
||||
|
||||
public static void SendMobileMovingNew(NetState ns, Mobile m, int noto)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[17]);
|
||||
w.Write((byte)0x77); // Packet ID
|
||||
|
||||
Point3D loc = m.Location;
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.Body);
|
||||
w.Write((short)loc.m_X);
|
||||
w.Write((short)loc.m_Y);
|
||||
w.Write((sbyte)loc.m_Z);
|
||||
w.Write((byte)m.Direction);
|
||||
w.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.Hue));
|
||||
w.Write((byte)m.GetPacketFlags());
|
||||
w.Write((byte)noto);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileMovingOld(NetState ns, Mobile m, int noto)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[17]);
|
||||
w.Write((byte)0x77); // Packet ID
|
||||
|
||||
Point3D loc = m.Location;
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.Body);
|
||||
w.Write((short)loc.m_X);
|
||||
w.Write((short)loc.m_Y);
|
||||
w.Write((sbyte)loc.m_Z);
|
||||
w.Write((byte)m.Direction);
|
||||
w.Write((short)(m.SolidHueOverride >= 0 ? m.SolidHueOverride : m.Hue));
|
||||
w.Write((byte)m.GetOldPacketFlags());
|
||||
w.Write((byte)noto);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplayPaperdoll(NetState ns, Mobile m, string text, bool canLift)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[66]);
|
||||
w.Write((byte)0x88); // Packet ID
|
||||
|
||||
byte flags = 0x00;
|
||||
|
||||
if (m.Warmode)
|
||||
flags |= 0x01;
|
||||
|
||||
if (canLift)
|
||||
flags |= 0x02;
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.WriteAsciiFixed(text, 60);
|
||||
w.Write(flags);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileName(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[37]);
|
||||
w.Write((byte)0x98); // Packet ID
|
||||
w.Write((ushort)37); // Dynamic Length
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.WriteAsciiFixed(m.Name ?? "", 30);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileAnimation(NetState ns, Mobile m, int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[14]);
|
||||
w.Write((byte)0x6E); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)action);
|
||||
w.Write((short)frameCount);
|
||||
w.Write((short)repeatCount);
|
||||
w.Write(!forward); // protocol has really "reverse" but I find this more intuitive
|
||||
w.Write(repeat);
|
||||
w.Write((byte)delay);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendNewMobileAnimation(NetState ns, Mobile m, int action, int frameCount, int delay)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[10]);
|
||||
w.Write((byte)0xE2); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)action);
|
||||
w.Write((short)frameCount);
|
||||
w.Write((byte)delay);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileStatusCompact(NetState ns, Mobile m, bool canBeRenamed = false)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[43]);
|
||||
w.Write((byte)0x11); // Packet ID
|
||||
w.Write((ushort)43); // Length
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.WriteAsciiFixed(m.Name ?? "", 30);
|
||||
|
||||
AttributeNormalizer.WriteReverse(w, m.Hits, m.HitsMax);
|
||||
|
||||
w.Write(canBeRenamed);
|
||||
|
||||
w.Position++; // type
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileStatusExtended(NetState to, Mobile m)
|
||||
{
|
||||
SendMobileStatusExtended(to, m, m.NetState);
|
||||
}
|
||||
|
||||
public static void SendMobileStatusExtended(NetState to, Mobile m, NetState ns)
|
||||
{
|
||||
if (to == null)
|
||||
return;
|
||||
|
||||
byte type;
|
||||
short length;
|
||||
|
||||
if (Core.HS && ns?.ExtendedStatus == true)
|
||||
{
|
||||
type = 6;
|
||||
length = 121;
|
||||
}
|
||||
else if (Core.ML && ns?.SupportsExpansion(Expansion.ML) == true)
|
||||
{
|
||||
type = 5;
|
||||
length = 91;
|
||||
}
|
||||
else if (Core.AOS)
|
||||
{
|
||||
type = 4;
|
||||
length = 88;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 3;
|
||||
length = 70;
|
||||
}
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x11); // Packet ID
|
||||
w.Write(length); // Length
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.WriteAsciiFixed(m.Name ?? "", 30);
|
||||
|
||||
w.Write((short)m.Hits);
|
||||
w.Write((short)m.HitsMax);
|
||||
|
||||
w.Write(m.CanBeRenamedBy(m));
|
||||
|
||||
w.Write(type);
|
||||
|
||||
w.Write(m.Female);
|
||||
|
||||
w.Write((short)m.Str);
|
||||
w.Write((short)m.Dex);
|
||||
w.Write((short)m.Int);
|
||||
|
||||
w.Write((short)m.Stam);
|
||||
w.Write((short)m.StamMax);
|
||||
|
||||
w.Write((short)m.Mana);
|
||||
w.Write((short)m.ManaMax);
|
||||
|
||||
w.Write(m.TotalGold);
|
||||
w.Write((short)(Core.AOS ? m.PhysicalResistance : (int)(m.ArmorRating + 0.5)));
|
||||
w.Write((short)(Mobile.BodyWeight + m.TotalWeight));
|
||||
|
||||
if (type >= 5)
|
||||
{
|
||||
w.Write((short)m.MaxWeight);
|
||||
w.Write((byte)(m.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but...
|
||||
}
|
||||
|
||||
w.Write((short)m.StatCap);
|
||||
|
||||
w.Write((byte)m.Followers);
|
||||
w.Write((byte)m.FollowersMax);
|
||||
|
||||
if (type >= 4)
|
||||
{
|
||||
w.Write((short)m.FireResistance); // Fire
|
||||
w.Write((short)m.ColdResistance); // Cold
|
||||
w.Write((short)m.PoisonResistance); // Poison
|
||||
w.Write((short)m.EnergyResistance); // Energy
|
||||
w.Write((short)m.Luck); // Luck
|
||||
|
||||
IWeapon weapon = m.Weapon;
|
||||
|
||||
if (weapon != null)
|
||||
{
|
||||
weapon.GetStatusDamage(m, out int min, out int max);
|
||||
w.Write((short)min); // Damage min
|
||||
w.Write((short)max); // Damage max
|
||||
}
|
||||
else
|
||||
w.Position += 4; // Damage min, Damage max
|
||||
|
||||
w.Write(m.TithingPoints);
|
||||
}
|
||||
|
||||
if (type >= 6)
|
||||
for (int i = 0; i < 15; ++i)
|
||||
w.Write((short)m.GetAOSStatus(i));
|
||||
|
||||
to.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileStatus(NetState to, Mobile beholder, Mobile beheld)
|
||||
{
|
||||
SendMobileStatus(to, beholder, beheld, beheld.NetState);
|
||||
}
|
||||
|
||||
public static void SendMobileStatus(NetState to, Mobile beholder, Mobile beheld, NetState ns)
|
||||
{
|
||||
if (to == null)
|
||||
return;
|
||||
|
||||
int type;
|
||||
short length;
|
||||
|
||||
if (beholder != beheld)
|
||||
{
|
||||
type = 0;
|
||||
length = 43;
|
||||
}
|
||||
else if (Core.HS && ns?.ExtendedStatus == true)
|
||||
{
|
||||
type = 6;
|
||||
length = 121;
|
||||
}
|
||||
else if (Core.ML && ns?.SupportsExpansion(Expansion.ML) == true)
|
||||
{
|
||||
type = 5;
|
||||
length = 91;
|
||||
}
|
||||
else if (Core.AOS)
|
||||
{
|
||||
type = 4;
|
||||
length = 88;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 3;
|
||||
length = 70;
|
||||
}
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x11); // Packet ID
|
||||
w.Write((ushort)length); // Length
|
||||
|
||||
w.Write(beheld.Serial);
|
||||
|
||||
w.WriteAsciiFixed(beheld.Name ?? "", 30);
|
||||
|
||||
if (beholder == beheld)
|
||||
{
|
||||
w.Write((short)beheld.Hits);
|
||||
w.Write((short)beheld.HitsMax);
|
||||
}
|
||||
else
|
||||
AttributeNormalizer.WriteReverse(w, beheld.Hits, beheld.HitsMax);
|
||||
|
||||
w.Write(beheld.CanBeRenamedBy(beholder));
|
||||
|
||||
w.Write((byte)type);
|
||||
|
||||
if (type <= 0)
|
||||
return;
|
||||
|
||||
w.Write(beheld.Female);
|
||||
|
||||
w.Write((short)beheld.Str);
|
||||
w.Write((short)beheld.Dex);
|
||||
w.Write((short)beheld.Int);
|
||||
|
||||
w.Write((short)beheld.Stam);
|
||||
w.Write((short)beheld.StamMax);
|
||||
|
||||
w.Write((short)beheld.Mana);
|
||||
w.Write((short)beheld.ManaMax);
|
||||
|
||||
w.Write(beheld.TotalGold);
|
||||
w.Write((short)(Core.AOS ? beheld.PhysicalResistance : (int)(beheld.ArmorRating + 0.5)));
|
||||
w.Write((short)(Mobile.BodyWeight + beheld.TotalWeight));
|
||||
|
||||
if (type >= 5)
|
||||
{
|
||||
w.Write((short)beheld.MaxWeight);
|
||||
w.Write((byte)(beheld.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but...
|
||||
}
|
||||
|
||||
w.Write((short)beheld.StatCap);
|
||||
|
||||
w.Write((byte)beheld.Followers);
|
||||
w.Write((byte)beheld.FollowersMax);
|
||||
|
||||
if (type >= 4)
|
||||
{
|
||||
w.Write((short)beheld.FireResistance); // Fire
|
||||
w.Write((short)beheld.ColdResistance); // Cold
|
||||
w.Write((short)beheld.PoisonResistance); // Poison
|
||||
w.Write((short)beheld.EnergyResistance); // Energy
|
||||
w.Write((short)beheld.Luck); // Luck
|
||||
|
||||
IWeapon weapon = beheld.Weapon;
|
||||
|
||||
if (weapon != null)
|
||||
{
|
||||
weapon.GetStatusDamage(beheld, out int min, out int max);
|
||||
w.Write((short)min); // Damage min
|
||||
w.Write((short)max); // Damage max
|
||||
}
|
||||
else
|
||||
w.Position += 2; // Damage min, Damage max
|
||||
|
||||
w.Write(beheld.TithingPoints);
|
||||
}
|
||||
|
||||
if (type >= 6)
|
||||
for (int i = 0; i < 15; ++i)
|
||||
w.Write((short)beheld.GetAOSStatus(i));
|
||||
|
||||
to.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendHealthbarPoison(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[12]);
|
||||
w.Write((byte)0x17); // Packet ID
|
||||
w.Write((ushort)12); // Length
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)1);
|
||||
w.Write((short)1);
|
||||
|
||||
Poison p = m.Poison;
|
||||
|
||||
if (p != null)
|
||||
w.Write((byte)(p.Level + 1));
|
||||
else
|
||||
w.Position++;
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendHealthbarYellow(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[12]);
|
||||
w.Write((byte)0x17); // Packet ID
|
||||
w.Write((ushort)12); // Length
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)1);
|
||||
w.Write((short)2);
|
||||
|
||||
w.Write(m.Blessed || m.YellowHealthbar);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileUpdate(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
SendMobileUpdateSA(ns, m);
|
||||
else
|
||||
SendMobileUpdateOld(ns, m);
|
||||
}
|
||||
|
||||
public static void SendMobileUpdateSA(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[19]);
|
||||
w.Write((byte)0x20); // Packet ID
|
||||
|
||||
int hue = m.Hue;
|
||||
|
||||
if (m.SolidHueOverride >= 0)
|
||||
hue = m.SolidHueOverride;
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.Body);
|
||||
w.Position++; // w.Write((byte)0);
|
||||
w.Write((short)hue);
|
||||
w.Write((byte)m.GetPacketFlags());
|
||||
w.Write((short)m.X);
|
||||
w.Write((short)m.Y);
|
||||
w.Position += 2; // w.Write((short)0);
|
||||
w.Write((byte)m.Direction);
|
||||
w.Write((sbyte)m.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileUpdateOld(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[19]);
|
||||
w.Write((byte)0x20); // Packet ID
|
||||
|
||||
int hue = m.Hue;
|
||||
|
||||
if (m.SolidHueOverride >= 0)
|
||||
hue = m.SolidHueOverride;
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Write((short)m.Body);
|
||||
w.Position++; // w.Write((byte)0);
|
||||
w.Write((short)hue);
|
||||
w.Write((byte)m.GetOldPacketFlags());
|
||||
w.Write((short)m.X);
|
||||
w.Write((short)m.Y);
|
||||
w.Position += 2; // w.Write((short)0);
|
||||
w.Write((byte)m.Direction);
|
||||
w.Write((sbyte)m.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileIncoming(NetState ns, Mobile beholder, Mobile beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.NewMobileIncoming)
|
||||
SendMobileIncomingNew(ns, beholder, beheld);
|
||||
else if (ns.StygianAbyss)
|
||||
SendMobileIncomingSA(ns, beholder, beheld);
|
||||
else
|
||||
SendMobileIncomingOld(ns, beholder, beheld);
|
||||
}
|
||||
|
||||
public static void SendMobileIncomingNew(NetState ns, Mobile beholder, Mobile beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
Span<bool> dupedLayers = stackalloc bool[256];
|
||||
|
||||
List<Item> eq = beheld.Items;
|
||||
int count = eq.Count;
|
||||
|
||||
if (beheld.HairItemID > 0)
|
||||
count++;
|
||||
if (beheld.FacialHairItemID > 0)
|
||||
count++;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[23 + count * 9]);
|
||||
w.Write((byte)0x78); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
int hue = beheld.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
w.Write(beheld.Serial);
|
||||
w.Write((short)beheld.Body);
|
||||
w.Write((short)beheld.X);
|
||||
w.Write((short)beheld.Y);
|
||||
w.Write((sbyte)beheld.Z);
|
||||
w.Write((byte)beheld.Direction);
|
||||
w.Write((short)hue);
|
||||
w.Write((byte)beheld.GetPacketFlags());
|
||||
w.Write(Notoriety.Compute(beholder, beheld));
|
||||
|
||||
for (int i = 0; i < eq.Count; ++i)
|
||||
{
|
||||
Item item = eq[i];
|
||||
|
||||
byte layer = (byte)item.Layer;
|
||||
|
||||
if (!item.Deleted && beholder.CanSee(item) && !dupedLayers[layer])
|
||||
{
|
||||
dupedLayers[layer] = true;
|
||||
|
||||
hue = item.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((ushort)(item.ItemID & 0xFFFF));
|
||||
w.Write(layer);
|
||||
w.Write((short)hue);
|
||||
}
|
||||
}
|
||||
|
||||
if (beheld.HairItemID > 0 && !dupedLayers[(int)Layer.Hair])
|
||||
{
|
||||
hue = beheld.HairHue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
w.Write(HairInfo.FakeSerial(beheld.Serial));
|
||||
w.Write((ushort)(beheld.HairItemID & 0xFFFF));
|
||||
w.Write((byte)Layer.Hair);
|
||||
w.Write((short)hue);
|
||||
}
|
||||
|
||||
if (beheld.FacialHairItemID > 0 && !dupedLayers[(int)Layer.FacialHair])
|
||||
{
|
||||
hue = beheld.FacialHairHue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
w.Write(FacialHairInfo.FakeSerial(beheld.Serial));
|
||||
w.Write((ushort)(beheld.FacialHairItemID & 0xFFFF));
|
||||
w.Write((byte)Layer.FacialHair);
|
||||
w.Write((short)hue);
|
||||
}
|
||||
|
||||
w.Position += 4; // w.Write(0)
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileIncomingSA(NetState ns, Mobile beholder, Mobile beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
Span<bool> dupedLayers = stackalloc bool[256];
|
||||
|
||||
List<Item> eq = beheld.Items;
|
||||
int count = eq.Count;
|
||||
|
||||
if (beheld.HairItemID > 0)
|
||||
count++;
|
||||
if (beheld.FacialHairItemID > 0)
|
||||
count++;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[23 + count * 9]);
|
||||
w.Write((byte)0x78); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
int hue = beheld.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
w.Write(beheld.Serial);
|
||||
w.Write((short)beheld.Body);
|
||||
w.Write((short)beheld.X);
|
||||
w.Write((short)beheld.Y);
|
||||
w.Write((sbyte)beheld.Z);
|
||||
w.Write((byte)beheld.Direction);
|
||||
w.Write((short)hue);
|
||||
w.Write((byte)beheld.GetPacketFlags());
|
||||
w.Write(Notoriety.Compute(beholder, beheld));
|
||||
|
||||
for (int i = 0; i < eq.Count; ++i)
|
||||
{
|
||||
Item item = eq[i];
|
||||
|
||||
byte layer = (byte)item.Layer;
|
||||
|
||||
if (!item.Deleted && beholder.CanSee(item) && !dupedLayers[layer])
|
||||
{
|
||||
dupedLayers[layer] = true;
|
||||
|
||||
hue = item.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
int itemId = item.ItemID & 0x7FFF;
|
||||
bool writeHue = hue != 0;
|
||||
|
||||
if (writeHue)
|
||||
itemId |= 0x8000;
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((ushort)itemId);
|
||||
w.Write(layer);
|
||||
|
||||
if (writeHue)
|
||||
w.Write((short)hue);
|
||||
}
|
||||
}
|
||||
|
||||
if (beheld.HairItemID > 0 && !dupedLayers[(int)Layer.Hair])
|
||||
{
|
||||
hue = beheld.HairHue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
int itemId = beheld.HairItemID & 0x7FFF;
|
||||
|
||||
bool writeHue = hue != 0;
|
||||
|
||||
if (writeHue)
|
||||
itemId |= 0x8000;
|
||||
|
||||
w.Write(HairInfo.FakeSerial(beheld.Serial));
|
||||
w.Write((ushort)itemId);
|
||||
w.Write((byte)Layer.Hair);
|
||||
|
||||
if (writeHue)
|
||||
w.Write((short)hue);
|
||||
}
|
||||
|
||||
if (beheld.FacialHairItemID > 0 && !dupedLayers[(int)Layer.FacialHair])
|
||||
{
|
||||
hue = beheld.FacialHairHue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
int itemId = beheld.FacialHairItemID & 0x7FFF;
|
||||
|
||||
bool writeHue = hue != 0;
|
||||
|
||||
if (writeHue)
|
||||
itemId |= 0x8000;
|
||||
|
||||
w.Write(FacialHairInfo.FakeSerial(beheld.Serial));
|
||||
w.Write((ushort)itemId);
|
||||
w.Write((byte)Layer.FacialHair);
|
||||
|
||||
if (writeHue)
|
||||
w.Write((short)hue);
|
||||
}
|
||||
|
||||
w.Position += 4; // w.Write(0)
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMobileIncomingOld(NetState ns, Mobile beholder, Mobile beheld)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
Span<bool> dupedLayers = stackalloc bool[256];
|
||||
|
||||
List<Item> eq = beheld.Items;
|
||||
int count = eq.Count;
|
||||
|
||||
if (beheld.HairItemID > 0)
|
||||
count++;
|
||||
if (beheld.FacialHairItemID > 0)
|
||||
count++;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[23 + count * 9]);
|
||||
w.Write((byte)0x78); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
int hue = beheld.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
w.Write(beheld.Serial);
|
||||
w.Write((short)beheld.Body);
|
||||
w.Write((short)beheld.X);
|
||||
w.Write((short)beheld.Y);
|
||||
w.Write((sbyte)beheld.Z);
|
||||
w.Write((byte)beheld.Direction);
|
||||
w.Write((short)hue);
|
||||
w.Write((byte)beheld.GetOldPacketFlags());
|
||||
w.Write(Notoriety.Compute(beholder, beheld));
|
||||
|
||||
for (int i = 0; i < eq.Count; ++i)
|
||||
{
|
||||
Item item = eq[i];
|
||||
|
||||
byte layer = (byte)item.Layer;
|
||||
|
||||
if (!item.Deleted && beholder.CanSee(item) && !dupedLayers[layer])
|
||||
{
|
||||
dupedLayers[layer] = true;
|
||||
|
||||
hue = item.Hue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
int itemId = item.ItemID & 0x7FFF;
|
||||
bool writeHue = hue != 0;
|
||||
|
||||
if (writeHue)
|
||||
itemId |= 0x8000;
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((ushort)itemId);
|
||||
w.Write(layer);
|
||||
|
||||
if (writeHue)
|
||||
w.Write((short)hue);
|
||||
}
|
||||
}
|
||||
|
||||
if (beheld.HairItemID > 0 && !dupedLayers[(int)Layer.Hair])
|
||||
{
|
||||
hue = beheld.HairHue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
int itemId = beheld.HairItemID & 0x7FFF;
|
||||
|
||||
bool writeHue = hue != 0;
|
||||
|
||||
if (writeHue)
|
||||
itemId |= 0x8000;
|
||||
|
||||
w.Write(HairInfo.FakeSerial(beheld.Serial));
|
||||
w.Write((ushort)itemId);
|
||||
w.Write((byte)Layer.Hair);
|
||||
|
||||
if (writeHue)
|
||||
w.Write((short)hue);
|
||||
}
|
||||
|
||||
if (beheld.FacialHairItemID > 0 && !dupedLayers[(int)Layer.FacialHair])
|
||||
{
|
||||
hue = beheld.FacialHairHue;
|
||||
|
||||
if (beheld.SolidHueOverride >= 0)
|
||||
hue = beheld.SolidHueOverride;
|
||||
|
||||
int itemId = beheld.FacialHairItemID & 0x7FFF;
|
||||
|
||||
bool writeHue = hue != 0;
|
||||
|
||||
if (writeHue)
|
||||
itemId |= 0x8000;
|
||||
|
||||
w.Write(FacialHairInfo.FakeSerial(beheld.Serial));
|
||||
w.Write((ushort)itemId);
|
||||
w.Write((byte)Layer.FacialHair);
|
||||
|
||||
if (writeHue)
|
||||
w.Write((short)hue);
|
||||
}
|
||||
|
||||
w.Position += 4; // w.Write(0)
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendFollowMessage(NetState ns, Serial s1, Serial s2)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0x15); // Packet ID
|
||||
|
||||
w.Write(s1);
|
||||
w.Write(s2);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,550 +0,0 @@
|
|||
using System;
|
||||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendObjectHelpResponse(NetState ns, Serial e, string text)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
text ??= "";
|
||||
|
||||
int length = 9 + text.Length * 2;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte) 0xB7); // Extended Packet ID
|
||||
w.Write((ushort) length); // Length
|
||||
|
||||
w.Write(e);
|
||||
w.WriteBigUniNull(text);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendChangeUpdateRange(NetState ns, byte range = 18)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0xC8, // Packet ID
|
||||
range
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendChangeCombatant(NetState ns, Serial combatant)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[5]);
|
||||
w.Write((byte)0xAA); // Packet ID
|
||||
|
||||
w.Write(combatant);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDisplayHuePicker(NetState ns, Serial s, int itemId)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0x95); // Packet ID
|
||||
|
||||
w.Write(s);
|
||||
w.Position += 2; // w.Write((short)0);
|
||||
w.Write((short)itemId);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendUnicodePrompt(NetState ns, Serial message)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[21]);
|
||||
w.Write((byte)0xC2); // Packet ID
|
||||
w.Write((short)21); // Length
|
||||
|
||||
w.Write(message); // Should be Player serial?
|
||||
w.Write(message);
|
||||
w.Position += 10;
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendDeathStatus_Dead(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x2C, // Packet ID
|
||||
0x00
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendDeathStatus_Alive(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x2C, // Packet ID
|
||||
0x02 // Why not 1?
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly byte[][] _speedControlPackets = new byte[3][];
|
||||
|
||||
public static void SendSpeedControlDisabled(NetState ns)
|
||||
{
|
||||
ns?.Send(_speedControlPackets[0] ??= new byte[]
|
||||
{
|
||||
0xBF, // Extended Packet ID
|
||||
0x00,
|
||||
0x06, // Length
|
||||
0x26,
|
||||
0x00 // Disabled
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendSpeedControlMount(NetState ns)
|
||||
{
|
||||
ns?.Send(_speedControlPackets[1] ??= new byte[]
|
||||
{
|
||||
0xBF, // Extended Packet ID
|
||||
0x00,
|
||||
0x06, // Length
|
||||
0x26,
|
||||
0x01 // Mount
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendSpeedControlWalk(NetState ns)
|
||||
{
|
||||
ns?.Send(_speedControlPackets[2] ??= new byte[]
|
||||
{
|
||||
0xBF, // Extended Packet ID
|
||||
0x00,
|
||||
0x06, // Length
|
||||
0x26,
|
||||
0x02 // Walk
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendToggleSpecialAbility(NetState ns, short ability, bool active)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[8]);
|
||||
w.Write((byte)0xBF); // Packet ID
|
||||
w.Write((short)8); // Length
|
||||
|
||||
w.Write((short)0x25); // Command
|
||||
w.Write(ability);
|
||||
w.Write(active);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendGlobalLightLevel(NetState ns, sbyte level)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x4F, // Packet ID
|
||||
(byte)level
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendLogoutAck(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0xD1, // Packet ID
|
||||
0x01
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendWeather(NetState ns, byte type, byte density, sbyte temperature)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x65, // Packet ID
|
||||
type,
|
||||
density,
|
||||
(byte)temperature
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendPlayerMove(NetState ns, Direction d)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x97, // Packet ID
|
||||
(byte)d
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendClientVersionReq(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0xBD, // Packet ID
|
||||
0x00,
|
||||
0x03
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendSetWarMode(NetState ns, bool warmode)
|
||||
{
|
||||
if (warmode)
|
||||
SendInWarMode(ns);
|
||||
else
|
||||
SendInPeaceMode(ns);
|
||||
}
|
||||
|
||||
public static void SendInWarMode(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x72, // Packet ID
|
||||
0x01, // War mode
|
||||
0x00,
|
||||
0x32, // ?
|
||||
0x00
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendInPeaceMode(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x72, // Packet ID
|
||||
0x00, // Peace mode
|
||||
0x00,
|
||||
0x32, // ?
|
||||
0x00
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendRemoveEntity(NetState ns, Serial entity)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[5]);
|
||||
w.Write((byte)0x1D); // Packet ID
|
||||
|
||||
w.Write(entity);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendServerChange(NetState ns, Mobile m, Map map)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[16]);
|
||||
w.Write((byte)0x76); // Packet ID
|
||||
|
||||
w.Write((short)m.X);
|
||||
w.Write((short)m.Y);
|
||||
w.Write((short)m.Z);
|
||||
w.Position += 5;
|
||||
w.Write((short)map.Width);
|
||||
w.Write((short)map.Height);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSkillsUpdate(NetState ns, Skills skills)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 6 + skills.Length * 9;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x3A); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write((byte)0x02); // type: absolute, capped
|
||||
|
||||
for (int i = 0; i < skills.Length; ++i)
|
||||
{
|
||||
Skill s = skills[i];
|
||||
|
||||
double v = s.NonRacialValue;
|
||||
int uv = (int)(v * 10);
|
||||
|
||||
if (uv < 0)
|
||||
uv = 0;
|
||||
else if (uv >= 0x10000)
|
||||
uv = 0xFFFF;
|
||||
|
||||
w.Write((ushort)(s.Info.SkillID + 1));
|
||||
w.Write((ushort)uv);
|
||||
w.Write((ushort)s.BaseFixedPoint);
|
||||
w.Write((byte)s.Lock);
|
||||
w.Write((ushort)s.CapFixedPoint);
|
||||
}
|
||||
|
||||
w.Position += 2;
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSkillChange(NetState ns, Skill skill)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[13]);
|
||||
w.Write((byte)0x3A); // Packet ID
|
||||
w.Write((short)13); // Length
|
||||
|
||||
|
||||
double v = skill.NonRacialValue;
|
||||
int uv = (int)(v * 10);
|
||||
|
||||
if (uv < 0)
|
||||
uv = 0;
|
||||
else if (uv >= 0x10000)
|
||||
uv = 0xFFFF;
|
||||
|
||||
w.Write((byte)0xDF); // type: delta, capped
|
||||
w.Write((ushort)skill.Info.SkillID);
|
||||
w.Write((ushort)uv);
|
||||
w.Write((ushort)skill.BaseFixedPoint);
|
||||
w.Write((byte)skill.Lock);
|
||||
w.Write((ushort)skill.CapFixedPoint);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendLaunchBrowser(NetState ns, string url)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
url ??= "";
|
||||
|
||||
int length = 4 + url.Length;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xA5); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.WriteAsciiNull(url);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
// TODO: Optimize for IEnumerable<NetState>
|
||||
public static void SendPlaySound(NetState ns, int soundId, IPoint3D target)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[12]);
|
||||
w.Write((byte)0x54); // Packet ID
|
||||
|
||||
w.Write((byte)1); // flags
|
||||
w.Write((short)soundId);
|
||||
w.Position += 2; // volume?
|
||||
w.Write((short)target.X);
|
||||
w.Write((short)target.Y);
|
||||
w.Write((short)target.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendPlayRepeatingSound(NetState ns, int soundId, IPoint3D target)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[12]);
|
||||
w.Write((byte)0x54); // Packet ID
|
||||
|
||||
w.Position++; // flags
|
||||
w.Write((short)soundId);
|
||||
w.Position += 2; // volume?
|
||||
w.Write((short)target.X);
|
||||
w.Write((short)target.Y);
|
||||
w.Write((short)target.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendPlayMusic(NetState ns, MusicName music)
|
||||
{
|
||||
ushort value = (ushort)music;
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x6D, // Packet ID
|
||||
(byte)(value >> 8),
|
||||
(byte)(value & 0xFF)
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendStopMusic(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x6D, // Packet ID
|
||||
0x1F,
|
||||
0xFF
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendScrollMessage(NetState ns, int type, int tip, string text)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
text ??= "";
|
||||
|
||||
int length = 10 + text.Length;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xA6); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write((byte)type);
|
||||
w.Write(tip);
|
||||
w.Write((ushort)text.Length);
|
||||
w.WriteAsciiFixed(text, text.Length);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendCurrentTime(NetState ns)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
// TODO: Don't call UtcNow so readily.
|
||||
DateTime now = DateTime.UtcNow;
|
||||
|
||||
ns.Send(stackalloc byte[]
|
||||
{
|
||||
0x5B, // Packet ID
|
||||
(byte)now.Hour,
|
||||
(byte)now.Minute,
|
||||
(byte)now.Second
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendPathfindMessage(NetState ns, IPoint3D p)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[7]);
|
||||
w.Write((byte)0x38); // Packet ID
|
||||
|
||||
w.Write((short)p.X);
|
||||
w.Write((short)p.Y);
|
||||
w.Write((short)p.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendPingAck(NetState ns, byte ping)
|
||||
{
|
||||
ns?.Send(stackalloc byte[2]
|
||||
{
|
||||
0x73, // Packet ID
|
||||
ping
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendMovementRej(NetState ns, int seq, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[8]);
|
||||
w.Write((byte)0x21); // Packet ID
|
||||
|
||||
w.Write((byte)seq);
|
||||
w.Write((short)m.X);
|
||||
w.Write((short)m.Y);
|
||||
w.Write((byte)m.Direction);
|
||||
w.Write((sbyte)m.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMovementAck(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SendMovementAck(ns, ns.Sequence, Notoriety.Compute(m, m));
|
||||
}
|
||||
|
||||
public static void SendMovementAck(NetState ns, byte seq, byte noto)
|
||||
{
|
||||
ns?.Send(stackalloc byte[3]
|
||||
{
|
||||
0x22,
|
||||
seq,
|
||||
noto
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendLoginConfirm(NetState ns, Mobile m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[37]);
|
||||
w.Write((byte)0x1B); // Packet ID
|
||||
|
||||
w.Write(m.Serial);
|
||||
w.Position++;
|
||||
w.Write((short)m.Body);
|
||||
w.Write((short)m.X);
|
||||
w.Write((short)m.Y);
|
||||
w.Write((short)m.Z);
|
||||
w.Write((byte)m.Direction);
|
||||
w.Position++;
|
||||
w.Write(-1);
|
||||
|
||||
Map map = m.Map;
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
map = m.LogoutMap;
|
||||
|
||||
w.Position += 4;
|
||||
w.Write((short)(map?.Width ?? 6144));
|
||||
w.Write((short)(map?.Height ?? 4096));
|
||||
w.Position += 9;
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendLoginComplete(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0x55 // Packet ID
|
||||
});
|
||||
}
|
||||
|
||||
public static void SendClearWeaponAbility(NetState ns)
|
||||
{
|
||||
ns?.Send(stackalloc byte[]
|
||||
{
|
||||
0xBF, // Extended Packet ID
|
||||
0x00,
|
||||
0x05, // Length
|
||||
0x21, // Command
|
||||
0x00
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDisplayProfile(NetState ns, Serial m, string header, string body, string footer)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
header ??= "";
|
||||
body ??= "";
|
||||
footer ??= "";
|
||||
|
||||
int length = 12 + header.Length + footer.Length * 2 + body.Length * 2;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0xB8); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Write(m);
|
||||
w.WriteAsciiNull(header);
|
||||
w.WriteBigUniNull(footer);
|
||||
w.WriteBigUniNull(body);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
using Server.Buffers;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendMultiTargetReqHS(NetState ns, MultiTarget t)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[30]);
|
||||
w.Write((byte)0x99); // Packet ID
|
||||
|
||||
w.Write(t.AllowGround);
|
||||
w.Write(t.TargetID);
|
||||
w.Write((byte)t.Flags);
|
||||
w.Position += 11;
|
||||
w.Write((short)t.MultiID);
|
||||
w.Write((short)t.Offset.X);
|
||||
w.Write((short)t.Offset.Y);
|
||||
w.Write((short)t.Offset.Z);
|
||||
// 4 bytes unknown?
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendMultiTargetReq(NetState ns, MultiTarget t)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[26]);
|
||||
w.Write((byte)0x99); // Packet ID
|
||||
|
||||
w.Write(t.AllowGround);
|
||||
w.Write(t.TargetID);
|
||||
w.Write((byte)t.Flags);
|
||||
w.Position += 14;
|
||||
w.Write((short)t.MultiID);
|
||||
w.Write((short)t.Offset.X);
|
||||
w.Write((short)t.Offset.Y);
|
||||
w.Write((short)t.Offset.Z);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
private static byte[] _targetReqPacket;
|
||||
|
||||
public static void SendCancelTarget(NetState ns)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (_targetReqPacket == null)
|
||||
{
|
||||
_targetReqPacket = new byte[19];
|
||||
_targetReqPacket[0] = 0x6C; // Packet ID
|
||||
_targetReqPacket[6] = 0x03; // ?
|
||||
}
|
||||
|
||||
ns.Send(_targetReqPacket);
|
||||
}
|
||||
|
||||
public static void SendTargetReq(NetState ns, Target t)
|
||||
{
|
||||
if (ns == null || t == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[19]);
|
||||
w.Write((byte)0x6C); // Packet ID
|
||||
|
||||
w.Write(t.AllowGround);
|
||||
w.Write(t.TargetID);
|
||||
w.Write((byte)t.Flags);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
using Server.Buffers;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public enum TradeFlag : byte
|
||||
{
|
||||
Display = 0x0,
|
||||
Close = 0x1,
|
||||
Update = 0x2,
|
||||
UpdateGold = 0x3,
|
||||
UpdateLedger = 0x4
|
||||
}
|
||||
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendDisplaySecureTrade(NetState ns, Serial them, Serial firstCont, Serial secondCont, string name = "")
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
name ??= "";
|
||||
|
||||
int length = 17 + name.Length;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x6F); // Packet ID
|
||||
w.Write((short)length); // Length
|
||||
|
||||
w.Position++; // Display
|
||||
w.Write(them);
|
||||
w.Write(firstCont);
|
||||
w.Write(secondCont);
|
||||
w.Write(name.Length > 0);
|
||||
w.WriteAscii(name);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendCloseSecureTrade(NetState ns, Serial cont)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[8]);
|
||||
w.Write((byte)0x6F); // Packet ID
|
||||
w.Write((ushort)8); // Length
|
||||
|
||||
w.Write((byte)1); // Close
|
||||
w.Write(cont);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendUpdateSecureTrade(NetState ns, Serial cont, bool fromAccepted, bool toAccepted)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[10]);
|
||||
w.Write((byte)0x6F); // Packet ID
|
||||
w.Write((ushort)10); // Length
|
||||
|
||||
w.Write((byte)TradeFlag.Update);
|
||||
w.Write(cont);
|
||||
w.Write(fromAccepted);
|
||||
w.Write(toAccepted);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendUpdateSecureTrade(NetState ns, Serial cont, TradeFlag flag, int first, int second)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[16]);
|
||||
w.Write((byte)0x6F); // Packet ID
|
||||
w.Write((ushort)16); // Length
|
||||
|
||||
w.Write((byte)flag);
|
||||
w.Write(cont);
|
||||
w.Write(first);
|
||||
w.Write(second);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSecureTradeEquip(NetState ns, Item item, Serial m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.ContainerGridLines)
|
||||
SendSecureTradeEquipNew(ns, item, m);
|
||||
else
|
||||
SendSecureTradeEquipOld(ns, item, m);
|
||||
}
|
||||
|
||||
public static void SendSecureTradeEquipOld(NetState ns, Item item, Serial m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[20]);
|
||||
w.Write((byte)0x25); // Packet ID
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((short)item.ItemID);
|
||||
w.Position++; // Write((byte)0)
|
||||
w.Write((short)item.Amount);
|
||||
w.Write((short)item.X);
|
||||
w.Write((short)item.Y);
|
||||
w.Write(m);
|
||||
w.Write((short)item.Hue);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendSecureTradeEquipNew(NetState ns, Item item, Serial m)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[21]);
|
||||
w.Write((byte)0x25); // Packet ID
|
||||
|
||||
w.Write(item.Serial);
|
||||
w.Write((short)item.ItemID);
|
||||
w.Position++; // Write((byte)0)
|
||||
w.Write((short)item.Amount);
|
||||
w.Write((short)item.X);
|
||||
w.Write((short)item.Y);
|
||||
w.Write(m);
|
||||
w.Position++; // Write((byte)0) Grid Location?
|
||||
w.Write((short)item.Hue);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Buffers;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendVendorBuyContent(NetState ns, IList<BuyItemState> list)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.ContainerGridLines)
|
||||
SendVendorBuyContentNew(ns, list);
|
||||
else
|
||||
SendVendorBuyContentOld(ns, list);
|
||||
}
|
||||
|
||||
public static void SendVendorBuyContentOld(NetState ns, IList<BuyItemState> list)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 5 + list.Count * 19;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Write((ushort)length); // Length
|
||||
|
||||
w.Write((short)list.Count);
|
||||
|
||||
//The client sorts these by their X/Y value.
|
||||
//OSI sends these in weird order. X/Y highest to lowest and serial lowest to highest
|
||||
//These are already sorted by serial (done by the vendor class) but we have to send them by x/y
|
||||
//(the x74 packet is sent in 'correct' order.)
|
||||
for (int i = list.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BuyItemState bis = list[i];
|
||||
|
||||
w.Write(bis.MySerial);
|
||||
w.Write((ushort)bis.ItemID);
|
||||
w.Position++; // Write((byte)0); itemid offset
|
||||
w.Write((ushort)bis.Amount);
|
||||
w.Write((short)(i + 1)); //x
|
||||
w.Write((short)1); //y
|
||||
w.Write(bis.ContainerSerial);
|
||||
w.Write((ushort)bis.Hue);
|
||||
}
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendVendorBuyContentNew(NetState ns, IList<BuyItemState> list)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
int length = 5 + list.Count * 20;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[length]);
|
||||
w.Write((byte)0x3C); // Packet ID
|
||||
w.Write((ushort)length); // Length
|
||||
|
||||
w.Write((short)list.Count);
|
||||
|
||||
//The client sorts these by their X/Y value.
|
||||
//OSI sends these in weird order. X/Y highest to lowest and serial lowest to highest
|
||||
//These are already sorted by serial (done by the vendor class) but we have to send them by x/y
|
||||
//(the x74 packet is sent in 'correct' order.)
|
||||
for (int i = list.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BuyItemState bis = list[i];
|
||||
|
||||
w.Write(bis.MySerial);
|
||||
w.Write((ushort)bis.ItemID);
|
||||
w.Position++; // Write((byte)0); itemid offset
|
||||
w.Write((ushort)bis.Amount);
|
||||
w.Write((short)(i + 1)); //x
|
||||
w.Write((short)1); //y
|
||||
w.Position++; // Write((byte)0); Grid Location?
|
||||
w.Write(bis.ContainerSerial);
|
||||
w.Write((ushort)bis.Hue);
|
||||
}
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendDisplayBuyList(NetState ns, Serial vendor)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (ns.HighSeas)
|
||||
SendDisplayBuyListHS(ns, vendor);
|
||||
else
|
||||
SendDisplayBuyListOld(ns, vendor);
|
||||
}
|
||||
|
||||
public static void SendDisplayBuyListOld(NetState ns, Serial vendor)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[7]);
|
||||
w.Write((byte)0x24); // Packet ID
|
||||
|
||||
w.Write(vendor);
|
||||
w.Write((short)0x30); // buy window id?
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendDisplayBuyListHS(NetState ns, Serial vendor)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9]);
|
||||
w.Write((byte)0x24); // Packet ID
|
||||
|
||||
w.Write(vendor);
|
||||
w.Write((short)0x30); // buy window id?
|
||||
//w.Write((short)0x00); // Unknown
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
|
||||
public static void SendVendorBuyList(NetState ns, Mobile vendor, IList<BuyItemState> list)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[8 + 135 * list.Count]);
|
||||
w.Write((byte)0x74); // Packet ID
|
||||
w.Position += 2; // Dynamic Length
|
||||
|
||||
w.Write(!(vendor.FindItemOnLayer(Layer.ShopBuy) is Container BuyPack) ? Serial.MinusOne : BuyPack.Serial);
|
||||
|
||||
w.Write((byte)list.Count);
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
BuyItemState bis = list[i];
|
||||
|
||||
w.Write(bis.Price);
|
||||
|
||||
string desc = bis.Description ?? "";
|
||||
w.Write((byte)(desc.Length + 1));
|
||||
w.WriteAsciiNull(desc);
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendVendorSellList(NetState ns, Serial shopkeeper, IList<SellItemState> list)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
ushort count = (ushort)list.Count;
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[9 + 140 * count]);
|
||||
w.Write((byte)0x9E); // Packet ID
|
||||
w.Position += 2; //( Dynamic Length
|
||||
|
||||
w.Write(shopkeeper);
|
||||
|
||||
w.Write(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
SellItemState state = list[i];
|
||||
|
||||
w.Write(state.Item.Serial);
|
||||
w.Write((ushort)state.Item.ItemID);
|
||||
w.Write((ushort)state.Item.Hue);
|
||||
w.Write((ushort)state.Item.Amount);
|
||||
w.Write((ushort)state.Price);
|
||||
|
||||
string name = state.Item.Name;
|
||||
|
||||
if (name == null || (name = name.Trim()).Length <= 0)
|
||||
name = state.Name ?? "";
|
||||
|
||||
w.Write((ushort)name.Length);
|
||||
w.WriteAsciiFixed(name, (ushort)name.Length);
|
||||
}
|
||||
|
||||
w.Position = 1;
|
||||
w.Write((ushort)w.WrittenCount);
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendEndVendorBuyOrSell(NetState ns, Serial vendor)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[8]);
|
||||
w.Write((byte)0x3B); // Packet ID
|
||||
|
||||
w.Write(vendor);
|
||||
|
||||
ns.Send(w.RawSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
using Server.Buffers;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static partial class Packets
|
||||
{
|
||||
public static void SendHairEquipUpdate(NetState ns, Mobile parent)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[15]);
|
||||
w.Write((byte)0x2E); // Packet ID
|
||||
|
||||
int hue = parent.HairHue;
|
||||
|
||||
if (parent.SolidHueOverride >= 0)
|
||||
hue = parent.SolidHueOverride;
|
||||
|
||||
w.Write(HairInfo.FakeSerial(parent.Serial));
|
||||
w.Write((short)parent.HairItemID);
|
||||
w.Write((short)Layer.Hair);
|
||||
w.Write(parent.Serial);
|
||||
w.Write((short)hue);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendFacialHairEquipUpdate(NetState ns, Mobile parent)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[15]);
|
||||
w.Write((byte)0x2E); // Packet ID
|
||||
|
||||
int hue = parent.FacialHairHue;
|
||||
|
||||
if (parent.SolidHueOverride >= 0)
|
||||
hue = parent.SolidHueOverride;
|
||||
|
||||
w.Write(FacialHairInfo.FakeSerial(parent.Serial));
|
||||
w.Write((short)parent.FacialHairItemID);
|
||||
w.Write((short)Layer.Hair);
|
||||
w.Write(parent.Serial);
|
||||
w.Write((short)hue);
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendRemoveHair(NetState ns, Mobile parent)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[5]);
|
||||
w.Write((byte)0x1D); // Packet ID
|
||||
|
||||
w.Write(HairInfo.FakeSerial(parent.Serial));
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
|
||||
public static void SendRemoveFacialHair(NetState ns, Mobile parent)
|
||||
{
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
SpanWriter w = new SpanWriter(stackalloc byte[5]);
|
||||
w.Write((byte)0x1D); // Packet ID
|
||||
|
||||
w.Write(FacialHairInfo.FakeSerial(parent.Serial));
|
||||
|
||||
ns.Send(w.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Projects/Server/Network/SendQueue.cs
Normal file
44
Projects/Server/Network/SendQueue.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/***************************************************************************
|
||||
* SendQueue.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class SendQueue<T>
|
||||
{
|
||||
private BlockingCollection<T> m_Queue = new BlockingCollection<T>(new ConcurrentQueue<T>());
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
m_Queue.Add(t);
|
||||
}
|
||||
|
||||
public Task<T> DequeueAsync()
|
||||
{
|
||||
TaskCompletionSource<T> taskCompletion = new TaskCompletionSource<T>();
|
||||
Task.Run(() => taskCompletion.SetResult(Dequeue()));
|
||||
return taskCompletion.Task;
|
||||
}
|
||||
|
||||
public T Dequeue() => m_Queue.Take();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public sealed class ServerInfo
|
||||
{
|
||||
public ServerInfo(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address)
|
||||
{
|
||||
Name = name;
|
||||
FullPercent = fullPercent;
|
||||
TimeZone = tz.GetUtcOffset(DateTime.Now).Hours;
|
||||
Address = address;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public int FullPercent { get; set; }
|
||||
|
||||
public int TimeZone { get; set; }
|
||||
|
||||
public IPEndPoint Address { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ namespace Server.Network
|
|||
|
||||
public static ArraySegment<byte> GetArray(this ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> result))
|
||||
if (MemoryMarshal.TryGetArray(memory, out var result))
|
||||
return result;
|
||||
|
||||
throw new InvalidOperationException("Buffer backed by array was expected");
|
||||
|
|
@ -42,7 +42,7 @@ namespace Server.Network
|
|||
|
||||
public static ArraySegment<byte> GetArray(this ReadOnlySequence<byte> memory)
|
||||
{
|
||||
if (SequenceMarshal.TryGetArray(memory, out ArraySegment<byte> result))
|
||||
if (SequenceMarshal.TryGetArray(memory, out var result))
|
||||
return result;
|
||||
|
||||
throw new InvalidOperationException("Buffer backed by array was expected");
|
||||
|
|
|
|||
135
Projects/Server/Network/StaticPacketHandlers.cs
Normal file
135
Projects/Server/Network/StaticPacketHandlers.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/***************************************************************************
|
||||
* StaticPacketHandlers.cs
|
||||
* -------------------
|
||||
* begin : March 15, 2019
|
||||
* copyright : (C) The ModernUO Team
|
||||
* email : hi@modernuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class StaticPacketHandlers
|
||||
{
|
||||
private static ConcurrentDictionary<IPropertyListObject,OPLInfo> OPLInfoPackets = new ConcurrentDictionary<IPropertyListObject,OPLInfo>();
|
||||
private static ConcurrentDictionary<IPropertyListObject,ObjectPropertyList> ObjectPropertyListPackets = new ConcurrentDictionary<IPropertyListObject,ObjectPropertyList>();
|
||||
private static ConcurrentDictionary<IEntity,RemoveEntity> RemoveEntityPackets = new ConcurrentDictionary<IEntity,RemoveEntity>();
|
||||
|
||||
private static ConcurrentDictionary<Item,WorldItem> WorldItemPackets = new ConcurrentDictionary<Item,WorldItem>();
|
||||
private static ConcurrentDictionary<Item,WorldItemSA> WorldItemSAPackets = new ConcurrentDictionary<Item,WorldItemSA>();
|
||||
private static ConcurrentDictionary<Item,WorldItemHS> WorldItemHSPackets = new ConcurrentDictionary<Item,WorldItemHS>();
|
||||
|
||||
public static OPLInfo GetOPLInfoPacket(IPropertyListObject obj)
|
||||
{
|
||||
return OPLInfoPackets.GetOrAdd(obj, value =>
|
||||
{
|
||||
OPLInfo packet = new OPLInfo(value.PropertyList);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static OPLInfo FreeOPLInfoPacket(IPropertyListObject obj)
|
||||
{
|
||||
if (OPLInfoPackets.TryRemove(obj, out OPLInfo p))
|
||||
Packet.Release(p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPLPacket(IPropertyListObject obj)
|
||||
{
|
||||
return ObjectPropertyListPackets.GetOrAdd(obj, value =>
|
||||
{
|
||||
ObjectPropertyList list = new ObjectPropertyList(value);
|
||||
|
||||
value.GetProperties(list);
|
||||
if (value is Item item)
|
||||
item.AppendChildProperties(list);
|
||||
|
||||
list.Terminate();
|
||||
list.SetStatic();
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
public static ObjectPropertyList FreeOPLPacket(IPropertyListObject obj)
|
||||
{
|
||||
if (ObjectPropertyListPackets.TryRemove(obj, out ObjectPropertyList list))
|
||||
Packet.Release(list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static RemoveEntity GetRemoveEntityPacket(IEntity entity)
|
||||
{
|
||||
return RemoveEntityPackets.GetOrAdd(entity, value =>
|
||||
{
|
||||
RemoveEntity packet = new RemoveEntity(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static void FreeRemoveItemPacket(IEntity entity)
|
||||
{
|
||||
if (RemoveEntityPackets.TryRemove(entity, out RemoveEntity p))
|
||||
Packet.Release(p);
|
||||
}
|
||||
|
||||
public static WorldItem GetWorldItemPacket(Item item)
|
||||
{
|
||||
return WorldItemPackets.GetOrAdd(item, value =>
|
||||
{
|
||||
WorldItem packet = new WorldItem(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static WorldItemSA GetWorldItemSAPacket(Item item)
|
||||
{
|
||||
return WorldItemSAPackets.GetOrAdd(item, value =>
|
||||
{
|
||||
WorldItemSA packet = new WorldItemSA(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static WorldItemHS GetWorldItemHSPacket(Item item)
|
||||
{
|
||||
return WorldItemHSPackets.GetOrAdd(item, value =>
|
||||
{
|
||||
WorldItemHS packet = new WorldItemHS(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static void FreeWorldItemPackets(Item item)
|
||||
{
|
||||
if (WorldItemPackets.TryRemove(item, out WorldItem wi))
|
||||
Packet.Release(wi);
|
||||
|
||||
if (WorldItemSAPackets.TryRemove(item, out WorldItemSA wisa))
|
||||
Packet.Release(wisa);
|
||||
|
||||
if (WorldItemHSPackets.TryRemove(item, out WorldItemHS wihs))
|
||||
Packet.Release(wihs);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue