first commit
This commit is contained in:
@@ -0,0 +1,813 @@
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ClassicAssist.Data;
|
||||
using ClassicAssist.Data.Abilities;
|
||||
using ClassicAssist.Data.Commands;
|
||||
using ClassicAssist.Data.Hotkeys;
|
||||
using ClassicAssist.Data.Macros;
|
||||
using ClassicAssist.Data.Scavenger;
|
||||
using ClassicAssist.Data.Targeting;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.UO.Data;
|
||||
using ClassicAssist.UO.Network;
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
using ClassicAssist.UO.Network.Packets;
|
||||
using ClassicAssist.UO.Objects;
|
||||
using CUO_API;
|
||||
using Sentry;
|
||||
|
||||
[assembly: InternalsVisibleTo( "ClassicAssist.Tests" )]
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace ClassicAssist.Shared
|
||||
{
|
||||
public static partial class Engine
|
||||
{
|
||||
public delegate void dConnected();
|
||||
|
||||
public delegate void dDisconnected();
|
||||
|
||||
public delegate void dPlayerInitialized( PlayerMobile player );
|
||||
|
||||
public delegate void dSendRecvPacket( byte[] data, int length );
|
||||
|
||||
public delegate void dUpdateWindowTitle();
|
||||
|
||||
private const int MAX_DISTANCE = 32;
|
||||
|
||||
private static OnConnected _onConnected;
|
||||
private static OnDisconnected _onDisconnected;
|
||||
private static OnPacketSendRecv _onReceive;
|
||||
private static OnPacketSendRecv _onSend;
|
||||
private static OnGetUOFilePath _getUOFilePath;
|
||||
private static OnPacketSendRecv _sendToClient;
|
||||
private static OnPacketSendRecv _sendToServer;
|
||||
private static OnGetPacketLength _getPacketLength;
|
||||
private static OnUpdatePlayerPosition _onPlayerPositionChanged;
|
||||
private static OnClientClose _onClientClosing;
|
||||
private static OnFocusGained _onFocusGained;
|
||||
private static OnFocusLost _onFocusLost;
|
||||
private static readonly PacketFilter _incomingPacketFilter = new PacketFilter();
|
||||
private static readonly PacketFilter _outgoingPacketPreFilter = new PacketFilter();
|
||||
private static readonly PacketFilter _outgoingPacketPostFilter = new PacketFilter();
|
||||
private static OnHotkey _onHotkeyPressed;
|
||||
private static RequestMove _requestMove;
|
||||
|
||||
private static readonly int[] _sequenceList = new int[256];
|
||||
private static OnMouse _onMouse;
|
||||
|
||||
private static readonly DateTime[] _lastMouseAction = new DateTime[(int)MouseOptions.None];
|
||||
private static readonly object _clientSendLock = new object();
|
||||
private static DateTime _nextPacketRecvTime;
|
||||
|
||||
private static readonly TimeSpan PACKET_RECV_DELAY = TimeSpan.FromMilliseconds( 5 );
|
||||
private static readonly object _serverSendLock = new object();
|
||||
|
||||
private static readonly TimeSpan PACKET_SEND_DELAY = TimeSpan.FromMilliseconds( 5 );
|
||||
private static DateTime _nextPacketSendTime;
|
||||
private static unsafe PluginHeader* _plugin;
|
||||
public static int LastSpellID;
|
||||
|
||||
public static Assembly ClassicAssembly { get; set; }
|
||||
|
||||
public static string ClientPath { get; set; }
|
||||
public static Version ClientVersion { get; set; }
|
||||
public static bool Connected { get; set; }
|
||||
public static ShardEntry CurrentShard { get; set; }
|
||||
public static IDispatcher Dispatcher { get; set; }
|
||||
public static FeatureFlags Features { get; set; }
|
||||
public static GumpCollection Gumps { get; set; } = new GumpCollection();
|
||||
public static bool IsClientFocused { get; set; }
|
||||
public static ItemCollection Items { get; set; } = new ItemCollection( 0 );
|
||||
public static CircularBuffer<JournalEntry> Journal { get; set; } = new CircularBuffer<JournalEntry>( 1024 );
|
||||
|
||||
public static DateTime LastActionPacket { get; set; }
|
||||
public static int LastPromptID { get; set; }
|
||||
public static int LastPromptSerial { get; set; }
|
||||
public static TargetQueue<object> LastTargetQueue { get; set; } = new TargetQueue<object>();
|
||||
public static MenuCollection Menus { get; set; } = new MenuCollection();
|
||||
public static MobileCollection Mobiles { get; set; } = new MobileCollection( Items );
|
||||
public static PacketWaitEntries PacketWaitEntries { get; set; }
|
||||
public static PlayerMobile Player { get; set; }
|
||||
public static QuestPointerList QuestPointers { get; set; } = new QuestPointerList();
|
||||
public static RehueList RehueList { get; set; } = new RehueList();
|
||||
public static List<ShardEntry> Shards { get; set; }
|
||||
public static string StartupPath { get; set; }
|
||||
public static bool TargetExists { get; set; }
|
||||
public static TargetFlags TargetFlags { get; set; }
|
||||
public static int TargetSerial { get; set; }
|
||||
public static TargetType TargetType { get; set; }
|
||||
public static IUIInvoker UIInvoker { get; set; }
|
||||
public static bool WaitingForTarget { get; set; }
|
||||
internal static ConcurrentDictionary<uint, int> GumpList { get; set; } = new ConcurrentDictionary<uint, int>();
|
||||
public static IMessageBoxProvider MessageBoxProvider { get; private set; }
|
||||
|
||||
public static event dUpdateWindowTitle UpdateWindowTitleEvent;
|
||||
|
||||
public static event dSendRecvPacket InternalPacketSentEvent;
|
||||
public static event dSendRecvPacket InternalPacketReceivedEvent;
|
||||
|
||||
public static event dSendRecvPacket PacketReceivedEvent;
|
||||
public static event dSendRecvPacket PacketSentEvent;
|
||||
public static event dSendRecvPacket SentPacketFilteredEvent;
|
||||
public static event dSendRecvPacket ReceivedPacketFilteredEvent;
|
||||
public static event dConnected ConnectedEvent;
|
||||
public static event dDisconnected DisconnectedEvent;
|
||||
public static event dPlayerInitialized PlayerInitializedEvent;
|
||||
|
||||
public static unsafe void Install( PluginHeader* plugin, IMessageBoxProvider provider )
|
||||
{
|
||||
_plugin = plugin;
|
||||
MessageBoxProvider = provider;
|
||||
|
||||
Initialize();
|
||||
|
||||
InitializePlugin( plugin );
|
||||
}
|
||||
|
||||
internal static unsafe void InitializePlugin( PluginHeader* plugin )
|
||||
{
|
||||
Console.WriteLine($"[CA] InitializePlugin called, plugin ptr={(IntPtr)plugin}");
|
||||
try
|
||||
{
|
||||
_onConnected = OnConnected;
|
||||
_onDisconnected = OnDisconnected;
|
||||
_onReceive = OnPacketReceive;
|
||||
_onSend = OnPacketSend;
|
||||
_onPlayerPositionChanged = OnPlayerPositionChanged;
|
||||
_onClientClosing = OnClientClosing;
|
||||
_onHotkeyPressed = OnHotkeyPressed;
|
||||
_onMouse = OnMouse;
|
||||
_onFocusGained = OnFocusGained;
|
||||
_onFocusLost = OnFocusLost;
|
||||
Console.WriteLine($"[CA] Delegates assigned");
|
||||
WindowHandle = plugin->HWND;
|
||||
Console.WriteLine($"[CA] WindowHandle={WindowHandle}");
|
||||
|
||||
plugin->OnConnected = Marshal.GetFunctionPointerForDelegate( _onConnected );
|
||||
plugin->OnDisconnected = Marshal.GetFunctionPointerForDelegate( _onDisconnected );
|
||||
plugin->OnRecv = Marshal.GetFunctionPointerForDelegate( _onReceive );
|
||||
plugin->OnSend = Marshal.GetFunctionPointerForDelegate( _onSend );
|
||||
plugin->OnPlayerPositionChanged = Marshal.GetFunctionPointerForDelegate( _onPlayerPositionChanged );
|
||||
plugin->OnClientClosing = Marshal.GetFunctionPointerForDelegate( _onClientClosing );
|
||||
plugin->OnHotkeyPressed = Marshal.GetFunctionPointerForDelegate( _onHotkeyPressed );
|
||||
plugin->OnMouse = Marshal.GetFunctionPointerForDelegate( _onMouse );
|
||||
plugin->OnFocusGained = Marshal.GetFunctionPointerForDelegate( _onFocusGained );
|
||||
plugin->OnFocusLost = Marshal.GetFunctionPointerForDelegate( _onFocusLost );
|
||||
|
||||
_getPacketLength = Marshal.GetDelegateForFunctionPointer<OnGetPacketLength>( plugin->GetPacketLength );
|
||||
_getUOFilePath = Marshal.GetDelegateForFunctionPointer<OnGetUOFilePath>( plugin->GetUOFilePath );
|
||||
_sendToClient = Marshal.GetDelegateForFunctionPointer<OnPacketSendRecv>( plugin->Recv );
|
||||
_sendToServer = Marshal.GetDelegateForFunctionPointer<OnPacketSendRecv>( plugin->Send );
|
||||
_requestMove = Marshal.GetDelegateForFunctionPointer<RequestMove>( plugin->RequestMove );
|
||||
|
||||
ClientPath = _getUOFilePath();
|
||||
ClientVersion = new Version( (byte)(plugin->ClientVersion >> 24), (byte)(plugin->ClientVersion >> 16),
|
||||
(byte)(plugin->ClientVersion >> 8), (byte)plugin->ClientVersion );
|
||||
|
||||
if (!Path.IsPathRooted( ClientPath ))
|
||||
{
|
||||
ClientPath = Path.GetFullPath( ClientPath );
|
||||
}
|
||||
|
||||
Art.Initialize( ClientPath );
|
||||
Hues.Initialize( ClientPath );
|
||||
Cliloc.Initialize( ClientPath );
|
||||
Skills.Initialize( ClientPath );
|
||||
Speech.Initialize( ClientPath );
|
||||
TileData.Initialize( ClientPath );
|
||||
Statics.Initialize( ClientPath );
|
||||
MapInfo.Initialize( ClientPath );
|
||||
|
||||
ClassicAssembly = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.FirstOrDefault( a => a.FullName.StartsWith( "ClassicUO," ) );
|
||||
|
||||
InitializeExtensions();
|
||||
Console.WriteLine("[CA] InitializePlugin DONE");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[CA] InitializePlugin ERROR: {ex}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeExtensions()
|
||||
{
|
||||
IEnumerable<Type> types = Assembly.GetExecutingAssembly().GetTypes()
|
||||
.Where( t => typeof( IExtension ).IsAssignableFrom( t ) && t.IsClass );
|
||||
|
||||
foreach (Type type in types)
|
||||
{
|
||||
try
|
||||
{
|
||||
IExtension instance = (IExtension)Activator.CreateInstance( type );
|
||||
instance?.Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine( e.ToString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnMouse( int button, int wheel )
|
||||
{
|
||||
MouseOptions mouse = MouseOptions.None;
|
||||
|
||||
if (button > 0)
|
||||
{
|
||||
mouse = SDLKeys.MouseButtonToMouseOptions( button );
|
||||
}
|
||||
|
||||
if (wheel != 0)
|
||||
{
|
||||
mouse = wheel < 0 ? MouseOptions.MouseWheelDown : MouseOptions.MouseWheelUp;
|
||||
|
||||
if (Options.CurrentOptions.LimitMouseWheelTrigger)
|
||||
{
|
||||
TimeSpan diff = DateTime.Now - _lastMouseAction[(int)mouse];
|
||||
|
||||
if (diff < TimeSpan.FromMilliseconds( Options.CurrentOptions.LimitMouseWheelTriggerMS ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_lastMouseAction[(int)mouse] = DateTime.Now;
|
||||
}
|
||||
|
||||
HotkeyManager.GetInstance().OnMouseAction( mouse );
|
||||
}
|
||||
|
||||
private static bool OnHotkeyPressed( int key, int mod, bool pressed )
|
||||
{
|
||||
if ( !IsClientFocused )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Key keys = SDLKeys.SDLKeyToKeys( key );
|
||||
|
||||
bool pass = HotkeyManager.GetInstance().OnHotkeyPressed( keys );
|
||||
|
||||
return !pass;
|
||||
}
|
||||
|
||||
private static void OnClientClosing()
|
||||
{
|
||||
if ( Options.CurrentOptions != null )
|
||||
{
|
||||
Options.Save( Options.CurrentOptions );
|
||||
}
|
||||
|
||||
try { AssistantOptions.Save(); } catch { /* ignored */ }
|
||||
try { SentrySdk.Close(); } catch { /* ignored */ }
|
||||
}
|
||||
|
||||
private static void OnPlayerPositionChanged( int x, int y, int z )
|
||||
{
|
||||
if (Player != null)
|
||||
{
|
||||
Player.X = x;
|
||||
Player.Y = y;
|
||||
Player.Z = z;
|
||||
}
|
||||
|
||||
Items.RemoveByDistance( MAX_DISTANCE, x, y );
|
||||
Mobiles.RemoveByDistance( MAX_DISTANCE, x, y );
|
||||
ScavengerManager.GetInstance().CheckArea?.Invoke();
|
||||
}
|
||||
|
||||
public static Item GetOrCreateItem( int serial, int containerSerial = -1 )
|
||||
{
|
||||
Item item = Items.GetItem( serial );
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
item = new Item( serial, containerSerial );
|
||||
|
||||
if (IncomingPacketHandlers.PropertyCache.TryGetValue( serial, out Property[] properties ))
|
||||
{
|
||||
item.Properties = properties;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static Mobile GetOrCreateMobile( int serial )
|
||||
{
|
||||
if (Player?.Serial == serial)
|
||||
{
|
||||
return Player;
|
||||
}
|
||||
|
||||
if (Mobiles.GetMobile( serial, out Mobile mobile ))
|
||||
{
|
||||
return mobile;
|
||||
}
|
||||
|
||||
mobile = new Mobile( serial );
|
||||
|
||||
if (IncomingPacketHandlers.PropertyCache.TryGetValue( serial, out Property[] properties ))
|
||||
{
|
||||
mobile.Properties = properties;
|
||||
}
|
||||
|
||||
return mobile;
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
StartupPath = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
|
||||
|
||||
if (StartupPath == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
|
||||
|
||||
PacketWaitEntries = new PacketWaitEntries();
|
||||
|
||||
IncomingQueue = new ThreadQueue<Packet>( ProcessIncomingQueue );
|
||||
OutgoingQueue = new ThreadQueue<Packet>( ProcessOutgoingQueue );
|
||||
|
||||
IncomingPacketHandlers.Initialize();
|
||||
OutgoingPacketHandlers.Initialize();
|
||||
|
||||
IncomingPacketFilters.Initialize();
|
||||
OutgoingPacketFilters.Initialize();
|
||||
|
||||
CommandsManager.Initialize();
|
||||
|
||||
AssistantOptions.Load();
|
||||
}
|
||||
|
||||
private static void ProcessIncomingQueue( Packet packet )
|
||||
{
|
||||
try
|
||||
{
|
||||
PacketReceivedEvent?.Invoke( packet.GetPacket(), packet.GetLength() );
|
||||
|
||||
PacketHandler handler = IncomingPacketHandlers.GetHandler( packet.GetPacketID() );
|
||||
|
||||
int length = _getPacketLength( packet.GetPacketID() );
|
||||
|
||||
handler?.OnReceive?.Invoke( new PacketReader( packet.GetPacket(), packet.GetLength(), length > 0 ) );
|
||||
|
||||
PacketWaitEntries?.CheckWait( packet.GetPacket(), PacketDirection.Incoming );
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SentrySdk.WithScope( scope =>
|
||||
{
|
||||
scope.SetExtra( "Packet", packet.GetPacket() );
|
||||
scope.SetExtra( "Player", Player.ToString() );
|
||||
scope.SetExtra( "WorldItemCount", Items.Count() );
|
||||
scope.SetExtra( "WorldMobileCount", Mobiles.Count() );
|
||||
SentrySdk.CaptureException( e );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessOutgoingQueue( Packet packet )
|
||||
{
|
||||
try
|
||||
{
|
||||
PacketSentEvent?.Invoke( packet.GetPacket(), packet.GetLength() );
|
||||
|
||||
PacketHandler handler = OutgoingPacketHandlers.GetHandler( packet.GetPacketID() );
|
||||
|
||||
int length = _getPacketLength( packet.GetPacketID() );
|
||||
|
||||
handler?.OnReceive?.Invoke( new PacketReader( packet.GetPacket(), packet.GetLength(), length > 0 ) );
|
||||
|
||||
PacketWaitEntries?.CheckWait( packet.GetPacket(), PacketDirection.Outgoing );
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SentrySdk.WithScope( scope =>
|
||||
{
|
||||
scope.SetExtra( "Packet", packet.GetPacket() );
|
||||
scope.SetExtra( "Player", Player.ToString() );
|
||||
scope.SetExtra( "WorldItemCount", Items.Count() );
|
||||
scope.SetExtra( "WorldMobileCount", Mobiles.Count() );
|
||||
SentrySdk.CaptureException( e );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
private static Assembly OnAssemblyResolve( object sender, ResolveEventArgs args )
|
||||
{
|
||||
string assemblyname = new AssemblyName( args.Name ).Name;
|
||||
|
||||
string[] searchPaths = { StartupPath, RuntimeEnvironment.GetRuntimeDirectory() };
|
||||
|
||||
if (assemblyname.Contains( "Colletions" ))
|
||||
{
|
||||
assemblyname = "System.Collections";
|
||||
}
|
||||
|
||||
foreach (string searchPath in searchPaths)
|
||||
{
|
||||
string fullPath = Path.Combine( searchPath, assemblyname + ".dll" );
|
||||
|
||||
string culture = new AssemblyName( args.Name ).CultureName;
|
||||
|
||||
if (!File.Exists( fullPath ))
|
||||
{
|
||||
string culturePath = Path.Combine( searchPath, culture, assemblyname + ".dll" );
|
||||
|
||||
if (File.Exists( culturePath ))
|
||||
{
|
||||
fullPath = culturePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Assembly assembly = Assembly.LoadFrom( fullPath );
|
||||
|
||||
return assembly;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void SetPlayer( PlayerMobile mobile )
|
||||
{
|
||||
Player = mobile;
|
||||
|
||||
PlayerInitializedEvent?.Invoke( mobile );
|
||||
|
||||
mobile.MobileStatusUpdated += ( status, newStatus ) =>
|
||||
{
|
||||
if (!Options.CurrentOptions.UseDeathScreenWhilstHidden)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (newStatus.HasFlag( MobileStatus.Hidden ))
|
||||
{
|
||||
SendPacketToClient( new MobileUpdate( mobile.Serial, mobile.ID == 0x191 ? 0x193 : 0x192, mobile.Hue,
|
||||
newStatus, mobile.X, mobile.Y, mobile.Z, mobile.Direction ) );
|
||||
}
|
||||
};
|
||||
|
||||
//TODO
|
||||
//Task.Run( async () =>
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// GitHubClient client = new GitHubClient( new ProductHeaderValue( "ClassicAssist" ) );
|
||||
|
||||
// IReadOnlyList<Release> releases =
|
||||
// await client.Repository.Release.GetAll( "Reetus", "ClassicAssist" );
|
||||
|
||||
// Release latestRelease = releases.FirstOrDefault();
|
||||
|
||||
// if ( latestRelease == null )
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Version latestVersion = Version.Parse( latestRelease.TagName );
|
||||
|
||||
// if ( !Version.TryParse(
|
||||
// FileVersionInfo.GetVersionInfo( Path.Combine( StartupPath, "ClassicAssist.dll" ) )
|
||||
// .ProductVersion, out Version localVersion ) )
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if ( latestVersion > localVersion && AssistantOptions.UpdateGumpVersion < latestVersion )
|
||||
// {
|
||||
// IReadOnlyList<GitHubCommit> commits =
|
||||
// await client.Repository.Commit.GetAll( "Reetus", "ClassicAssist" );
|
||||
|
||||
// IEnumerable<GitHubCommit> latestCommits =
|
||||
// commits.OrderByDescending( c => c.Commit.Author.Date ).Take( 15 );
|
||||
|
||||
// StringBuilder commitMessage = new StringBuilder();
|
||||
|
||||
// foreach ( GitHubCommit gitHubCommit in latestCommits )
|
||||
// {
|
||||
// commitMessage.AppendLine( $"{gitHubCommit.Commit.Author.Date.Date.ToShortDateString()}:" );
|
||||
// commitMessage.AppendLine();
|
||||
// commitMessage.AppendLine( gitHubCommit.Commit.Message );
|
||||
// commitMessage.AppendLine();
|
||||
// }
|
||||
|
||||
// StringBuilder message = new StringBuilder();
|
||||
// message.AppendLine( Strings.ProductName );
|
||||
// message.AppendLine(
|
||||
// $"{Strings.New_version_available_} <A HREF=\"https://github.com/Reetus/ClassicAssist/releases/tag/{latestVersion}\">{latestVersion}</A>" );
|
||||
// message.AppendLine();
|
||||
// message.AppendLine( commitMessage.ToString() );
|
||||
// message.AppendLine(
|
||||
// $"<A HREF=\"https://github.com/Reetus/ClassicAssist/commits/master\">{Strings.See_More}</A>" );
|
||||
|
||||
// UpdateMessageGump gump =
|
||||
// new UpdateMessageGump( WindowHandle, message.ToString(), latestVersion );
|
||||
// gump.SendGump();
|
||||
// }
|
||||
// }
|
||||
// catch ( Exception )
|
||||
// {
|
||||
// // Squash all
|
||||
// }
|
||||
//} );
|
||||
|
||||
AbilitiesManager.GetInstance().Enabled = AbilityType.None;
|
||||
AbilitiesManager.GetInstance().ResendGump( AbilityType.None );
|
||||
|
||||
Task.Run( async () =>
|
||||
{
|
||||
await Task.Delay( 3000 );
|
||||
MacroManager.GetInstance().Autostart();
|
||||
} );
|
||||
}
|
||||
|
||||
public static void SendPacketToServer( byte[] packet, int length )
|
||||
{
|
||||
lock (_serverSendLock)
|
||||
{
|
||||
while (DateTime.Now < _nextPacketSendTime)
|
||||
{
|
||||
Thread.Sleep( 1 );
|
||||
}
|
||||
|
||||
InternalPacketSentEvent?.Invoke( packet, length );
|
||||
|
||||
PacketWaitEntries?.CheckWait( packet, PacketDirection.Outgoing, true );
|
||||
|
||||
(byte[] data, int dataLength) = Utility.CopyBuffer( packet, length );
|
||||
|
||||
_sendToServer?.Invoke( ref data, ref dataLength );
|
||||
|
||||
_nextPacketSendTime = DateTime.Now + PACKET_SEND_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendPacketToClient( byte[] packet, int length, bool delay = true )
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_clientSendLock)
|
||||
{
|
||||
if (delay)
|
||||
{
|
||||
while (DateTime.Now < _nextPacketRecvTime)
|
||||
{
|
||||
Thread.Sleep( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
InternalPacketReceivedEvent?.Invoke( packet, length );
|
||||
|
||||
_sendToClient?.Invoke( ref packet, ref length );
|
||||
|
||||
_nextPacketRecvTime = DateTime.Now + PACKET_RECV_DELAY;
|
||||
}
|
||||
}
|
||||
catch (ThreadInterruptedException)
|
||||
{
|
||||
// Macro was interupted whilst we were waiting...
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendPacketToClient( PacketWriter packet )
|
||||
{
|
||||
byte[] data = packet.ToArray();
|
||||
|
||||
SendPacketToClient( data, data.Length );
|
||||
}
|
||||
|
||||
public static void SendPacketToClient( BasePacket basePacket, bool delay = true )
|
||||
{
|
||||
if (basePacket.Direction != PacketDirection.Any && basePacket.Direction != PacketDirection.Incoming)
|
||||
{
|
||||
throw new InvalidOperationException( "Send packet wrong direction." );
|
||||
}
|
||||
|
||||
byte[] data = basePacket.ToArray();
|
||||
|
||||
SendPacketToClient( data, data.Length, delay );
|
||||
}
|
||||
|
||||
public static void SendPacketToServer( PacketWriter packet )
|
||||
{
|
||||
byte[] data = packet.ToArray();
|
||||
|
||||
SendPacketToServer( data, data.Length );
|
||||
}
|
||||
|
||||
public static void SendPacketToServer( BasePacket basePacket )
|
||||
{
|
||||
if (basePacket.Direction != PacketDirection.Any && basePacket.Direction != PacketDirection.Outgoing)
|
||||
{
|
||||
throw new InvalidOperationException( "Send packet wrong direction." );
|
||||
}
|
||||
|
||||
byte[] data = basePacket.ToArray();
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendPacketToServer( data, data.Length );
|
||||
}
|
||||
|
||||
public static bool Move( Direction direction, bool run )
|
||||
{
|
||||
return _requestMove?.Invoke( (int)direction, run ) ?? false;
|
||||
}
|
||||
|
||||
public static void UpdateWindowTitle()
|
||||
{
|
||||
UpdateWindowTitleEvent?.Invoke();
|
||||
}
|
||||
|
||||
public static void GetMapZ( int x, int y, out sbyte groundZ, out sbyte staticZ )
|
||||
{
|
||||
groundZ = staticZ = (sbyte)(Player?.Z ?? 0);
|
||||
|
||||
if (ClassicAssembly == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyInfo mapProperty = ClassicAssembly.GetType( "ClassicUO.Game.World" )?.GetProperty( "Map" );
|
||||
|
||||
if (mapProperty == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object mapInstance = mapProperty.GetMethod.Invoke( mapProperty, null );
|
||||
|
||||
MethodInfo getMapZMethod = mapInstance?.GetType().GetMethod( "GetMapZ" );
|
||||
|
||||
if (getMapZMethod == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object[] parameters = { x, y, null, null };
|
||||
|
||||
getMapZMethod.Invoke( mapInstance, parameters );
|
||||
|
||||
groundZ = (sbyte)parameters[2];
|
||||
staticZ = (sbyte)parameters[3];
|
||||
}
|
||||
|
||||
public static Stream GetResourceStream( string name )
|
||||
{
|
||||
return Assembly.GetAssembly( typeof( Engine ) )
|
||||
.GetManifestResourceStream( $"ClassicAssist.Shared.Resources.{name}" );
|
||||
}
|
||||
|
||||
#region ClassicUO Events
|
||||
|
||||
private static bool OnPacketSend( ref byte[] data, ref int length )
|
||||
{
|
||||
bool filter = false;
|
||||
|
||||
if (CommandsManager.IsSpeechPacket( data[0] ))
|
||||
{
|
||||
filter = CommandsManager.CheckCommand( data, length );
|
||||
}
|
||||
|
||||
if (_outgoingPacketPreFilter.MatchFilterAll( data, out PacketFilterInfo[] pfis ) > 0)
|
||||
{
|
||||
foreach (PacketFilterInfo pfi in pfis)
|
||||
{
|
||||
pfi.Action?.Invoke( data, pfi );
|
||||
}
|
||||
|
||||
SentPacketFilteredEvent?.Invoke( data, data.Length );
|
||||
|
||||
PacketWaitEntries.CheckWait( data, PacketDirection.Outgoing, true );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OutgoingPacketFilters.CheckPacket( ref data, ref length ))
|
||||
{
|
||||
SentPacketFilteredEvent?.Invoke( data, data.Length );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
OutgoingQueue.Enqueue( new Packet( data, length ) );
|
||||
|
||||
// ReSharper disable once InvertIf
|
||||
if (_outgoingPacketPostFilter.MatchFilterAll( data, out PacketFilterInfo[] pfisPost ) > 0)
|
||||
{
|
||||
foreach (PacketFilterInfo pfi in pfisPost)
|
||||
{
|
||||
pfi.Action?.Invoke( data, pfi );
|
||||
}
|
||||
|
||||
SentPacketFilteredEvent?.Invoke( data, data.Length );
|
||||
|
||||
PacketWaitEntries.CheckWait( data, PacketDirection.Outgoing, true );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return !filter;
|
||||
}
|
||||
|
||||
public static IntPtr WindowHandle { get; private set; }
|
||||
|
||||
public static ThreadQueue<Packet> IncomingQueue { get; set; }
|
||||
|
||||
public static ThreadQueue<Packet> OutgoingQueue { get; set; }
|
||||
|
||||
private static bool OnPacketReceive( ref byte[] data, ref int length )
|
||||
{
|
||||
if (_incomingPacketFilter.MatchFilterAll( data, out PacketFilterInfo[] pfis ) > 0)
|
||||
{
|
||||
foreach (PacketFilterInfo pfi in pfis)
|
||||
{
|
||||
pfi.Action?.Invoke( data, pfi );
|
||||
}
|
||||
|
||||
ReceivedPacketFilteredEvent?.Invoke( data, length );
|
||||
|
||||
PacketWaitEntries.CheckWait( data, PacketDirection.Incoming, true );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IncomingPacketFilters.CheckPacket( ref data, ref length ))
|
||||
{
|
||||
ReceivedPacketFilteredEvent?.Invoke( data, length );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IncomingQueue.Enqueue( new Packet( data, length ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Direction GetSequence( int sequence )
|
||||
{
|
||||
return (Direction)Thread.VolatileRead( ref _sequenceList[sequence] );
|
||||
}
|
||||
|
||||
public static void SetSequence( int sequence, Direction direction )
|
||||
{
|
||||
_sequenceList[sequence] = (int)direction;
|
||||
}
|
||||
|
||||
private static void OnConnected()
|
||||
{
|
||||
Connected = true;
|
||||
|
||||
ConnectedEvent?.Invoke();
|
||||
}
|
||||
|
||||
private static void OnDisconnected()
|
||||
{
|
||||
Connected = false;
|
||||
|
||||
Items.Clear();
|
||||
Mobiles.Clear();
|
||||
Player = null;
|
||||
|
||||
DisconnectedEvent?.Invoke();
|
||||
}
|
||||
|
||||
private static void OnFocusGained()
|
||||
{
|
||||
IsClientFocused = true;
|
||||
}
|
||||
|
||||
private static void OnFocusLost()
|
||||
{
|
||||
IsClientFocused = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user