Updates Packets & Randomizer (#43)
* Fixes a bug with the main loop. Removes unnecessary optimizations for RDRand. * WIP - Rewriting packets. * Cleanup and updates README * Converts more packets * Fixes header * Converts Effects packets. * Forgot the send command * Adds the start of containers packets. * Adds message packets with caching * Extends the send methods * Starts to add Acquire methods * Converted the packets * Cleanup * Cleanup * Adds more packets * Adds more packets * Fixes clearing arrays from pool. Adds Mobile Incoming * Converts more packets. * Moves more packets * Moves more packets * Test compression * Merges * Migrating to an idiomatic syntax that also supports compression, and proxying. * Optimize the stack alloc. Changes attributes * Converted container packets * Visual Studio doesn't auto save files. I am still getting used to subpar IDEs. * Adds static packet caching. Will profile later. Converts more packets * Fixes packets and changes how compression is configured * WIP - Adds basics for Gumps. Not finished though. * Fix file * Fixes formatting * Changed SpanWriter to be more idiomatic. * Fixes Span vs RawSpan and missing stackallocs * Converts over some more gumps * WIP - Deletes 32bit support. * Drops RDRand32 support. * Fixes gump compilation * Converting gump components * Removes old huffman compression function * Revert signature for backwards compatibility * WIP - Converting more gump components * Creates ArraySet for the strings. Updates AppendTo to reference that. * Converts the maining gump components * Cleans up gump components * Cleans up directives * Cleans up ArraySet and moves it. Adds null-coalescing-assignment * Cleanup, Target Packets, and C# 8 changes. * Removed OPL Packet * World packets * Fixing packet uses * Cleans up code. Fixes packet uses in various places. * More cleanup for packets * Code cleanup * Converts more packet uses and cleans up more code * More code cleanup * Finishes fixing the packets in Item * Updates secure trade packets * Updates core and gets it to compile. * Moved packets to scripts. Fixed account handler use of packets * Code cleanup * Updates chat packets * Code cleanuo * Adds party packets, but need to implement them. * Party packets WIP * Finishes party packets * Rearrange movement namespaces and classes * Finishes plant packets * Code Formatting * Fixes moving effects * Code cleanup, eliminates equipinfo * Adds more packets. Fixes bugs with various packets. * Finishes mahjon packets * Fixes mahjong packet * Code cleanup * Finishes mahjong packets * Adds Map packets * Add multifacet maps and charts * Cleans up some packets with UTF8 * Optimizes packets * Cleans up more packets. Moves the MessageHelper * Removes assistant support. Removes extended protocol. Incorporates MapUO packets as normal packets. * Updates protocol extensions packet receiver * Fixes a few bugs. Fixes a few more packets. * Code cleanup and fixing more packets * Fixes packet effects * Cleaned up more code * Buff Icon cleanup * Removed unused constructors * Code Cleanup. Adds BoatHS Packets * Moves house files. Updates house foundation packets. * Deployment cleanup * Fixes: * Code cleanup * More code cleanup * More code cleanup * Cleaned up BaseHouse * Enforces styling * Converts foreach to linq where possible. * Dont need that * Goals/Readme updates * Removes 32bit support at the highest level. Turns on HRT by default. * Code cleanup. Fixes extended features packet. * Fixes various bugs * Code cleanup * Code cleanup * Code cleanup. Fixes gump X/Y assignment. * Code cleanup using |= operator * More code cleanup * Cleanup * Fixes spacing issues. Thanks Visual Studio. You suck. * Compiler error * Fixes NPE from RunUO 2.7 * Renames ScriptCompiler to AssemblyHandler. Fixes packets. Updates README * Fixes more packets. Stupid trailing nulls. * Fixes various bugs. * Fixes for gumps * Fixes more gump stuff. Going to split it out later since it is getting insane * Recoded the gump writing * WIP * *Added output path of scripts project to dev branch *Activated debugging in code
This commit is contained in:
parent
7aa8fd3df1
commit
179cb50557
588 changed files with 10843 additions and 16177 deletions
325
Projects/Server/Network/Packets/Accounts.cs
Normal file
325
Projects/Server/Network/Packets/Accounts.cs
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Projects/Server/Network/Packets/Arrow.cs
Normal file
69
Projects/Server/Network/Packets/Arrow.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Projects/Server/Network/Packets/Attributes.cs
Normal file
168
Projects/Server/Network/Packets/Attributes.cs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Projects/Server/Network/Packets/Containers.cs
Normal file
217
Projects/Server/Network/Packets/Containers.cs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Projects/Server/Network/Packets/Damage.cs
Normal file
61
Projects/Server/Network/Packets/Damage.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
283
Projects/Server/Network/Packets/Effects.cs
Normal file
283
Projects/Server/Network/Packets/Effects.cs
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Projects/Server/Network/Packets/Gumps.cs
Normal file
94
Projects/Server/Network/Packets/Gumps.cs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
330
Projects/Server/Network/Packets/Items.cs
Normal file
330
Projects/Server/Network/Packets/Items.cs
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Projects/Server/Network/Packets/Map.cs
Normal file
72
Projects/Server/Network/Packets/Map.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
235
Projects/Server/Network/Packets/Menus.cs
Normal file
235
Projects/Server/Network/Packets/Menus.cs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
161
Projects/Server/Network/Packets/Messages.cs
Normal file
161
Projects/Server/Network/Packets/Messages.cs
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
959
Projects/Server/Network/Packets/Mobiles.cs
Normal file
959
Projects/Server/Network/Packets/Mobiles.cs
Normal file
|
|
@ -0,0 +1,959 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
550
Projects/Server/Network/Packets/Player.cs
Normal file
550
Projects/Server/Network/Packets/Player.cs
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Projects/Server/Network/Packets/Profile.cs
Normal file
29
Projects/Server/Network/Packets/Profile.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Projects/Server/Network/Packets/Targeting.cs
Normal file
81
Projects/Server/Network/Packets/Targeting.cs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
139
Projects/Server/Network/Packets/Trade.cs
Normal file
139
Projects/Server/Network/Packets/Trade.cs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
207
Projects/Server/Network/Packets/Vendors.cs
Normal file
207
Projects/Server/Network/Packets/Vendors.cs
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Projects/Server/Network/Packets/VirtualHair.cs
Normal file
78
Projects/Server/Network/Packets/VirtualHair.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue