2022-06-06 17:37:11 +08:00
#undef DEBUG
2022-07-20 17:50:01 +08:00
using GTA ;
2022-06-06 17:37:11 +08:00
using RageCoop.Core ;
2022-07-20 17:50:01 +08:00
using System ;
using System.Collections.Generic ;
2022-07-11 11:06:57 +08:00
using System.Windows.Forms ;
2022-06-06 17:37:11 +08:00
2022-06-11 18:41:10 +08:00
namespace RageCoop.Client.Scripting
2022-06-06 17:37:11 +08:00
{
2022-07-01 13:54:18 +08:00
/// <summary>
///
/// </summary>
2022-06-22 14:18:20 +08:00
public class CustomEventReceivedArgs : EventArgs
{
2022-07-01 13:54:18 +08:00
/// <summary>
/// The event hash
/// </summary>
2022-06-22 14:18:20 +08:00
public int Hash { get ; set ; }
2022-07-01 13:54:18 +08:00
/// <summary>
2022-07-02 18:30:16 +08:00
/// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion
2022-07-01 13:54:18 +08:00
/// </summary>
2022-07-05 10:52:22 +08:00
public object [ ] Args { get ; set ; }
2022-06-22 14:18:20 +08:00
}
2022-06-06 17:37:11 +08:00
/// <summary>
2022-06-12 15:39:32 +08:00
/// Provides vital functionality to interact with RAGECOOP
2022-06-06 17:37:11 +08:00
/// </summary>
2022-08-04 17:14:07 +08:00
public class API
2022-06-06 17:37:11 +08:00
{
2022-06-22 14:18:20 +08:00
#region INTERNAL
internal static Dictionary < int , List < Action < CustomEventReceivedArgs > > > CustomEventHandlers = new Dictionary < int , List < Action < CustomEventReceivedArgs > > > ( ) ;
#endregion
2022-06-12 15:39:32 +08:00
/// <summary>
/// Client configuration, this will conflict with server-side config.
/// </summary>
2022-06-06 17:37:11 +08:00
public static class Config
{
2022-06-12 15:39:32 +08:00
/// <summary>
/// Get or set local player's username, set won't be effective if already connected to a server.
/// </summary>
public static string Username
{
get { return Main . Settings . Username ; }
set
{
2022-07-11 11:30:00 +08:00
if ( Networking . IsOnServer | | string . IsNullOrEmpty ( value ) )
2022-06-12 15:39:32 +08:00
{
return ;
}
Main . Settings . Username = value ;
}
}
2022-06-06 17:37:11 +08:00
/// <summary>
2022-06-11 18:41:10 +08:00
/// Enable automatic respawn for this player.
2022-06-06 17:37:11 +08:00
/// </summary>
public static bool EnableAutoRespawn { get ; set ; } = true ;
2022-07-03 10:46:24 +08:00
/// <summary>
/// Get or set player's blip color
/// </summary>
public static BlipColor BlipColor { get ; set ; } = BlipColor . White ;
2022-07-04 22:50:47 +08:00
/// <summary>
/// Get or set player's blip sprite
/// </summary>
public static BlipSprite BlipSprite { get ; set ; } = BlipSprite . Standard ;
2022-07-20 17:50:01 +08:00
2022-07-04 22:50:47 +08:00
/// <summary>
/// Get or set scale of player's blip
/// </summary>
public static float BlipScale { get ; set ; } = 1 ;
2022-06-11 18:41:10 +08:00
}
2022-06-12 15:39:32 +08:00
/// <summary>
/// Base events for RageCoop
/// </summary>
2022-06-11 18:41:10 +08:00
public static class Events
{
2022-06-21 18:13:30 +08:00
#region DELEGATES
2022-07-01 13:54:18 +08:00
/// <summary>
///
/// </summary>
2022-06-11 18:41:10 +08:00
public delegate void EmptyEvent ( ) ;
2022-07-01 13:54:18 +08:00
/// <summary>
///
/// </summary>
/// <param name="hash"></param>
/// <param name="args"></param>
2022-06-21 18:13:30 +08:00
public delegate void CustomEvent ( int hash , List < object > args ) ;
#endregion
2022-06-06 17:37:11 +08:00
/// <summary>
2022-06-11 18:41:10 +08:00
/// The local player is dead
2022-06-06 17:37:11 +08:00
/// </summary>
2022-06-11 18:41:10 +08:00
public static event EmptyEvent OnPlayerDied ;
2022-06-06 17:37:11 +08:00
/// <summary>
2022-06-11 18:41:10 +08:00
/// A local vehicle is spawned
2022-06-06 17:37:11 +08:00
/// </summary>
2022-06-11 18:41:10 +08:00
public static event EventHandler < SyncedVehicle > OnVehicleSpawned ;
2022-06-06 17:37:11 +08:00
2022-06-11 18:41:10 +08:00
/// <summary>
/// A local vehicle is deleted
/// </summary>
public static event EventHandler < SyncedVehicle > OnVehicleDeleted ;
2022-06-06 17:37:11 +08:00
2022-06-12 15:39:32 +08:00
/// <summary>
/// A local ped is spawned
/// </summary>
2022-06-11 18:41:10 +08:00
public static event EventHandler < SyncedPed > OnPedSpawned ;
2022-06-12 15:39:32 +08:00
/// <summary>
/// A local ped is deleted
/// </summary>
2022-06-11 18:41:10 +08:00
public static event EventHandler < SyncedPed > OnPedDeleted ;
2022-06-12 15:39:32 +08:00
/// <summary>
/// This is equivalent of <see cref="GTA.Script.Tick"/>.
/// </summary>
public static event EmptyEvent OnTick ;
2022-06-21 18:13:30 +08:00
2022-07-11 11:06:57 +08:00
/// <summary>
/// This is equivalent of <see cref="Script.KeyDown"/>
/// </summary>
public static KeyEventHandler OnKeyDown ;
/// <summary>
/// This is equivalent of <see cref="Script.KeyUp"/>
/// </summary>
public static KeyEventHandler OnKeyUp ;
2022-06-21 18:13:30 +08:00
2022-06-11 18:41:10 +08:00
#region INVOKE
2022-06-21 18:13:30 +08:00
internal static void InvokeVehicleSpawned ( SyncedVehicle v ) { OnVehicleSpawned ? . Invoke ( null , v ) ; }
2022-06-12 15:39:32 +08:00
internal static void InvokeVehicleDeleted ( SyncedVehicle v ) { OnVehicleDeleted ? . Invoke ( null , v ) ; }
internal static void InvokePedSpawned ( SyncedPed p ) { OnPedSpawned ? . Invoke ( null , p ) ; }
internal static void InvokePedDeleted ( SyncedPed p ) { OnPedDeleted ? . Invoke ( null , p ) ; }
internal static void InvokePlayerDied ( ) { OnPlayerDied ? . Invoke ( ) ; }
internal static void InvokeTick ( ) { OnTick ? . Invoke ( ) ; }
2022-06-21 18:13:30 +08:00
2022-07-20 17:50:01 +08:00
internal static void InvokeKeyDown ( object s , KeyEventArgs e ) { OnKeyDown ? . Invoke ( s , e ) ; }
2022-07-11 11:06:57 +08:00
internal static void InvokeKeyUp ( object s , KeyEventArgs e ) { OnKeyUp ? . Invoke ( s , e ) ; }
2022-06-22 14:18:20 +08:00
internal static void InvokeCustomEventReceived ( Packets . CustomEvent p )
2022-06-21 18:13:30 +08:00
{
2022-07-20 17:50:01 +08:00
var args = new CustomEventReceivedArgs ( ) { Hash = p . Hash , Args = p . Args } ;
2022-06-23 09:46:38 +08:00
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
2022-07-20 17:50:01 +08:00
2022-06-22 14:18:20 +08:00
List < Action < CustomEventReceivedArgs > > handlers ;
if ( CustomEventHandlers . TryGetValue ( p . Hash , out handlers ) )
{
handlers . ForEach ( ( x ) = > { x . Invoke ( args ) ; } ) ;
}
2022-06-21 18:13:30 +08:00
}
2022-06-11 18:41:10 +08:00
#endregion
}
2022-06-21 18:13:30 +08:00
2022-07-11 11:30:00 +08:00
#region PROPERTIES
2022-06-06 17:37:11 +08:00
2022-06-12 15:39:32 +08:00
/// <summary>
2022-07-11 11:30:00 +08:00
/// Get the local player's ID
2022-06-12 15:39:32 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
/// <returns>PlayerID</returns>
public static int LocalPlayerID
2022-06-11 18:41:10 +08:00
{
2022-07-11 11:30:00 +08:00
get { return Main . LocalPlayerID ; }
2022-06-11 18:41:10 +08:00
}
2022-07-11 11:30:00 +08:00
2022-07-31 20:47:04 +08:00
/// <summary>
/// Check if player is connected to a server
/// </summary>
public static bool IsOnServer { get { return Networking . IsOnServer ; } }
/// <summary>
/// Get an <see cref="System.Net.IPEndPoint"/> that the player is currently connected to, or null if not connected to the server
/// </summary>
2022-08-06 12:32:04 +08:00
public static System . Net . IPEndPoint ServerEndPoint { get { return Networking . IsOnServer ? Networking . ServerConnection ? . RemoteEndPoint : null ; } }
2022-07-31 20:47:04 +08:00
2022-06-11 18:41:10 +08:00
/// <summary>
2022-07-11 11:30:00 +08:00
/// Check if a RAGECOOP menu is visible
2022-06-11 18:41:10 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
public static bool IsMenuVisible
2022-06-11 18:41:10 +08:00
{
2022-07-11 11:30:00 +08:00
get { return Menus . CoopMenu . MenuPool . AreAnyVisible ; }
2022-06-11 18:41:10 +08:00
}
2022-07-11 11:30:00 +08:00
2022-06-06 17:37:11 +08:00
/// <summary>
2022-07-11 11:30:00 +08:00
/// Check if the RAGECOOP chat is visible
2022-06-06 17:37:11 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
public static bool IsChatFocused
2022-06-06 17:37:11 +08:00
{
2022-07-11 11:30:00 +08:00
get { return Main . MainChat . Focused ; }
2022-06-06 17:37:11 +08:00
}
/// <summary>
2022-07-11 11:30:00 +08:00
/// Check if the RAGECOOP list of players is visible
2022-06-06 17:37:11 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
public static bool IsPlayerListVisible
2022-06-06 17:37:11 +08:00
{
2022-07-11 11:30:00 +08:00
get { return Util . GetTickCount64 ( ) - PlayerList . Pressed < 5000 ; }
2022-06-06 17:37:11 +08:00
}
/// <summary>
2022-07-11 11:30:00 +08:00
/// Get the version of RAGECOOP
2022-06-06 17:37:11 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
public static string CurrentVersion
2022-06-06 17:37:11 +08:00
{
2022-07-11 11:30:00 +08:00
get { return Main . CurrentVersion ; }
2022-06-06 17:37:11 +08:00
}
2022-07-11 11:30:00 +08:00
2022-06-06 17:37:11 +08:00
/// <summary>
2022-07-11 11:30:00 +08:00
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
2022-06-06 17:37:11 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
/// <returns></returns>
public static Logger Logger
2022-06-06 17:37:11 +08:00
{
2022-07-11 11:30:00 +08:00
get
{
return Main . Logger ;
}
2022-06-06 17:37:11 +08:00
}
2022-07-11 11:30:00 +08:00
#endregion
2022-06-06 17:37:11 +08:00
2022-07-11 11:30:00 +08:00
#region FUNCTIONS
2022-06-06 17:37:11 +08:00
/// <summary>
2022-07-31 20:47:04 +08:00
/// Connect to a server
/// </summary>
/// <param name="address">Address of the server, e.g. 127.0.0.1:4499</param>
/// <exception cref="InvalidOperationException">When a connection is active or being established</exception>
public static void Connect ( string address )
{
if ( Networking . IsOnServer | | Networking . IsConnecting )
{
throw new InvalidOperationException ( "Cannot connect to server when another connection is active" ) ;
}
Networking . ToggleConnection ( address ) ;
}
/// <summary>
/// Disconnect from current server or cancel the connection attempt.
/// </summary>
public static void Disconnect ( )
{
if ( Networking . IsOnServer | | Networking . IsConnecting )
{
Networking . ToggleConnection ( null ) ;
}
}
/// <summary>
2022-07-11 11:30:00 +08:00
/// Send a local chat message to this player
2022-06-06 17:37:11 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
/// <param name="from">Name of the sender</param>
/// <param name="message">The player's message</param>
public static void LocalChatMessage ( string from , string message )
2022-06-06 17:37:11 +08:00
{
2022-07-11 11:30:00 +08:00
Main . MainChat . AddMessage ( from , message ) ;
2022-06-06 17:37:11 +08:00
}
/// <summary>
2022-07-11 11:30:00 +08:00
/// Queue an action to be executed on next tick.
2022-06-06 17:37:11 +08:00
/// </summary>
2022-07-11 11:30:00 +08:00
/// <param name="a"></param>
public static void QueueAction ( Action a )
2022-06-06 17:37:11 +08:00
{
2022-07-11 11:30:00 +08:00
Main . QueueAction ( a ) ;
2022-06-06 17:37:11 +08:00
}
2022-07-14 18:50:15 +08:00
/// <summary>
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// </summary>
2022-07-31 20:47:04 +08:00
/// <param name="a"> An <see cref="Func{T, TResult}"/> to be executed with a return value indicating whether it can be removed after execution.</param>
2022-07-14 18:50:15 +08:00
public static void QueueAction ( Func < bool > a )
{
Main . QueueAction ( a ) ;
}
2022-07-11 11:30:00 +08:00
2022-06-21 18:13:30 +08:00
/// <summary>
2022-07-01 19:02:38 +08:00
/// Send an event and data to the server.
2022-06-21 18:13:30 +08:00
/// </summary>
/// <param name="eventHash">An unique identifier of the event</param>
2022-07-02 18:30:16 +08:00
/// <param name="args">The objects conataing your data, see <see cref="CustomEventReceivedArgs"/> for a list of supported types</param>
2022-07-05 10:52:22 +08:00
public static void SendCustomEvent ( int eventHash , params object [ ] args )
2022-06-21 18:13:30 +08:00
{
var p = new Packets . CustomEvent ( )
{
Args = args ,
Hash = eventHash
} ;
2022-08-08 17:03:41 +08:00
Networking . SendTo ( p , Networking . ServerConnection , ConnectionChannel . Event , Lidgren . Network . NetDeliveryMethod . ReliableOrdered ) ;
2022-06-21 18:13:30 +08:00
}
2022-06-22 14:18:20 +08:00
/// <summary>
/// Register an handler to the specifed event hash, one event can have multiple handlers. This will be invoked from backgound thread, use <see cref="QueueAction(Action)"/> in the handler to dispatch code to script thread.
/// </summary>
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="Core.Scripting.CustomEvents.Hash(string)"/></param>
/// <param name="handler">An handler to be invoked when the event is received from the server. </param>
public static void RegisterCustomEventHandler ( int hash , Action < CustomEventReceivedArgs > handler )
{
lock ( CustomEventHandlers )
{
2022-07-11 11:30:00 +08:00
if ( ! CustomEventHandlers . TryGetValue ( hash , out List < Action < CustomEventReceivedArgs > > handlers ) )
2022-06-22 14:18:20 +08:00
{
CustomEventHandlers . Add ( hash , handlers = new List < Action < CustomEventReceivedArgs > > ( ) ) ;
}
handlers . Add ( handler ) ;
}
}
2022-07-20 17:50:01 +08:00
2022-07-19 17:15:53 +08:00
/// <summary>
///
/// </summary>
/// <returns></returns>
2022-07-20 17:50:01 +08:00
public static void RequestSharedFile ( string name , Action < string > callback )
2022-07-19 17:15:53 +08:00
{
EventHandler < string > handler = ( s , e ) = >
{
if ( e . EndsWith ( name ) )
{
callback ( e ) ;
}
} ;
DownloadManager . DownloadCompleted + = handler ;
Networking . GetResponse < Packets . FileTransferResponse > ( new Packets . FileTransferRequest ( )
{
Name = name ,
2022-07-20 17:50:01 +08:00
} ,
2022-07-19 17:15:53 +08:00
( p ) = >
{
2022-07-20 17:50:01 +08:00
if ( p . Response ! = FileResponse . Loaded )
2022-07-19 17:15:53 +08:00
{
DownloadManager . DownloadCompleted - = handler ;
throw new ArgumentException ( "Requested file was not found on the server: " + name ) ;
}
} ) ;
}
2022-06-21 18:13:30 +08:00
#endregion
2022-06-06 17:37:11 +08:00
}
}