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