Introduce CustomEventHandler for more flexible invocation
This commit is contained in:
@ -12,10 +12,6 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
static readonly ThreadLocal<char[]> _resultBuf = new(() => new char[4096]);
|
static readonly ThreadLocal<char[]> _resultBuf = new(() => new char[4096]);
|
||||||
|
|
||||||
static readonly ThreadLocal<BufferWriter> _bufWriter = new(() => new(4096));
|
|
||||||
|
|
||||||
static readonly ThreadLocal<BufferReader> _bufReader = new(() => new());
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy content of string to a sequential block of memory
|
/// Copy content of string to a sequential block of memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -91,8 +87,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
|
|
||||||
public static void SendCustomEvent(CustomEventFlags flags, CustomEventHash hash, params object[] args)
|
public static void SendCustomEvent(CustomEventFlags flags, CustomEventHash hash, params object[] args)
|
||||||
{
|
{
|
||||||
var writer = _bufWriter.Value;
|
var writer = GetWriter();
|
||||||
writer.Reset();
|
|
||||||
CustomEvents.WriteObjects(writer, args);
|
CustomEvents.WriteObjects(writer, args);
|
||||||
SendCustomEvent(flags, hash, writer.Address, writer.Position);
|
SendCustomEvent(flags, hash, writer.Address, writer.Position);
|
||||||
}
|
}
|
||||||
|
@ -237,11 +237,6 @@ namespace RageCoop.Client
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (e.KeyCode == Keys.I)
|
|
||||||
{
|
|
||||||
APIBridge.SendChatMessage("hello there");
|
|
||||||
}
|
|
||||||
#if CEF
|
#if CEF
|
||||||
if (CefRunning)
|
if (CefRunning)
|
||||||
{
|
{
|
||||||
|
@ -15,20 +15,6 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace RageCoop.Client.Scripting
|
namespace RageCoop.Client.Scripting
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
public class CustomEventReceivedArgs : EventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The event hash
|
|
||||||
/// </summary>
|
|
||||||
public int Hash { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion
|
|
||||||
/// </summary>
|
|
||||||
public object[] Args { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides vital functionality to interact with RAGECOOP
|
/// Provides vital functionality to interact with RAGECOOP
|
||||||
@ -37,8 +23,8 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
#region INTERNAL
|
#region INTERNAL
|
||||||
|
|
||||||
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers =
|
internal static Dictionary<int, List<CustomEventHandler>> CustomEventHandlers =
|
||||||
new Dictionary<int, List<Action<CustomEventReceivedArgs>>>();
|
new();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -166,12 +152,26 @@ namespace RageCoop.Client.Scripting
|
|||||||
|
|
||||||
internal static void InvokeCustomEventReceived(Packets.CustomEvent p)
|
internal static void InvokeCustomEventReceived(Packets.CustomEvent p)
|
||||||
{
|
{
|
||||||
var args = new CustomEventReceivedArgs { Hash = p.Hash, Args = p.Args };
|
|
||||||
|
|
||||||
// Log.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
// Log.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
||||||
|
|
||||||
if (CustomEventHandlers.TryGetValue(p.Hash, out var handlers))
|
if (CustomEventHandlers.TryGetValue(p.Hash, out var handlers))
|
||||||
handlers.ForEach(x => { x.Invoke(args); });
|
{
|
||||||
|
fixed (byte* pData = p.Payload)
|
||||||
|
{
|
||||||
|
foreach (var handler in handlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler.Invoke(p.Hash, pData, p.Payload.Length);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("InvokeCustomEvent", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -290,9 +290,12 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// </param>
|
/// </param>
|
||||||
public static void SendCustomEvent(CustomEventFlags flags, CustomEventHash eventHash, params object[] args)
|
public static void SendCustomEvent(CustomEventFlags flags, CustomEventHash eventHash, params object[] args)
|
||||||
{
|
{
|
||||||
|
var writer = GetWriter();
|
||||||
|
CustomEvents.WriteObjects(writer, args);
|
||||||
Networking.Peer.SendTo(new Packets.CustomEvent(flags)
|
Networking.Peer.SendTo(new Packets.CustomEvent(flags)
|
||||||
{
|
{
|
||||||
Args = args,
|
|
||||||
|
Payload = writer.ToByteArray(writer.Position),
|
||||||
Hash = eventHash
|
Hash = eventHash
|
||||||
}, Networking.ServerConnection, ConnectionChannel.Event, NetDeliveryMethod.ReliableOrdered);
|
}, Networking.ServerConnection, ConnectionChannel.Event, NetDeliveryMethod.ReliableOrdered);
|
||||||
}
|
}
|
||||||
@ -310,7 +313,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
lock (CustomEventHandlers)
|
lock (CustomEventHandlers)
|
||||||
{
|
{
|
||||||
if (!CustomEventHandlers.TryGetValue(hash, out var handlers))
|
if (!CustomEventHandlers.TryGetValue(hash, out var handlers))
|
||||||
CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
|
CustomEventHandlers.Add(hash, handlers = new());
|
||||||
handlers.Add(handler);
|
handlers.Add(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
@ -43,6 +44,11 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public unsafe sealed class BufferWriter : Buffer
|
public unsafe sealed class BufferWriter : Buffer
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a thread local instance of this writer
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ThreadLocal<BufferWriter> ThreadLocal = new(() => new(4096));
|
||||||
|
|
||||||
public BufferWriter(int size)
|
public BufferWriter(int size)
|
||||||
{
|
{
|
||||||
Resize(size);
|
Resize(size);
|
||||||
@ -184,6 +190,11 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public unsafe sealed class BufferReader : Buffer
|
public unsafe sealed class BufferReader : Buffer
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a thread local instance of this reader
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ThreadLocal<BufferReader> ThreadLocal = new(() => new());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize an empty instance, needs to call <see cref="Initialise(byte*, int)"/> before reading data
|
/// Initialize an empty instance, needs to call <see cref="Initialise(byte*, int)"/> before reading data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -19,21 +19,11 @@ namespace RageCoop.Core
|
|||||||
public override PacketType Type => PacketType.CustomEvent;
|
public override PacketType Type => PacketType.CustomEvent;
|
||||||
public int Hash { get; set; }
|
public int Hash { get; set; }
|
||||||
public byte[] Payload;
|
public byte[] Payload;
|
||||||
public object[] Args;
|
|
||||||
|
|
||||||
protected override void Serialize(NetOutgoingMessage m)
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
m.Write((byte)Flags);
|
m.Write((byte)Flags);
|
||||||
m.Write(Hash);
|
m.Write(Hash);
|
||||||
if (Args != null)
|
|
||||||
{
|
|
||||||
lock (SharedWriter)
|
|
||||||
{
|
|
||||||
SharedWriter.Reset();
|
|
||||||
CustomEvents.WriteObjects(SharedWriter, Args);
|
|
||||||
Payload = SharedWriter.ToByteArray(SharedWriter.Position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.Write(Payload);
|
m.Write(Payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,14 +32,6 @@ namespace RageCoop.Core
|
|||||||
Flags = (CustomEventFlags)m.ReadByte();
|
Flags = (CustomEventFlags)m.ReadByte();
|
||||||
Hash = m.ReadInt32();
|
Hash = m.ReadInt32();
|
||||||
Payload = m.ReadBytes(m.LengthBytes - m.PositionInBytes);
|
Payload = m.ReadBytes(m.LengthBytes - m.PositionInBytes);
|
||||||
fixed (byte* p = Payload)
|
|
||||||
{
|
|
||||||
lock (SharedReader)
|
|
||||||
{
|
|
||||||
SharedReader.Initialise(p, Payload.Length);
|
|
||||||
Args = CustomEvents.ReadObjects(SharedReader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,8 +152,6 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
internal abstract class Packet : IPacket
|
internal abstract class Packet : IPacket
|
||||||
{
|
{
|
||||||
public static BufferWriter SharedWriter = new(1024);
|
|
||||||
public static BufferReader SharedReader = new();
|
|
||||||
|
|
||||||
public abstract PacketType Type { get; }
|
public abstract PacketType Type { get; }
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<ImplicitUsings>true</ImplicitUsings>
|
||||||
<NoWarn>1701;1702;CS1591</NoWarn>
|
<NoWarn>1701;1702;CS1591</NoWarn>
|
||||||
<TargetFrameworks>net7.0</TargetFrameworks>
|
<TargetFrameworks>net7.0</TargetFrameworks>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
72
Core/Scripting/CustomEventHandler.cs
Normal file
72
Core/Scripting/CustomEventHandler.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace RageCoop.Core.Scripting
|
||||||
|
{
|
||||||
|
public unsafe delegate void CustomEventHandlerDelegate(int hash, byte* data, int cbData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public class CustomEventReceivedArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The event hash
|
||||||
|
/// </summary>
|
||||||
|
public int Hash { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion
|
||||||
|
/// </summary>
|
||||||
|
public object[] Args { get; set; }
|
||||||
|
|
||||||
|
internal object Tag { get; set; }
|
||||||
|
}
|
||||||
|
public unsafe class CustomEventHandler
|
||||||
|
{
|
||||||
|
[ThreadStatic]
|
||||||
|
static object _tag;
|
||||||
|
public CustomEventHandler(IntPtr func)
|
||||||
|
{
|
||||||
|
FunctionPtr = func;
|
||||||
|
if (Path.GetFileName(Environment.ProcessPath).ToLower() == "gtav.exe")
|
||||||
|
{
|
||||||
|
Module = SHVDN.Core.CurrentModule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomEventHandlerDelegate _managedHandler; // Used to keep GC reference
|
||||||
|
public IntPtr FunctionPtr { get; }
|
||||||
|
public IntPtr Module { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hash"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="cbData"></param>
|
||||||
|
/// <param name="tag">Only works when using <see cref="CustomEventReceivedArgs"/></param>
|
||||||
|
public void Invoke(int hash, byte* data, int cbData, object tag = null)
|
||||||
|
{
|
||||||
|
_tag = tag;
|
||||||
|
((delegate* unmanaged<int, byte*, int, void>)FunctionPtr)(hash, data, cbData);
|
||||||
|
_tag = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator CustomEventHandler(CustomEventHandlerDelegate handler)
|
||||||
|
=> new(Marshal.GetFunctionPointerForDelegate(handler)) { _managedHandler = handler };
|
||||||
|
|
||||||
|
public static implicit operator CustomEventHandler(Action<CustomEventReceivedArgs> handler)
|
||||||
|
{
|
||||||
|
return new CustomEventHandlerDelegate((hash, data, cbData) =>
|
||||||
|
{
|
||||||
|
var reader = GetReader(data, cbData);
|
||||||
|
var arg = new CustomEventReceivedArgs
|
||||||
|
{
|
||||||
|
Hash = hash,
|
||||||
|
Args = CustomEvents.ReadObjects(reader),
|
||||||
|
Tag = _tag
|
||||||
|
};
|
||||||
|
handler(arg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,5 +22,30 @@ namespace RageCoop.Core
|
|||||||
public static T JsonDeserialize<T>(string text) => (T)JsonDeserialize(text, typeof(T));
|
public static T JsonDeserialize<T>(string text) => (T)JsonDeserialize(text, typeof(T));
|
||||||
|
|
||||||
public static string JsonSerialize(object obj) => JsonConvert.SerializeObject(obj, JsonSettings);
|
public static string JsonSerialize(object obj) => JsonConvert.SerializeObject(obj, JsonSettings);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shortcut to <see cref="BufferReader.ThreadLocal"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static unsafe BufferReader GetReader(byte* data=null,int cbData=0)
|
||||||
|
{
|
||||||
|
var reader = BufferReader.ThreadLocal.Value;
|
||||||
|
reader.Initialise(data,cbData);
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shortcut to <see cref="BufferWriter.ThreadLocal"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static BufferWriter GetWriter(bool reset=true) {
|
||||||
|
var writer=BufferWriter.ThreadLocal.Value;
|
||||||
|
if (reset)
|
||||||
|
{
|
||||||
|
writer.Reset();
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,10 +198,13 @@ public class Client
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var outgoingMessage = Server.MainNetServer.CreateMessage();
|
var outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||||
|
|
||||||
|
var writer = GetWriter();
|
||||||
|
CustomEvents.WriteObjects(writer, args);;
|
||||||
new Packets.CustomEvent(flags)
|
new Packets.CustomEvent(flags)
|
||||||
{
|
{
|
||||||
Hash = hash,
|
Hash = hash,
|
||||||
Args = args
|
Payload = writer.ToByteArray(writer.Position)
|
||||||
}.Pack(outgoingMessage);
|
}.Pack(outgoingMessage);
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered,
|
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered,
|
||||||
(byte)ConnectionChannel.Event);
|
(byte)ConnectionChannel.Event);
|
||||||
|
@ -15,7 +15,7 @@ using System.Resources;
|
|||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
// Version information
|
// Version information
|
||||||
[assembly: AssemblyVersion("1.6.0.30")]
|
[assembly: AssemblyVersion("1.6.0.32")]
|
||||||
[assembly: AssemblyFileVersion("1.6.0.30")]
|
[assembly: AssemblyFileVersion("1.6.0.32")]
|
||||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<Configurations>Debug;Release;API</Configurations>
|
<Configurations>Debug;Release;API</Configurations>
|
||||||
<OutDir>..\bin\$(Configuration)\Server</OutDir>
|
<OutDir>..\bin\$(Configuration)\Server</OutDir>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'API'">
|
<PropertyGroup Condition="'$(Configuration)' == 'API'">
|
||||||
|
@ -19,7 +19,7 @@ public class ServerEvents
|
|||||||
|
|
||||||
#region INTERNAL
|
#region INTERNAL
|
||||||
|
|
||||||
internal Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new();
|
internal Dictionary<int, List<CustomEventHandler>> CustomEventHandlers = new();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -138,10 +138,25 @@ public class ServerEvents
|
|||||||
OnPlayerDisconnected?.Invoke(this, client);
|
OnPlayerDisconnected?.Invoke(this, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InvokeCustomEventReceived(Packets.CustomEvent p, Client sender)
|
internal unsafe void InvokeCustomEventReceived(Packets.CustomEvent p, Client sender)
|
||||||
{
|
{
|
||||||
var args = new CustomEventReceivedArgs { Hash = p.Hash, Args = p.Args, Client = sender };
|
if (CustomEventHandlers.TryGetValue(p.Hash, out var handlers))
|
||||||
if (CustomEventHandlers.TryGetValue(p.Hash, out var handlers)) handlers.ForEach(x => { x.Invoke(args); });
|
{
|
||||||
|
fixed (byte* pData = p.Payload)
|
||||||
|
{
|
||||||
|
foreach (var handler in handlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler.Invoke(p.Hash, pData, p.Payload.Length, sender);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Server.Logger?.Error("InvokeCustomEvent", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InvokePlayerUpdate(Client client)
|
internal void InvokePlayerUpdate(Client client)
|
||||||
@ -351,9 +366,11 @@ public class API
|
|||||||
public void SendCustomEvent(CustomEventFlags flags, List<Client> targets, CustomEventHash eventHash,
|
public void SendCustomEvent(CustomEventFlags flags, List<Client> targets, CustomEventHash eventHash,
|
||||||
params object[] args)
|
params object[] args)
|
||||||
{
|
{
|
||||||
|
var writer = GetWriter();
|
||||||
|
CustomEvents.WriteObjects(writer, args);
|
||||||
var p = new Packets.CustomEvent(flags)
|
var p = new Packets.CustomEvent(flags)
|
||||||
{
|
{
|
||||||
Args = args,
|
Payload = writer.ToByteArray(writer.Position),
|
||||||
Hash = eventHash
|
Hash = eventHash
|
||||||
};
|
};
|
||||||
if (targets == null)
|
if (targets == null)
|
||||||
@ -383,8 +400,11 @@ public class API
|
|||||||
lock (Events.CustomEventHandlers)
|
lock (Events.CustomEventHandlers)
|
||||||
{
|
{
|
||||||
if (!Events.CustomEventHandlers.TryGetValue(hash, out var handlers))
|
if (!Events.CustomEventHandlers.TryGetValue(hash, out var handlers))
|
||||||
Events.CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
|
Events.CustomEventHandlers.Add(hash, handlers = new());
|
||||||
handlers.Add(handler);
|
handlers.Add(new Action<Core.Scripting.CustomEventReceivedArgs>((e) =>
|
||||||
|
{
|
||||||
|
handler.Invoke(CustomEventReceivedArgs.From(e));
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,23 +25,26 @@ public class ChatEventArgs : EventArgs
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CustomEventReceivedArgs : EventArgs
|
public class CustomEventReceivedArgs : Core.Scripting.CustomEventReceivedArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="RageCoop.Server.Client" /> that triggered this event
|
/// The <see cref="RageCoop.Server.Client" /> that triggered this event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Client Client { get; set; }
|
public Client Client
|
||||||
|
{
|
||||||
|
get => Tag as Client;
|
||||||
|
set => Tag = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static CustomEventReceivedArgs From(Core.Scripting.CustomEventReceivedArgs e)
|
||||||
/// The event hash
|
{
|
||||||
/// </summary>
|
return new CustomEventReceivedArgs
|
||||||
public int Hash { get; set; }
|
{
|
||||||
|
Args = e.Args,
|
||||||
/// <summary>
|
Tag = e.Tag,
|
||||||
/// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion, Vector2
|
Hash = e.Hash,
|
||||||
/// <see cref="ServerObject.Handle" />
|
};
|
||||||
/// </summary>
|
}
|
||||||
public object[] Args { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Reference in New Issue
Block a user