first commit

This commit is contained in:
Beyhan Oğur
2026-09-03 04:45:36 +03:00
commit d5f52cc3d3
1038 changed files with 169579 additions and 0 deletions
@@ -0,0 +1,211 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ClassicAssist.Shared;
using ClassicAssist.Data;
using ClassicAssist.Data.Macros;
using ClassicAssist.Misc;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UO.Network.Packets;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network
{
public static class ActionPacketQueue
{
private const int DRAG_DROP_DISTANCE = 3;
private static readonly ThreadPriorityQueue<BaseQueueItem> _actionPacketQueue =
new ThreadPriorityQueue<BaseQueueItem>( ProcessActionPacketQueue );
private static readonly object _actionPacketQueueLock = new object();
private static void ProcessActionPacketQueue( BaseQueueItem queueItem )
{
// Lock here so wait don't set the WaitHandle before we've called ToTask(?)
lock ( _actionPacketQueueLock )
{
if ( queueItem is PacketQueueItem actionQueueItem )
{
if ( actionQueueItem.DelaySend )
{
while ( Engine.LastActionPacket +
TimeSpan.FromMilliseconds( Options.CurrentOptions.ActionDelayMS ) > DateTime.Now )
{
Thread.Sleep( 1 );
}
}
byte[] data = actionQueueItem.Packet;
int length = actionQueueItem.Length;
Engine.LastActionPacket = DateTime.Now;
Engine.SendPacketToServer( data, length );
actionQueueItem.WaitHandle.Set();
}
else if ( queueItem is ActionQueueItem actionItem )
{
if ( actionItem.DelaySend )
{
while ( Engine.LastActionPacket +
TimeSpan.FromMilliseconds( Options.CurrentOptions.ActionDelayMS ) > DateTime.Now )
{
Thread.Sleep( 1 );
}
}
bool? result = actionItem.Action?.Invoke( actionItem.CheckRange );
if ( result.HasValue && result.Value )
{
Engine.LastActionPacket = DateTime.Now;
}
actionItem.WaitHandle.Set();
}
}
}
// ReSharper disable once UnusedMember.Global
public static Task EnqueueActionPacket( byte[] packet, int length, QueuePriority priority, bool delaySend )
{
return EnqueueActionPacket( new PacketQueueItem( packet, length, delaySend ), priority );
}
public static Task EnqueueActionPacket( BasePacket packet, QueuePriority priority = QueuePriority.Low,
bool delaySend = true )
{
byte[] data = packet.ToArray();
return EnqueueActionPacket( new PacketQueueItem( data, data.Length, delaySend ), priority );
}
public static Task EnqueueActionPacket( PacketQueueItem packetQueueItem, QueuePriority priority )
{
lock ( _actionPacketQueueLock )
{
_actionPacketQueue.Enqueue( packetQueueItem, priority );
return packetQueueItem.WaitHandle.ToTask();
}
}
public static Task EnqueueDragDropGround( int serial, int amount, int x, int y, int z,
QueuePriority priority = QueuePriority.Low, bool delaySend = true )
{
lock ( _actionPacketQueueLock )
{
byte[] dragPacket = new DragItem( serial, amount ).ToArray();
byte[] dropItem = new DropItem( serial, -1, x, y, z ).ToArray();
PacketQueueItem dragPacketQueueItem = new PacketQueueItem( dragPacket, dragPacket.Length, delaySend );
_actionPacketQueue.Enqueue( dragPacketQueueItem, priority );
PacketQueueItem dropPacketQueueItem = new PacketQueueItem( dropItem, dropItem.Length, delaySend );
_actionPacketQueue.Enqueue( dropPacketQueueItem, priority );
return new[] { dragPacketQueueItem.WaitHandle, dropPacketQueueItem.WaitHandle }.ToTask();
}
}
public static Task EnqueueActionPackets( IEnumerable<BasePacket> packets,
QueuePriority priority = QueuePriority.Low, bool delaySend = true )
{
lock ( _actionPacketQueueLock )
{
List<EventWaitHandle> handles = new List<EventWaitHandle>();
foreach ( BasePacket packet in packets )
{
byte[] data = packet.ToArray();
PacketQueueItem packetQueueItem = new PacketQueueItem( data, data.Length, delaySend );
handles.Add( packetQueueItem.WaitHandle );
_actionPacketQueue.Enqueue( packetQueueItem, priority );
}
return handles.ToTask();
}
}
public static Task EnqueueDragDrop( int serial, int amount, int containerSerial,
QueuePriority priority = QueuePriority.Low, bool checkRange = false, bool checkExisting = false, bool delaySend = true, int x = -1,
int y = -1 )
{
lock ( _actionPacketQueueLock )
{
if ( checkExisting && _actionPacketQueue.Contains( e => e is ActionQueueItem aqi && aqi.Serial == serial ) )
{
return Task.CompletedTask;
}
ActionQueueItem actionQueueItem = new ActionQueueItem( check =>
{
if ( check )
{
Item item = Engine.Items.GetItem( serial );
if ( item == null || item.Distance >= DRAG_DROP_DISTANCE )
{
if ( !MacroManager.QuietMode )
{
Commands.SystemMessage( Strings.Item_out_of_range___ );
}
return false;
}
}
Engine.SendPacketToServer( new DragItem( serial, amount ) );
Thread.Sleep( 50 );
Engine.SendPacketToServer( new DropItem( serial, containerSerial, x, y, 0 ) );
return true;
} ) { CheckRange = checkRange, DelaySend = delaySend, Serial = serial };
_actionPacketQueue.Enqueue( actionQueueItem, priority );
return actionQueueItem.WaitHandle.ToTask();
}
}
public static int Count()
{
lock ( _actionPacketQueueLock )
{
return _actionPacketQueue.Count();
}
}
public static void Clear()
{
lock ( _actionPacketQueueLock )
{
_actionPacketQueue.Clear();
}
}
}
}
@@ -0,0 +1,60 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using System.Threading;
namespace ClassicAssist.UO.Network
{
public abstract class BaseQueueItem
{
protected BaseQueueItem()
{
WaitHandle = new AutoResetEvent( false );
}
public bool DelaySend { get; set; }
public EventWaitHandle WaitHandle { get; set; }
}
public class PacketQueueItem : BaseQueueItem
{
public PacketQueueItem( byte[] packet, int length, bool delaySend )
{
Packet = packet;
Length = length;
DelaySend = delaySend;
}
public int Length { get; set; }
public byte[] Packet { get; set; }
}
public class ActionQueueItem : BaseQueueItem
{
public ActionQueueItem( Func<bool, bool> action )
{
Action = action;
}
public Func<bool, bool> Action { get; set; }
public int Serial { get; set; }
public bool CheckRange { get; set; }
}
}
@@ -0,0 +1,311 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ClassicAssist.Shared;
using ClassicAssist.Data;
using ClassicAssist.Data.Filters;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network
{
public static class IncomingPacketFilters
{
public delegate bool OnReceive( ref byte[] packet, ref int length );
private static readonly Dictionary<byte, OnReceive> _filters = new Dictionary<byte, OnReceive>();
public static void Initialize()
{
Register( 0x1C, OnASCIIMessage );
Register( 0x20, OnMobileUpdate );
Register( 0x77, OnMobileMoving );
Register( 0x78, OnMobileIncoming );
Register( 0xC1, OnLocalizedMessage );
Register( 0xCC, OnLocalizedMessageAffix );
Register( 0xF3, OnSAWorldItem );
}
private static bool OnASCIIMessage( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, false );
JournalEntry journalEntry = new JournalEntry
{
Serial = reader.ReadInt32(),
ID = reader.ReadInt16(),
SpeechType = (JournalSpeech) reader.ReadByte(),
SpeechHue = reader.ReadInt16(),
SpeechFont = reader.ReadInt16(),
Name = reader.ReadString( 30 ),
Text = reader.ReadString()
};
bool block = RepeatedMessagesFilter.CheckMessage( journalEntry );
if ( block && RepeatedMessagesFilter.FilterOptions.SendToJournal )
{
IncomingPacketHandlers.AddToJournal( journalEntry );
}
return block;
}
private static bool OnMobileUpdate( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, true );
int serial = reader.ReadInt32();
int id = reader.ReadInt16();
reader.ReadByte(); // BYTE 0x00;
int hue = reader.ReadUInt16();
int status = reader.ReadByte();
int x = reader.ReadInt16();
int y = reader.ReadInt16();
reader.ReadInt16(); // WORD 0x00;
//TODO Removed & 0x07 to not strip running flag, think of better solution
int direction = reader.ReadByte();
int z = reader.ReadSByte();
Mobile mobile = new Mobile( serial )
{
ID = id,
Hue = hue,
Status = (MobileStatus) status,
X = x,
Y = y,
Direction = (Direction) direction,
Z = z
};
if ( !Engine.RehueList.CheckMobileUpdate( mobile ) )
{
return false;
}
Engine.IncomingQueue.Enqueue( new Packet( packet, length ) );
return true;
}
private static bool OnSAWorldItem( ref byte[] packet, ref int length )
{
if ( !Engine.RehueList.CheckSAWorldItem( ref packet, ref length ) )
{
return false;
}
// Will need to send to handler ourselves because we won't see packet again
PacketHandler handler = IncomingPacketHandlers.GetHandler( 0xF3 );
handler?.OnReceive( new PacketReader( packet, length, true ) );
return true;
}
private static bool OnMobileMoving( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, true );
int serial = reader.ReadInt32();
int id = reader.ReadInt16();
int x = reader.ReadInt16();
int y = reader.ReadInt16();
int z = reader.ReadSByte();
//TODO Removed & 0x07 to not strip running flag, think of better solution
int direction = reader.ReadByte();
int hue = reader.ReadUInt16();
int status = reader.ReadByte();
int notoriety = reader.ReadByte();
Mobile mobile = new Mobile( serial )
{
ID = id,
X = x,
Y = y,
Z = z,
Direction = (Direction) direction,
Hue = hue,
Status = (MobileStatus) status,
Notoriety = (Notoriety) notoriety
};
if ( !Engine.RehueList.CheckMobileMoving( mobile ) )
{
return false;
}
Engine.IncomingQueue.Enqueue( new Packet( packet, length ) );
return true;
}
private static bool OnMobileIncoming( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, false );
int serial = reader.ReadInt32();
ItemCollection container = new ItemCollection( serial );
Mobile mobile = serial == Engine.Player?.Serial ? Engine.Player : Engine.GetOrCreateMobile( serial );
mobile.ID = reader.ReadInt16();
mobile.X = reader.ReadInt16();
mobile.Y = reader.ReadInt16();
mobile.Z = reader.ReadSByte();
//TODO Removed & 0x07 to not strip running flag, think of better solution
mobile.Direction = (Direction) reader.ReadByte();
mobile.Hue = reader.ReadUInt16();
mobile.Status = (MobileStatus) reader.ReadByte();
mobile.Notoriety = (Notoriety) reader.ReadByte();
bool useNewIncoming = Engine.ClientVersion == null || Engine.ClientVersion >= new Version( 7, 0, 33, 1 );
for ( ;; )
{
int itemSerial = reader.ReadInt32();
if ( itemSerial == 0 )
{
break;
}
Item item = Engine.GetOrCreateItem( itemSerial );
item.Owner = serial;
item.ID = reader.ReadUInt16();
item.Layer = (Layer) reader.ReadByte();
if ( useNewIncoming )
{
item.Hue = reader.ReadUInt16();
}
else
{
if ( ( item.ID & 0x8000 ) != 0 )
{
item.ID ^= 0x8000;
item.Hue = reader.ReadUInt16();
}
}
container.Add( item );
}
mobile.Equipment.Clear();
mobile.Equipment.Add( container.GetItems() );
foreach ( Item item in container.GetItems() )
{
mobile.SetLayer( item.Layer, item.Serial );
}
if ( !Engine.RehueList.CheckMobileIncoming( mobile, container ) )
{
return false;
}
Engine.IncomingQueue.Enqueue( new Packet( packet, length ) );
return true;
}
private static bool OnLocalizedMessage( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, false );
JournalEntry journalEntry = new JournalEntry
{
Serial = reader.ReadInt32(),
ID = reader.ReadInt16(),
SpeechType = (JournalSpeech) reader.ReadByte(),
SpeechHue = reader.ReadInt16(),
SpeechFont = reader.ReadInt16(),
Cliloc = reader.ReadInt32(),
Name = reader.ReadString( 30 ),
Arguments = reader.ReadUnicodeString( (int) reader.Size - 50 ).Split( '\t' )
};
journalEntry.Text = Cliloc.GetLocalString( journalEntry.Cliloc, journalEntry.Arguments );
bool block = RepeatedMessagesFilter.CheckMessage( journalEntry );
if ( block && RepeatedMessagesFilter.FilterOptions.SendToJournal )
{
IncomingPacketHandlers.AddToJournal( journalEntry );
}
return block || ClilocFilter.CheckMessage( journalEntry );
}
private static bool OnLocalizedMessageAffix( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, false );
int serial = reader.ReadInt32();
int graphic = reader.ReadInt16();
JournalSpeech messageType = (JournalSpeech) reader.ReadByte();
int hue = reader.ReadInt16();
int font = reader.ReadInt16();
int cliloc = reader.ReadInt32();
MessageAffixType affixType = (MessageAffixType) reader.ReadByte();
string name = reader.ReadString( 30 );
string affix = reader.ReadString();
string[] arguments = reader.ReadUnicodeString()
.Split( new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries );
JournalEntry journalEntry = new JournalEntry
{
Serial = serial,
ID = graphic,
SpeechType = messageType,
SpeechHue = hue,
SpeechFont = font,
Cliloc = cliloc,
Name = name,
Arguments = arguments
};
string text = Cliloc.GetLocalString( journalEntry.Cliloc, journalEntry.Arguments );
if ( affixType.HasFlag( MessageAffixType.Prepend ) )
{
journalEntry.Text = $"{affix}{text}";
}
else if ( affixType.HasFlag( MessageAffixType.Append ) )
{
journalEntry.Text = $"{text}{affix}";
}
bool block = RepeatedMessagesFilter.CheckMessage( journalEntry );
if ( block && RepeatedMessagesFilter.FilterOptions.SendToJournal )
{
IncomingPacketHandlers.AddToJournal( journalEntry );
}
return block || ClilocFilter.CheckMessageAffix( journalEntry, affixType, affix );
}
private static void Register( byte packetId, OnReceive action )
{
if ( !_filters.ContainsKey( packetId ) )
{
_filters.Add( packetId, action );
}
}
public static bool CheckPacket( ref byte[] data, ref int length )
{
if ( _filters.ContainsKey( data[0] ) && _filters.TryGetValue( data[0], out OnReceive onReceive ) )
{
return onReceive.Invoke( ref data, ref length );
}
foreach ( DynamicFilterEntry dynamicFilterEntry in DynamicFilterEntry.Filters.Where( e => e.Enabled ) )
{
bool result = dynamicFilterEntry.CheckPacket( ref data, ref length, PacketDirection.Incoming );
if ( result )
{
return true;
}
}
return false;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClassicAssist.Data;
using ClassicAssist.Data.Abilities;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using UOC = ClassicAssist.Shared.UO.Commands;
namespace ClassicAssist.UO.Network
{
public static class OutgoingPacketFilters
{
public delegate bool OnReceive( ref byte[] packet, ref int length );
private static readonly Dictionary<byte, OnReceive> _filters = new Dictionary<byte, OnReceive>();
public static void Initialize()
{
Register( 0x05, OnAttackRequested );
Register( 0x06, OnUseRequest );
Register( 0x80, OnAccountLoginRequest );
Register( 0x91, OnGameServerLogin );
}
private static bool OnUseRequest( ref byte[] packet, ref int length )
{
if ( !Options.CurrentOptions.CheckHandsPotions )
{
return false;
}
int serial = ( packet[1] << 24 ) | ( packet[2] << 16 ) | ( packet[3] << 8 ) | packet[4];
return AbilitiesManager.GetInstance().CheckHands( serial );
}
private static bool OnGameServerLogin( ref byte[] packet, ref int length )
{
PacketReader reader = new PacketReader( packet, length, true );
_ = reader.ReadInt32();
string username = reader.ReadString( 30 );
string password = reader.ReadString( 30 );
if ( !AssistantOptions.SavePasswords )
{
return false;
}
if ( !AssistantOptions.SavedPasswords.ContainsKey( username ) ||
AssistantOptions.SavePasswordsOnlyBlank && !string.IsNullOrEmpty( password ) )
{
return false;
}
string storedPassword = AssistantOptions.SavedPasswords[username];
byte[] passwordBytes = Encoding.ASCII.GetBytes( storedPassword );
byte[] buffer = new byte[30];
Buffer.BlockCopy( passwordBytes, 0, buffer, 0, passwordBytes.Length );
Buffer.BlockCopy( buffer, 0, packet, 35, buffer.Length );
return false;
}
private static bool OnAccountLoginRequest( ref byte[] packet, ref int packetLength )
{
PacketReader reader = new PacketReader( packet, packetLength, true );
string username = reader.ReadString( 30 );
string password = reader.ReadString( 30 );
if ( !AssistantOptions.SavePasswords )
{
return false;
}
if ( AssistantOptions.SavedPasswords.ContainsKey( username ) &&
( !AssistantOptions.SavePasswordsOnlyBlank || string.IsNullOrEmpty( password ) ) )
{
string storedPassword = AssistantOptions.SavedPasswords[username];
byte[] passwordBytes = Encoding.ASCII.GetBytes( storedPassword );
byte[] buffer = new byte[30];
Buffer.BlockCopy( passwordBytes, 0, buffer, 0, passwordBytes.Length );
Buffer.BlockCopy( buffer, 0, packet, 31, buffer.Length );
return false;
}
if ( string.IsNullOrEmpty( password ) )
{
return false;
}
if ( AssistantOptions.SavedPasswords.ContainsKey( username ) )
{
AssistantOptions.SavedPasswords.Remove( username );
}
AssistantOptions.SavedPasswords.Add( username, password );
AssistantOptions.OnPasswordsChanged();
return false;
}
private static bool OnAttackRequested( ref byte[] packet, ref int length )
{
int serial = ( packet[1] << 24 ) | ( packet[2] << 16 ) | ( packet[3] << 8 ) | packet[4];
bool block = Options.CurrentOptions.PreventAttackingFriendsInWarMode &&
Options.CurrentOptions.Friends.Any( fe => fe.Serial == serial );
if ( block )
{
UOC.SystemMessage( Strings.Attack_request_blocked___ );
}
return block;
}
private static void Register( byte packetId, OnReceive action )
{
if ( !_filters.ContainsKey( packetId ) )
{
_filters.Add( packetId, action );
}
}
public static bool CheckPacket( ref byte[] data, ref int length )
{
if ( _filters.ContainsKey( data[0] ) && _filters.TryGetValue( data[0], out OnReceive onReceive ) )
{
return onReceive.Invoke( ref data, ref length );
}
return false;
}
}
}
@@ -0,0 +1,245 @@
using System;
using System.IO;
using System.Linq;
using ClassicAssist.Shared;
using ClassicAssist.Data.Abilities;
using ClassicAssist.Data.Counters;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Data.Targeting;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
using ClassicAssist.UO.Objects.Gumps;
namespace ClassicAssist.UO.Network
{
public static class OutgoingPacketHandlers
{
public delegate void dGump( uint gumpId, int serial, Gump gump );
public delegate void dMenuClick( int serial, int gumpId, int index, int id, int hue );
public delegate void dTargetSentEvent( TargetType targetType, int senderSerial, int flags, int serial, int x,
int y, int z, int id );
private static PacketHandler[] _handlers;
private static PacketHandler[] _extendedHandlers;
public static event dTargetSentEvent TargetSentEvent;
public static event dGump GumpEvent;
public static event dMenuClick MenuClickedEvent;
public static void Initialize()
{
_handlers = new PacketHandler[0x100];
_extendedHandlers = new PacketHandler[0x100];
Register( 0x02, 7, OnMoveRequested );
Register( 0x06, 5, OnUseRequest );
Register( 0x07, 7, OnLiftRequest );
Register( 0x08, 15, OnDropRequest );
Register( 0x13, 10, OnEquipRequest );
Register( 0x6C, 19, OnTargetSent );
Register( 0x7D, 13, OnMenuResponse );
Register( 0xA0, 3, OnPlayServer );
Register( 0xB1, 0, OnGumpButtonPressed );
Register( 0xBD, 0, OnClientVersion );
Register( 0xBF, 0, OnExtendedCommand );
Register( 0xD7, 0, OnEncodedCommand );
Register( 0xEF, 31, OnNewClientVersion );
RegisterExtended( 0x1C, 0, OnSpellCast );
}
private static void OnSpellCast( PacketReader reader )
{
int type = reader.ReadInt16();
if ( type == 0 )
{
reader.Seek( 4, SeekOrigin.Current );
}
Engine.LastSpellID = reader.ReadInt16();
}
private static void OnExtendedCommand( PacketReader reader )
{
int command = reader.ReadInt16();
PacketHandler handler = GetExtendedHandler( command );
handler?.OnReceive( reader );
}
private static void OnMenuResponse( PacketReader reader )
{
int serial = reader.ReadInt32();
int gumpId = reader.ReadInt16();
int index = reader.ReadInt16();
int id = reader.ReadInt16();
int hue = reader.ReadInt16();
Engine.Menus.Remove( gumpId );
MenuClickedEvent?.Invoke( serial, gumpId, index, id, hue );
}
private static void OnPlayServer( PacketReader reader )
{
int index = reader.ReadInt16();
Engine.CurrentShard = Engine.Shards.FirstOrDefault( i => i.Index == index );
}
private static void OnClientVersion( PacketReader reader )
{
string version = reader.ReadString();
Engine.ClientVersion = Version.Parse( version );
}
private static void OnEquipRequest( PacketReader reader )
{
AbilitiesManager manager = AbilitiesManager.GetInstance();
manager.ResendGump( manager.Enabled );
}
private static void OnLiftRequest( PacketReader reader )
{
Engine.LastActionPacket = DateTime.Now;
Engine.Player.Holding = reader.ReadInt32();
Engine.Player.HoldingAmount = reader.ReadUInt16();
CountersManager.GetInstance().RecountAll?.Invoke();
}
private static void OnDropRequest( PacketReader reader )
{
Engine.LastActionPacket = DateTime.Now;
}
private static void OnEncodedCommand( PacketReader reader )
{
int serial = reader.ReadInt32();
int command = reader.ReadInt16();
switch ( command )
{
case 0x19:
{
reader.ReadByte();
int abilityIndex = reader.ReadInt32();
AbilitiesManager.GetInstance().CheckAbility( abilityIndex );
break;
}
}
}
private static void OnUseRequest( PacketReader reader )
{
Engine.LastActionPacket = DateTime.Now;
int serial = reader.ReadInt32();
if ( Engine.Player != null )
{
Engine.Player.LastObjectSerial = serial;
}
}
private static void OnMoveRequested( PacketReader reader )
{
Direction direction = (Direction) ( reader.ReadByte() & 0x07 );
int sequence = reader.ReadByte();
Engine.SetSequence( sequence, direction );
}
private static void OnGumpButtonPressed( PacketReader reader )
{
int senderSerial = reader.ReadInt32();
uint gumpId = reader.ReadUInt32();
int buttonId = reader.ReadInt32();
Engine.GumpList.TryRemove( gumpId, out _ );
if ( Engine.Gumps.GetGump( gumpId, out Gump gump ) )
{
GumpEvent?.Invoke( gumpId, senderSerial, gump );
}
Engine.Gumps.Remove( gumpId, buttonId );
}
private static void OnTargetSent( PacketReader reader )
{
if ( Engine.Player == null )
{
return;
}
TargetType targetType = (TargetType) reader.ReadByte();
Engine.Player.LastTargetType = targetType;
int senderSerial = reader.ReadInt32(); // sender serial
int flags = reader.ReadByte();
int serial = reader.ReadInt32();
int x = reader.ReadInt16();
int y = reader.ReadInt16();
int z = reader.ReadInt16();
int id = reader.ReadInt16();
if ( targetType == TargetType.Object && flags != 0x03 && serial != 0 )
{
Engine.Player.LastTargetSerial = serial;
Engine.Player.LastTargetType = targetType;
switch ( (TargetFlags) flags )
{
case TargetFlags.Harmful when Engine.Mobiles.GetMobile( serial, out Mobile enemyMobile ) &&
AliasCommands.GetAlias( "enemy" ) != serial:
TargetManager.GetInstance().SetEnemy( enemyMobile );
break;
case TargetFlags.Beneficial when Engine.Mobiles.GetMobile( serial, out Mobile friendMobile ) &&
MobileCommands.InFriendList( serial ) &&
AliasCommands.GetAlias( "friend" ) != serial:
TargetManager.GetInstance().SetFriend( friendMobile );
break;
}
}
Engine.TargetExists = false;
TargetSentEvent?.Invoke( targetType, senderSerial, flags, serial, x, y, z, id );
}
private static void OnNewClientVersion( PacketReader reader )
{
reader.ReadInt32();
Engine.ClientVersion = new Version( reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32(),
reader.ReadInt32() );
}
private static void Register( int packetId, int length, OnPacketReceive onReceive )
{
_handlers[packetId] = new PacketHandler( packetId, length, onReceive );
}
private static void RegisterExtended( int packetId, int length, OnPacketReceive onReceive )
{
_extendedHandlers[packetId] = new PacketHandler( packetId, length, onReceive );
}
internal static PacketHandler GetHandler( int packetId )
{
return _handlers[packetId];
}
private static PacketHandler GetExtendedHandler( int packetId )
{
return _extendedHandlers[packetId];
}
}
}
@@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ClassicAssist.UO.Network.PacketFilter
{
public class PacketFilter
{
private List<PacketFilterInfo> _filters = new List<PacketFilterInfo>();
public void Add( byte packet, PacketFilterCondition[] constraints )
{
Add( new PacketFilterInfo( packet, constraints ) );
}
public void Add( PacketFilterInfo pfi )
{
if ( _filters == null )
{
_filters = new List<PacketFilterInfo>();
}
_filters.Add( pfi );
}
public void Remove( PacketFilterInfo pfi )
{
if ( _filters == null )
{
_filters = new List<PacketFilterInfo>();
}
if ( _filters.Contains( pfi ) )
{
_filters.Remove( pfi );
}
}
public bool Remove( byte packet, PacketFilterCondition[] constraints )
{
if ( _filters == null )
{
_filters = new List<PacketFilterInfo>();
}
for ( int i = 0; i < _filters.Count; i++ )
{
if ( _filters[i].PacketID != packet )
{
continue;
}
if ( constraints == null && _filters[i].GetConditions() == null )
{
_filters.Remove( _filters[i] );
return true;
}
bool remove = true;
if ( constraints == null || _filters[i].GetConditions() == null ||
_filters[i].GetConditions().Length != constraints.Length )
{
continue;
}
for ( int x = 0; x < _filters[i].GetConditions().Length; x++ )
{
if ( !_filters[i].GetConditions()[x].Equals( constraints[x] ) )
{
remove = false;
}
}
if ( !remove )
{
continue;
}
_filters.Remove( _filters[i] );
return true;
}
return false;
}
public bool Contains( PacketFilterInfo pfi )
{
return _filters != null && _filters.Contains( pfi );
}
public int Count()
{
return _filters?.Count ?? 0;
}
public void Clear()
{
_filters?.Clear();
}
public bool MatchFilter( byte[] packet )
{
return MatchFilter( packet, out PacketFilterInfo _ );
}
public bool MatchFilter( byte[] packet, out PacketFilterInfo pfi )
{
pfi = null;
if ( _filters == null )
{
return false;
}
bool result = false;
for ( int i = 0; i < _filters.Count; i++ )
{
if ( packet[0] == _filters[i].PacketID )
{
if ( _filters[i].GetConditions() == null )
{
// No condition so just match packetid
result = true;
pfi = _filters[i];
}
else
{
foreach ( PacketFilterCondition fc in _filters[i].GetConditions() )
{
if ( fc.Position + fc.Length > packet.Length )
{
result = false;
continue;
}
byte[] tmp = new byte[fc.Length];
Buffer.BlockCopy( packet, fc.Position, tmp, 0, fc.Length );
if ( !tmp.SequenceEqual( fc.GetBytes() ) )
{
result = false;
break;
}
result = true;
pfi = _filters?[i] ?? null;
}
}
}
if ( result )
{
break;
}
}
if ( !result )
{
pfi = null;
}
return result;
}
public int MatchFilterAll( byte[] packet, out PacketFilterInfo[] pfis )
{
List<PacketFilterInfo> pfiList = new List<PacketFilterInfo>();
pfis = null;
if ( _filters == null )
{
return 0;
}
for ( int i = 0; i < _filters.Count; i++ )
{
if ( packet[0] != _filters[i].PacketID )
{
continue;
}
if ( _filters[i].GetConditions() == null )
{
// No condition so just match packetid
pfiList.Add( _filters[i] );
}
else
{
foreach ( PacketFilterCondition fc in _filters[i].GetConditions() )
{
if ( fc.Position + fc.Length > packet.Length )
{
continue;
}
byte[] tmp = new byte[fc.Length];
Buffer.BlockCopy( packet, fc.Position, tmp, 0, fc.Length );
if ( !tmp.SequenceEqual( fc.GetBytes() ) )
{
break;
}
pfiList.Add( _filters[i] );
}
}
}
pfis = pfiList.ToArray();
return pfiList.Count;
}
}
}
@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
namespace ClassicAssist.UO.Network.PacketFilter
{
public class PacketFilterCondition
{
private readonly byte[] _bytes;
public PacketFilterCondition( int position, byte[] bytes, int length )
{
Position = position;
_bytes = bytes;
Length = length;
}
public int Length { get; }
public int Position { get; }
public override bool Equals( object obj )
{
if ( !( obj is PacketFilterCondition pfc ) )
{
return false;
}
return Position == pfc.Position && Length == pfc.Length && _bytes.SequenceEqual( pfc.GetBytes() );
}
public byte[] GetBytes()
{
return _bytes;
}
public override int GetHashCode()
{
int hashCode = -285373213;
hashCode = hashCode * -1521134295 + Position.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<byte[]>.Default.GetHashCode( _bytes );
hashCode = hashCode * -1521134295 + Length.GetHashCode();
return hashCode;
}
}
}
@@ -0,0 +1,33 @@
namespace ClassicAssist.UO.Network.PacketFilter
{
public class PacketFilterConditions
{
public static PacketFilterCondition IntAtPositionCondition( int value, int position )
{
byte[] valueBytes = { (byte) ( value >> 24 ), (byte) ( value >> 16 ), (byte) ( value >> 8 ), (byte) value };
return new PacketFilterCondition( position, valueBytes, 4 );
}
public static PacketFilterCondition UIntAtPositionCondition( uint value, int position )
{
byte[] valueBytes = { (byte) ( value >> 24 ), (byte) ( value >> 16 ), (byte) ( value >> 8 ), (byte) value };
return new PacketFilterCondition( position, valueBytes, 4 );
}
public static PacketFilterCondition ShortAtPositionCondition( int value, int position )
{
byte[] valueBytes = { (byte) ( value >> 8 ), (byte) value };
return new PacketFilterCondition( position, valueBytes, 2 );
}
public static PacketFilterCondition ByteAtPositionCondition( int value, int position )
{
byte[] valueBytes = { (byte) value };
return new PacketFilterCondition( position, valueBytes, 1 );
}
}
}
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ClassicAssist.UO.Network.PacketFilter
{
public class PacketFilterInfo
{
private PacketFilterCondition[] _conditions;
public PacketFilterInfo( int packetId, Action<byte[], PacketFilterInfo> onMatch = null )
{
PacketID = packetId;
_conditions = null;
Action = onMatch;
}
public PacketFilterInfo( int packetid, PacketFilterCondition[] conditions,
Action<byte[], PacketFilterInfo> onMatch = null )
{
PacketID = packetid;
_conditions = conditions;
Action = onMatch;
}
public Action<byte[], PacketFilterInfo> Action { get; set; }
public int PacketID { get; set; }
public override bool Equals( object obj )
{
if ( !( obj is PacketFilterInfo pfi ) )
{
return false;
}
// Disabled because won't remove filter as Action == null in Remove methods.
//if ( Action != pfi.Action )
// return false;
if ( GetConditions() == null && pfi.GetConditions() != null )
{
return false;
}
if ( pfi.GetConditions() == null && GetConditions() != null )
{
return false;
}
if ( GetConditions() == null && pfi.GetConditions() == null )
{
return PacketID == pfi.PacketID;
}
return PacketID == pfi.PacketID && GetConditions().SequenceEqual( pfi.GetConditions() );
}
public PacketFilterCondition[] GetConditions()
{
return _conditions;
}
public override int GetHashCode()
{
int hashCode = -1985156662;
hashCode = hashCode * -1521134295 +
EqualityComparer<PacketFilterCondition[]>.Default.GetHashCode( _conditions );
hashCode = hashCode * -1521134295 + PacketID.GetHashCode();
hashCode = hashCode * -1521134295 +
EqualityComparer<Action<byte[], PacketFilterInfo>>.Default.GetHashCode( Action );
return hashCode;
}
public void SetConditions( PacketFilterCondition[] value )
{
_conditions = value;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat( "PacketID: 0x{0:X}\r\n", PacketID );
if ( _conditions == null )
{
sb.AppendLine( "No conditions." );
}
else
{
foreach ( PacketFilterCondition pfc in _conditions )
{
sb.Append( pfc );
}
}
return sb.ToString();
}
}
}
@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ClassicAssist.UO.Network.PacketFilter
{
public class PacketWaitEntries
{
public delegate void dWaitEntryAddedRemoved( PacketWaitEntry entry );
private readonly List<PacketWaitEntry> _waitEntries = new List<PacketWaitEntry>();
private readonly object _waitEntryLock = new object();
public event dWaitEntryAddedRemoved WaitEntryAddedEvent;
public event dWaitEntryAddedRemoved WaitEntryRemovedEvent;
public PacketWaitEntry Add( PacketFilterInfo pfi, PacketDirection direction, bool autoRemove = false,
bool filteredOnly = false )
{
PacketWaitEntry we = new PacketWaitEntry
{
PFI = pfi,
Lock = new AutoResetEvent( false ),
PacketDirection = direction,
AutoRemove = autoRemove,
MatchFilteredOnly = filteredOnly
};
lock ( _waitEntryLock )
{
_waitEntries.Add( we );
WaitEntryAddedEvent?.Invoke( we );
}
return we;
}
public bool CheckWait( byte[] packet, PacketDirection direction, bool filteredPacket = false )
{
lock ( _waitEntryLock )
{
if ( _waitEntries.Count == 0 )
{
return false;
}
}
List<PacketWaitEntry> matchedEntries = new List<PacketWaitEntry>();
lock ( _waitEntryLock )
{
foreach ( PacketWaitEntry t in _waitEntries.Where( t => packet[0] == t.PFI.PacketID ).Where( t =>
direction == t.PacketDirection &&
( filteredPacket ? t.MatchFilteredOnly : !t.MatchFilteredOnly ) ) )
{
if ( t.PFI.GetConditions() == null )
{
// No condition so just match packetid
matchedEntries.Add( t );
}
else
{
bool result = false;
foreach ( PacketFilterCondition fc in t.PFI.GetConditions() )
{
if ( fc.Position + fc.Length > packet.Length )
{
result = false;
break;
}
byte[] tmp = new byte[fc.Length];
Buffer.BlockCopy( packet, fc.Position, tmp, 0, fc.Length );
if ( !tmp.SequenceEqual( fc.GetBytes() ) )
{
result = false;
break;
}
result = true;
}
if ( result )
{
matchedEntries.Add( t );
}
}
}
}
if ( matchedEntries.Count == 0 )
{
return false;
}
List<PacketWaitEntry> removeList = new List<PacketWaitEntry>();
foreach ( PacketWaitEntry entry in matchedEntries )
{
entry.Packet = new byte[packet.Length];
Buffer.BlockCopy( packet, 0, entry.Packet, 0, packet.Length );
entry.Lock.Set();
entry.PFI.Action?.Invoke( packet, entry.PFI );
if ( entry.AutoRemove )
{
removeList.Add( entry );
}
}
removeList.ForEach( Remove );
return true;
}
public void Clear()
{
lock ( _waitEntryLock )
{
foreach ( PacketWaitEntry we in _waitEntries )
{
we.Lock.Set();
}
_waitEntries?.Clear();
}
}
public PacketWaitEntry[] GetEntries()
{
lock ( _waitEntryLock )
{
return _waitEntries?.ToArray();
}
}
public void Remove( PacketWaitEntry we )
{
lock ( _waitEntryLock )
{
_waitEntries.Remove( we );
WaitEntryRemovedEvent?.Invoke( we );
}
}
public void RemoveRange( IEnumerable<PacketWaitEntry> wes )
{
lock ( _waitEntryLock )
{
foreach ( PacketWaitEntry we in wes )
{
_waitEntries.Remove( we );
WaitEntryRemovedEvent?.Invoke( we );
}
}
}
}
}
@@ -0,0 +1,14 @@
using System.Threading;
namespace ClassicAssist.UO.Network.PacketFilter
{
public class PacketWaitEntry
{
public bool AutoRemove { get; set; }
public AutoResetEvent Lock { get; set; }
public bool MatchFilteredOnly { get; set; } = false;
public byte[] Packet { get; set; }
public PacketDirection PacketDirection { get; set; }
public PacketFilterInfo PFI { get; set; }
}
}
@@ -0,0 +1,20 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network
{
internal delegate void OnPacketReceive( PacketReader reader );
internal class PacketHandler
{
public PacketHandler( int packetId, int length, OnPacketReceive onReceive )
{
PacketID = packetId;
Length = length;
OnReceive = onReceive;
}
public int Length { get; set; }
public int PacketID { get; set; }
internal OnPacketReceive OnReceive { get; set; }
}
}
@@ -0,0 +1,17 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class AcceptPartyInvitation : BasePacket
{
public AcceptPartyInvitation( int partyLeaderSerial )
{
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 10 );
_writer.Write( (short) 0x06 );
_writer.Write( (byte) 0x08 );
_writer.Write( partyLeaderSerial );
}
}
}
@@ -0,0 +1,14 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class AttackRequest : BasePacket
{
public AttackRequest( int serial )
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0x05 );
_writer.Write( serial );
}
}
}
@@ -0,0 +1,31 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public abstract class BasePacket
{
protected PacketWriter _writer;
protected BasePacket()
{
}
protected BasePacket( int length )
{
_writer = new PacketWriter( length );
}
protected BasePacket( PacketDirection direction )
{
Direction = direction;
}
public PacketDirection Direction { get; set; } = PacketDirection.Any;
public virtual byte[] ToArray()
{
return _writer?.ToArray();
}
}
}
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class BatchQueryProperties : BasePacket
{
public BatchQueryProperties( int serial )
{
_writer = new PacketWriter();
_writer.Write( (byte) 0xD6 );
_writer.Write( (short) 7 );
_writer.Write( serial );
}
public BatchQueryProperties( IReadOnlyCollection<int> serials )
{
_writer = new PacketWriter();
_writer.Write( (byte) 0xD6 );
_writer.Write( (short) ( 3 + serials.Count * 4 ) );
foreach ( int serial in serials )
{
_writer.Write( serial );
}
}
}
}
@@ -0,0 +1,27 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class CancelTargetCursor : BasePacket
{
public CancelTargetCursor( uint senderSerial )
{
_writer = new PacketWriter( 19 );
_writer.Write( (byte) 0x6C );
_writer.Write( (byte) 0 );
_writer.Write( senderSerial );
_writer.Write( (byte) 3 );
_writer.Fill();
}
public CancelTargetCursor( int senderSerial )
{
_writer = new PacketWriter( 19 );
_writer.Write( (byte) 0x6C );
_writer.Write( (byte) 0 );
_writer.Write( senderSerial );
_writer.Write( (byte) 3 );
_writer.Fill();
}
}
}
@@ -0,0 +1,39 @@
using ClassicAssist.Data.Spells;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class CastSpell : BasePacket, IMacroCommandParser
{
public CastSpell()
{
}
public CastSpell( int id )
{
_writer = new PacketWriter( 9 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 9 );
_writer.Write( (short) 0x1C );
_writer.Write( (short) 0x02 );
_writer.Write( (short) id );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xBF || packet[4] != 0x1C || direction != PacketDirection.Outgoing )
{
return null;
}
int spellId = ( packet[7] << 8 ) | packet[8];
SpellManager manager = SpellManager.GetInstance();
SpellData sd = manager.GetSpellData( spellId ) ?? manager.GetMasteryData( spellId );
return sd != null ? $"Cast(\"{sd.Name}\")\r\n" : null;
}
}
}
@@ -0,0 +1,15 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class ChangeCombatant : BasePacket
{
public ChangeCombatant( int serial ) : base( PacketDirection.Incoming )
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0xAA );
_writer.Write( serial );
}
}
}
@@ -0,0 +1,18 @@
using ClassicAssist.Data.Skills;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class ChangeSkillLock : BasePacket
{
public ChangeSkillLock( SkillEntry skill, LockStatus lockStatus )
{
_writer = new PacketWriter( 6 );
_writer.Write( (byte) 0x3A );
_writer.Write( (short) 6 );
_writer.Write( (byte) 0 );
_writer.Write( (byte) skill.Skill.ID );
_writer.Write( (byte) lockStatus );
}
}
}
@@ -0,0 +1,54 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class ChangeStatLock : BasePacket, IMacroCommandParser
{
public ChangeStatLock()
{
}
public ChangeStatLock( StatType stat, LockStatus lockStatus )
{
_writer = new PacketWriter( 7 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 7 );
_writer.Write( (short) 0x1A );
_writer.Write( (byte) stat );
_writer.Write( (byte) lockStatus );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( direction != PacketDirection.Outgoing || packet[0] != 0xBF || packet[4] != 0x1A )
{
return null;
}
StatType stat = (StatType) packet[5];
LockStatus lockStatus = (LockStatus) packet[6];
return $"SetStatus(\"{stat.ToString().ToLower()}\", \"{lockStatus.ToString().ToLower()}\")\r\n";
}
}
}
@@ -0,0 +1,16 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class ClearWeaponAbility : BasePacket
{
public ClearWeaponAbility()
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 5 );
_writer.Write( (short) 0x21 );
}
}
}
@@ -0,0 +1,17 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class CloseClientGump : BasePacket
{
public CloseClientGump( uint gumpID )
{
_writer = new PacketWriter( 13 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 13 );
_writer.Write( (short) 0x04 );
_writer.Write( gumpID );
_writer.Fill();
}
}
}
@@ -0,0 +1,19 @@
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class CompressedGump : IMacroCommandParser
{
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xDD || direction != PacketDirection.Incoming )
{
return null;
}
int serial = ( packet[7] << 24 ) | ( packet[8] << 16 ) | ( packet[9] << 8 ) | packet[10];
return $"WaitForGump(0x{serial:x}, 5000)\r\n";
}
}
}
@@ -0,0 +1,33 @@
using System;
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class ContainerContentUpdate : BasePacket
{
public ContainerContentUpdate( int serial, int id, Direction direction, int amount, int x, int y, int grid,
int parentSerial, int hue ) : base( PacketDirection.Incoming )
{
bool isNew = Engine.ClientVersion == null || Engine.ClientVersion >= new Version( 6, 0, 1, 7 );
_writer = new PacketWriter( isNew ? 21 : 20 );
_writer.Write( (byte) 0x25 );
_writer.Write( serial );
_writer.Write( (short) id );
_writer.Write( (byte) direction );
_writer.Write( (short) amount );
_writer.Write( (short) x );
_writer.Write( (short) y );
if ( isNew )
{
_writer.Write( (byte) grid );
}
_writer.Write( parentSerial );
_writer.Write( (short) hue );
}
}
}
@@ -0,0 +1,30 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network.Packets
{
public class ContainerContentsPacket : BasePacket
{
public ContainerContentsPacket( ItemCollection collection )
{
_writer = new PacketWriter( 5 + collection.GetTotalItemCount() * 20 );
_writer.Write( (byte) 0x3C );
_writer.Write( (short) ( collection.GetTotalItemCount() * 20 ) );
_writer.Write( (short) collection.GetTotalItemCount() );
foreach ( Item item in collection.GetItems() )
{
_writer.Write( item.Serial );
_writer.Write( (short) item.ID );
_writer.Write( (byte) 0 ); // itemid offset
_writer.Write( (short) item.Count );
_writer.Write( (short) item.X );
_writer.Write( (short) item.Y );
_writer.Write( (byte) item.Grid );
_writer.Write( collection.Serial );
_writer.Write( (short) item.Hue );
}
}
}
}
@@ -0,0 +1,39 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class ContextMenuClick : BasePacket, IMacroCommandParser
{
public ContextMenuClick()
{
}
public ContextMenuClick( int serial, int index )
{
_writer = new PacketWriter( 11 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 11 );
_writer.Write( (short) 0x15 );
_writer.Write( serial );
_writer.Write( (short) index );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xBF || packet[4] != 0x15 || direction != PacketDirection.Outgoing )
{
return null;
}
PacketReader reader = new PacketReader( packet, length, false );
reader.ReadInt16();
int serial = reader.ReadInt32();
int index = reader.ReadInt16();
return $"WaitForContext(0x{serial:x}, {index}, 5000)\r\n";
}
}
}
@@ -0,0 +1,16 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class ContextMenuRequest : BasePacket
{
public ContextMenuRequest( int serial )
{
_writer = new PacketWriter( 9 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 9 );
_writer.Write( (short) 0x13 );
_writer.Write( serial );
}
}
}
@@ -0,0 +1,45 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class DisarmRequest : BasePacket, IMacroCommandParser
{
public DisarmRequest()
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 5 );
_writer.Write( (short) 0x09 );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( direction == PacketDirection.Outgoing && packet[0] == 0xBF && packet[4] == 0x09 )
{
return "SetAbility(\"Disarm\")\r\n";
}
return null;
}
}
}
@@ -0,0 +1,42 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class DisplayQuestPointer : BasePacket
{
public DisplayQuestPointer( bool active, int x, int y, int serial = 0 )
{
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0xBA );
_writer.Write( (byte) ( active ? 1 : 0 ) );
_writer.Write( (short) x );
_writer.Write( (short) y );
if ( Engine.ClientVersion >= new Version( 7, 0, 9, 0 ) )
{
_writer.Write( serial );
}
}
}
}
@@ -0,0 +1,27 @@
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network.Packets
{
public class DragItem : BasePacket
{
public DragItem( int serial, int amount, bool checkAmount = false )
{
if ( checkAmount && amount == -1 )
{
Item item = Engine.Items.GetItem( serial );
if ( item != null )
{
amount = item.Count;
}
}
_writer = new PacketWriter( 7 );
_writer.Write( (byte) 0x07 );
_writer.Write( serial );
_writer.Write( (short) amount );
}
}
}
@@ -0,0 +1,49 @@
using System;
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class DropItem : BasePacket, IMacroCommandParser
{
public DropItem()
{
}
public DropItem( int serial, int containerSerial, int x, int y, int z )
{
_writer = new PacketWriter( 15 );
_writer.Write( (byte) 0x08 );
_writer.Write( serial );
_writer.Write( (short) x );
_writer.Write( (short) y );
_writer.Write( (sbyte) z );
if ( Engine.ClientVersion == null || Engine.ClientVersion >= new Version( 6, 0, 1, 7 ) )
{
_writer.Write( (byte) 0 );
}
_writer.Write( containerSerial );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x08 || direction != PacketDirection.Outgoing )
{
return null;
}
int serial = ( packet[1] << 24 ) | ( packet[2] << 16 ) | ( packet[3] << 8 ) | packet[4];
int containerSerial = ( packet[11] << 24 ) | ( packet[12] << 16 ) | ( packet[13] << 8 ) | packet[14];
if ( serial == 0 || containerSerial == 0 )
{
return null;
}
return $"MoveItem(0x{serial:x}, 0x{containerSerial:x})\r\n";
}
}
}
@@ -0,0 +1,34 @@
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class EquipLastWeapon : BasePacket, IMacroCommandParser
{
public EquipLastWeapon()
{
if ( Engine.Player == null )
{
return;
}
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0xD7 );
_writer.Write( (short) 10 ); // size
_writer.Write( Engine.Player.Serial );
_writer.Write( (short) 0x1E );
_writer.Write( (byte) 0x0A );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xD7 || packet[8] != 0x1E || packet[9] != 0x0A || direction != PacketDirection.Outgoing )
{
return null;
}
return "EquipLastWeapon()\r\n";
}
}
}
@@ -0,0 +1,35 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class EquipRequest : BasePacket, IMacroCommandParser
{
public EquipRequest()
{
}
public EquipRequest( int serial, Layer layer, int containerSerial )
{
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0x13 );
_writer.Write( serial );
_writer.Write( (byte) layer );
_writer.Write( containerSerial );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x13 || direction != PacketDirection.Outgoing )
{
return null;
}
int serial = ( packet[1] << 24 ) | ( packet[2] << 16 ) | ( packet[3] << 8 ) | packet[4];
Layer layer = (Layer) packet[5];
return $"EquipItem(0x{serial:x}, \"{layer.ToString()}\")\r\n";
}
}
}
@@ -0,0 +1,53 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class GuildButtonRequest : BasePacket, IMacroCommandParser
{
public GuildButtonRequest()
{
if ( Engine.Player == null )
{
return;
}
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0xD7 );
_writer.Write( (short) 10 ); // size
_writer.Write( Engine.Player.Serial );
_writer.Write( (short) 0x28 );
_writer.Write( (byte) 0x0A );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xD7 || packet[8] != 0x28 || packet[9] != 0x0A || direction != PacketDirection.Outgoing )
{
return null;
}
return "OpenGuildGump()\r\n";
}
}
}
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class GumpButtonClick : BasePacket, IMacroCommandParser
{
public GumpButtonClick()
{
}
public GumpButtonClick( int gumpID, int serial, int buttonID, IReadOnlyCollection<int> switches = null )
{
//TODO switches etc
_writer = new PacketWriter( 23 + ( switches?.Count * 4 ?? 0 ) );
_writer.Write( (byte) 0xB1 );
_writer.Write( (short) ( 23 + ( switches?.Count * 4 ?? 0 ) ) );
_writer.Write( serial );
_writer.Write( gumpID );
_writer.Write( buttonID );
if ( switches != null )
{
_writer.Write( switches.Count );
foreach ( int @switch in switches )
{
_writer.Write( @switch );
}
}
_writer.Fill();
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xB1 || direction != PacketDirection.Outgoing )
{
return null;
}
uint gumpId = (uint) ( ( packet[7] << 24 ) | ( packet[8] << 16 ) | ( packet[9] << 8 ) | packet[10] );
int buttonId = ( packet[11] << 24 ) | ( packet[12] << 16 ) | ( packet[13] << 8 ) | packet[14];
return $"ReplyGump(0x{gumpId:x}, {buttonId})\r\n";
}
}
}
@@ -0,0 +1,9 @@
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public interface IMacroCommandParser
{
string Parse( byte[] packet, int length, PacketDirection direction );
}
}
@@ -0,0 +1,32 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class InvokeVirtue : BasePacket, IMacroCommandParser
{
public InvokeVirtue()
{
}
public InvokeVirtue( Virtues virtue )
{
_writer = new PacketWriter( 6 );
_writer.Write( (byte) 0x12 );
_writer.Write( (short) 6 );
_writer.Write( (byte) 0xF4 );
_writer.Write( (byte) virtue );
_writer.Write( (byte) 0 );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x12 || packet[3] != 0xF4 || direction != PacketDirection.Outgoing )
{
return null;
}
return $"InvokeVirtue(\"{(Virtues) packet[4]}\")\r\n";
}
}
}
@@ -0,0 +1,18 @@
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class ItemListMenu : BasePacket, IMacroCommandParser
{
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x7C || direction != PacketDirection.Incoming )
{
return null;
}
int gumpId = ( packet[7] << 8 ) | packet[8];
return $"WaitForMenu(0x{gumpId:x}, 5000)\r\n";
}
}
}
@@ -0,0 +1,32 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class LookRequest : BasePacket, IMacroCommandParser
{
public LookRequest()
{
}
public LookRequest( int serial )
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0x09 );
_writer.Write( serial );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
//if ( basePacket[0] != 0x09 || direction != PacketDirection.Outgoing )
//{
// return null;
//}
//int serial = ( basePacket[1] << 24 ) | ( basePacket[2] << 16 ) | ( basePacket[3] << 8 ) | basePacket[4];
//return $"ClickObject(0x{serial:x})\r\nPause({Options.CurrentOptions.ActionDelayMS})\r\n";
return null;
}
}
}
@@ -0,0 +1,71 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network.Packets
{
public class MenuButtonClick : BasePacket, IMacroCommandParser
{
public MenuButtonClick()
{
}
public MenuButtonClick( int gumpId, int serial, int index, int id = 0, int hue = 0 )
{
if ( serial == -1 )
{
if ( !Engine.Menus.GetMenu( gumpId, out Menu menu ) )
{
return;
}
serial = menu.Serial;
}
_writer = new PacketWriter( 13 );
_writer.Write( (byte) 0x7D );
_writer.Write( serial );
_writer.Write( (short) gumpId );
_writer.Write( (short) index );
_writer.Write( (short) id );
_writer.Write( (short) hue );
Engine.Menus?.Remove( gumpId );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x7D || direction != PacketDirection.Outgoing )
{
return null;
}
int gumpId = ( packet[5] << 8 ) | packet[6];
int index = ( packet[7] << 8 ) | packet[8];
int id = ( packet[9] << 8 ) | packet[10];
int hue = ( packet[11] << 8 ) | packet[12];
return $"ReplyMenu(0x{gumpId:x}, {index}, 0x{id:x}, {hue})\r\n";
}
}
}
@@ -0,0 +1,60 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using System.Linq;
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network.Packets
{
public class MobileIncoming : BasePacket
{
public MobileIncoming( Mobile mobile, ItemCollection equipment, int overrideHue = 0 )
{
bool useNewIncoming = Engine.ClientVersion == null || Engine.ClientVersion >= new Version( 7, 0, 33, 1 );
int len = 23 + equipment.Count() * 9;
_writer = new PacketWriter( len );
_writer.Write( (byte) 0x78 );
_writer.Write( (short) len );
_writer.Write( mobile.Serial );
_writer.Write( (short) mobile.ID );
_writer.Write( (short) mobile.X );
_writer.Write( (short) mobile.Y );
_writer.Write( (sbyte) mobile.Z );
_writer.Write( (byte) mobile.Direction );
_writer.Write( (short) ( overrideHue > 0 ? overrideHue : mobile.Hue ) );
_writer.Write( (byte) mobile.Status );
_writer.Write( (byte) mobile.Notoriety );
foreach ( Item item in equipment.GetItems() )
{
_writer.Write( item.Serial );
_writer.Write( (short) ( useNewIncoming ? item.ID : item.ID | 0x8000 ) );
_writer.Write( (byte) item.Layer );
_writer.Write( (short) ( overrideHue > 0 ? overrideHue : item.Hue ) );
}
_writer.Write( 0 );
}
}
}
@@ -0,0 +1,42 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network.Packets
{
public class MobileMoving : BasePacket
{
public MobileMoving( Mobile mobile, int hueOverride = 0 )
{
_writer = new PacketWriter( 17 );
_writer.Write( (byte) 0x77 );
_writer.Write( mobile.Serial );
_writer.Write( (short) mobile.ID );
_writer.Write( (short) mobile.X );
_writer.Write( (short) mobile.Y );
_writer.Write( (sbyte) mobile.Z );
_writer.Write( (byte) mobile.Direction );
_writer.Write( (short) ( hueOverride > 0 ? hueOverride : mobile.Hue ) );
_writer.Write( (byte) mobile.Status );
_writer.Write( (byte) mobile.Notoriety );
}
}
}
@@ -0,0 +1,16 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class MobileQuery : BasePacket
{
public MobileQuery( int serial, MobileQueryType queryType = MobileQueryType.StatsRequest )
{
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0x34 );
_writer.Write( 0xEDEDEDED );
_writer.Write( (byte) queryType );
_writer.Write( serial );
}
}
}
@@ -0,0 +1,23 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class MobileUpdate : BasePacket
{
public MobileUpdate( int serial, int id, int hue, MobileStatus flags, int x, int y, int z, Direction direction )
{
_writer = new PacketWriter( 19 );
_writer.Write( (byte) 0x20 );
_writer.Write( serial );
_writer.Write( (short) id );
_writer.Write( (byte) 0 );
_writer.Write( (short) hue );
_writer.Write( (byte) flags );
_writer.Write( (short) x );
_writer.Write( (short) y );
_writer.Write( (short) 0 );
_writer.Write( (byte) direction );
_writer.Write( (sbyte) z );
}
}
}
@@ -0,0 +1,20 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class MovementRequest : BasePacket, IMacroCommandParser
{
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x02 || direction != PacketDirection.Outgoing )
{
return null;
}
Direction d = (Direction) packet[1];
return $"Walk(\"{d.ToString()}\")\r\n";
}
}
}
@@ -0,0 +1,36 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class MultiTarget : BasePacket, IMacroCommandParser
{
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x99 )
{
return null;
}
return direction == PacketDirection.Incoming ? "WaitForTarget(5000)\r\n" : null;
}
}
}
@@ -0,0 +1,11 @@
namespace ClassicAssist.UO.Network.Packets
{
public class Ping : BasePacket
{
public Ping( byte value ) : base( 2 )
{
_writer.Write( (byte) 0x73 );
_writer.Write( value );
}
}
}
@@ -0,0 +1,20 @@
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class PlaySound : BasePacket
{
public PlaySound( int id )
{
_writer = new PacketWriter( 12 );
_writer.Write( (byte) 0x54 );
_writer.Write( (byte) 0x01 );
_writer.Write( (short) id );
_writer.Write( (short) 0 );
_writer.Write( (short) ( Engine.Player?.X ?? 0 ) );
_writer.Write( (short) ( Engine.Player?.Y ?? 0 ) );
_writer.Write( (short) ( Engine.Player?.Z ?? 0 ) );
}
}
}
@@ -0,0 +1,35 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class QueryProperties : BasePacket
{
public QueryProperties( int serial )
{
_writer = new PacketWriter( 9 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 9 );
_writer.Write( (short) 0x10 );
_writer.Write( serial );
}
}
}
@@ -0,0 +1,53 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class QuestsButtonRequest : BasePacket, IMacroCommandParser
{
public QuestsButtonRequest()
{
if ( Engine.Player == null )
{
return;
}
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0xD7 );
_writer.Write( (short) 10 ); // size
_writer.Write( Engine.Player.Serial );
_writer.Write( (short) 0x32 );
_writer.Write( (byte) 0x0A );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xD7 || packet[8] != 0x32 || packet[9] != 0x0A || direction != PacketDirection.Outgoing )
{
return null;
}
return "OpenQuestsGump()\r\n";
}
}
}
@@ -0,0 +1,17 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class RejectPartyInvitation : BasePacket
{
public RejectPartyInvitation( int partyLeaderSerial )
{
_writer = new PacketWriter( 10 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 10 );
_writer.Write( (short) 0x06 );
_writer.Write( (byte) 0x09 );
_writer.Write( partyLeaderSerial );
}
}
}
@@ -0,0 +1,33 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class RemoveObject : BasePacket
{
public RemoveObject( int serial )
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0x1D );
_writer.Write( serial );
}
}
}
@@ -0,0 +1,35 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class RenameRequest : BasePacket, IMacroCommandParser
{
public RenameRequest()
{
}
public RenameRequest( int serial, string name )
{
_writer = new PacketWriter( 35 );
_writer.Write( (byte) 0x75 );
_writer.Write( serial );
_writer.WriteAsciiFixed( name, 30 );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x75 || direction != PacketDirection.Outgoing )
{
return null;
}
PacketReader reader = new PacketReader( packet, length, true );
int serial = reader.ReadInt32();
string name = reader.ReadString( 30 );
return $"Rename(0x{serial:x}, \"{name}\")\r\n";
}
}
}
@@ -0,0 +1,14 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class Resync : BasePacket
{
public Resync()
{
_writer = new PacketWriter( 3 );
_writer.Write( (byte) 0x22 );
_writer.Write( (short) 0 );
}
}
}
@@ -0,0 +1,42 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System.IO;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class SAWorldItem : BasePacket
{
public SAWorldItem( byte[] packet, int length, int hueOverride )
{
_writer = new PacketWriter( length );
_writer.Write( packet, 0, length );
if ( hueOverride <= 0 )
{
return;
}
_writer.Seek( 21, SeekOrigin.Begin );
_writer.Write( (short) hueOverride );
_writer.Seek( 0, SeekOrigin.End );
}
}
}
@@ -0,0 +1,21 @@
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class SetWeaponAbility : BasePacket
{
public SetWeaponAbility( int abilityIndex )
{
_writer = new PacketWriter( 15 );
_writer.Write( (byte) 0xD7 );
_writer.Write( (short) 15 );
_writer.Write( Engine.Player?.Serial ?? 0 );
_writer.Write( (short) 0x19 );
_writer.Write( (byte) 0 );
_writer.Write( abilityIndex );
_writer.Write( (byte) 0x0A );
}
}
}
@@ -0,0 +1,45 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class StunRequest : BasePacket, IMacroCommandParser
{
public StunRequest()
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 5 );
_writer.Write( (short) 0x0A );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( direction == PacketDirection.Outgoing && packet[0] == 0xBF && packet[4] == 0x0A )
{
return "SetAbility(\"Stun\")\r\n";
}
return null;
}
}
}
@@ -0,0 +1,97 @@
using ClassicAssist.Shared;
using ClassicAssist.Data;
using ClassicAssist.Data.Macros.Commands;
using ClassicAssist.Shared.Resources;
using ClassicAssist.Shared.UO;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
using ClassicAssist.UO.Objects;
namespace ClassicAssist.UO.Network.Packets
{
public class Target : BasePacket, IMacroCommandParser
{
public Target()
{
}
public Target( int senderSerial, Entity entity, bool cancelClientCursor ) : this( TargetType.Object,
senderSerial, TargetFlags.None, entity.Serial, -1, -1, -1, entity.ID, cancelClientCursor )
{
}
public Target( TargetType targetType, int senderSerial, TargetFlags flags, int targetSerial, int x, int y,
int z, int id, bool cancelClientCursor )
{
if ( senderSerial == -1 )
{
senderSerial = Engine.TargetSerial;
}
if ( targetSerial > 0 )
{
Engine.Player.LastTargetSerial = targetSerial;
Engine.Player.LastTargetType = targetType;
}
if ( Engine.TargetFlags == TargetFlags.Harmful &&
Options.CurrentOptions.PreventTargetingFriendsWithHarmful &&
MobileCommands.InFriendList( targetSerial ) )
{
Commands.SystemMessage( Strings.Target_blocked____try_again___ );
Commands.ResendTargetToClient();
return;
}
_writer = new PacketWriter( 19 );
_writer.Write( (byte) 0x6C );
_writer.Write( (byte) targetType );
_writer.Write( senderSerial );
_writer.Write( (byte) flags );
_writer.Write( targetSerial );
_writer.Write( (short) x );
_writer.Write( (short) y );
_writer.Write( (short) z );
_writer.Write( (short) id );
Engine.TargetExists = false;
if ( cancelClientCursor )
{
Engine.SendPacketToClient( new Target( targetType, senderSerial, TargetFlags.Cancel, targetSerial, x, y,
z, id, false ) );
Engine.AddSendPreFilter( new PacketFilterInfo( 0x6C,
new[] { PacketFilterConditions.IntAtPositionCondition( senderSerial, 2 ) },
( p, pfi ) => { Engine.RemoveSendPreFilter( pfi ); } ) );
}
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x6C )
{
return null;
}
if ( direction == PacketDirection.Incoming )
{
return "WaitForTarget(5000)\r\n";
}
if ( packet[1] == 0 )
{
uint serial = (uint) ( ( packet[7] << 24 ) | ( packet[8] << 16 ) | ( packet[9] << 8 ) | packet[10] );
return $"Target(0x{serial:x})\r\n";
}
int x = ( packet[11] << 8 ) | packet[12];
int y = ( packet[13] << 8 ) | packet[14];
int z = (sbyte) ( packet[15] << 8 ) | (sbyte) packet[16];
int id = ( packet[17] << 8 ) | packet[18];
return id == 0 ? $"TargetXYZ({x}, {y}, {z})\r\n" : $"TargetXYZ({x}, {y}, {z}, {id})\r\n";
}
}
}
@@ -0,0 +1,36 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class TargetByResource : BasePacket
{
public TargetByResource( int serial, int resourceType )
{
_writer = new PacketWriter( 11 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 11 );
_writer.Write( (short) 0x30 );
_writer.Write( serial );
_writer.Write( (short) resourceType );
}
}
}
@@ -0,0 +1,18 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class ToggleGargoyleFlying : BasePacket
{
public ToggleGargoyleFlying()
{
_writer = new PacketWriter( 11 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 11 );
_writer.Write( (short) 0x32 );
_writer.Write( (short) 1 );
_writer.Write( 0 );
}
}
}
@@ -0,0 +1,54 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.Shared.Resources;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class UnicodePromptCancel : BasePacket, IMacroCommandParser
{
public UnicodePromptCancel()
{
}
public UnicodePromptCancel( int senderSerial, int promptId )
{
_writer = new PacketWriter( 20 );
_writer.Write( (byte) 0xC2 );
_writer.Write( (short) 20 );
_writer.Write( senderSerial );
_writer.Write( promptId );
_writer.Write( 0 );
_writer.WriteAsciiFixed( Strings.UO_LOCALE, 4 );
_writer.Fill();
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xC2 || direction != PacketDirection.Outgoing )
{
return null;
}
return packet[14] != 0x00 ? null : "CancelPrompt()\r\n";
}
}
}
@@ -0,0 +1,24 @@
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class UnicodePromptRequest : BasePacket, IMacroCommandParser
{
// ReSharper disable once EmptyConstructor
public UnicodePromptRequest()
{
// TODO
// byte[] packet = new byte[] { 0xC2, 0x00, 0x15, 0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] == 0xC2 && direction == PacketDirection.Incoming )
{
return "WaitForPrompt(5000)\r\n";
}
return null;
}
}
}
@@ -0,0 +1,47 @@
using System.Text;
using ClassicAssist.Shared.Resources;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class UnicodePromptResponse : BasePacket, IMacroCommandParser
{
public UnicodePromptResponse()
{
}
public UnicodePromptResponse( int senderSerial, int promptId, string text )
{
byte[] textBytes = Encoding.Unicode.GetBytes( text );
int len = 19 + textBytes.Length;
_writer = new PacketWriter( len );
_writer.Write( (byte) 0xC2 );
_writer.Write( (short) len );
_writer.Write( senderSerial );
_writer.Write( promptId );
_writer.Write( 1 );
_writer.WriteAsciiFixed( Strings.UO_LOCALE, 4 );
_writer.Write( textBytes, 0, textBytes.Length );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0xC2 || direction != PacketDirection.Outgoing )
{
return null;
}
if ( packet[14] == 0x00 )
{
return null;
}
string text = Encoding.Unicode.GetString( packet, 19, packet.Length - 20 ).Trim( '\0' );
return $"PromptMsg(\"{text}\")\r\n";
}
}
}
@@ -0,0 +1,27 @@
using System.Text;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class UnicodeText : BasePacket
{
public UnicodeText( int serial, int graphic, JournalSpeech speechType, int hue, int font, string lang,
string name, string text )
{
byte[] textBytes = Encoding.BigEndianUnicode.GetBytes( text );
int len = 48 + textBytes.Length;
_writer = new PacketWriter( len );
_writer.Write( (byte) 0xAE );
_writer.Write( (short) len );
_writer.Write( serial );
_writer.Write( (ushort) graphic );
_writer.Write( (byte) speechType );
_writer.Write( (short) hue );
_writer.Write( (short) font );
_writer.WriteAsciiFixed( lang, 4 );
_writer.WriteAsciiFixed( name, 30 );
_writer.Write( textBytes, 0, textBytes.Length );
}
}
}
@@ -0,0 +1,31 @@
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
namespace ClassicAssist.UO.Network.Packets
{
public class UseObject : BasePacket, IMacroCommandParser
{
public UseObject()
{
}
public UseObject( int serial )
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0x06 );
_writer.Write( serial );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x06 || direction != PacketDirection.Outgoing )
{
return null;
}
int serial = ( packet[1] << 24 ) | ( packet[2] << 16 ) | ( packet[3] << 8 ) | packet[4];
return $"UseObject(0x{serial:x})\r\n";
}
}
}
@@ -0,0 +1,67 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using System;
using ClassicAssist.UO.Data;
using ClassicAssist.UO.Network.PacketFilter;
using static System.Text.Encoding;
namespace ClassicAssist.UO.Network.Packets
{
public class UseSkill : BasePacket, IMacroCommandParser
{
public UseSkill()
{
}
public UseSkill( int index )
{
string args = $"{index} 0";
_writer = new PacketWriter( 5 + args.Length );
_writer.Write( (byte) 0x12 );
_writer.Write( (short) ( 5 + args.Length ) );
_writer.Write( (byte) 0x24 );
_writer.WriteAsciiFixed( args, args.Length );
_writer.Write( (byte) 0 );
}
public string Parse( byte[] packet, int length, PacketDirection direction )
{
if ( packet[0] != 0x12 || packet[3] != 0x24 || direction != PacketDirection.Outgoing )
{
return null;
}
int len = packet.Length - 4;
byte[] skillPart = new byte[len];
Buffer.BlockCopy( packet, 4, skillPart, 0, len );
string skill = ASCII.GetString( skillPart );
if ( !int.TryParse( skill.Substring( 0, skill.IndexOf( ' ' ) ), out int id ) )
{
return null;
}
string skillName = Skills.GetSkillName( id );
return string.IsNullOrEmpty( skillName ) ? null : $"UseSkill(\"{skillName}\")\r\n";
}
}
}
@@ -0,0 +1,34 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class UseTargetedItem : BasePacket
{
public UseTargetedItem( int serial, int targetSerial )
{
_writer = new PacketWriter( 13 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 13 );
_writer.Write( (short) 0x2C );
_writer.Write( serial );
_writer.Write( targetSerial );
}
}
}
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Linq;
using ClassicAssist.Data.Vendors;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class VendorBuy : BasePacket
{
public VendorBuy( IReadOnlyCollection<ShopListEntry> entries )
{
int len = 8 + entries.Count * 7;
_writer = new PacketWriter( len );
_writer.Write( (byte) 0x3B );
_writer.Write( (short) len );
_writer.Write( entries.FirstOrDefault()?.VendorSerial ?? 0 );
_writer.Write( (byte) 2 ); // item list
foreach ( ShopListEntry entry in entries )
{
_writer.Write( (byte) Layer.ShopBuy );
_writer.Write( entry.Item.Serial );
_writer.Write( (short) entry.Amount );
}
}
}
}
@@ -0,0 +1,17 @@
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public class WarMode : BasePacket
{
public WarMode( bool onOff )
{
_writer = new PacketWriter( 5 );
_writer.Write( (byte) 0x72 );
_writer.Write( onOff );
_writer.Write( (byte) 0x00 );
_writer.Write( (byte) 0x32 );
_writer.Write( (byte) 0x00 );
}
}
}
@@ -0,0 +1,46 @@
#region License
// Copyright (C) 2020 Reetus
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#endregion
using ClassicAssist.Shared;
using ClassicAssist.UO.Data;
namespace ClassicAssist.UO.Network.Packets
{
public enum BoatSpeed : byte
{
Stop,
OneTile,
Normal
}
public class WheelBoatMoving : BasePacket
{
public WheelBoatMoving( Direction direction, BoatSpeed speed )
{
_writer = new PacketWriter( 12 );
_writer.Write( (byte) 0xBF );
_writer.Write( (short) 12 );
_writer.Write( (short) 0x33 );
_writer.Write( Engine.Player.Serial );
_writer.Write( (byte) direction );
_writer.Write( (byte) direction );
_writer.Write( (byte) speed );
}
}
}