diff --git a/Client/JavascriptHook.cs b/Client/JavascriptHook.cs index a201096..ccc7689 100644 --- a/Client/JavascriptHook.cs +++ b/Client/JavascriptHook.cs @@ -189,7 +189,7 @@ namespace CoopClient OnChatMessage?.Invoke(from, message); } - public void InvokeServerEvent(string eventName, params object[] args) + public void InvokeServerEvent(string eventName, object[] args) { _serverEvents.FirstOrDefault(x => x.Key == eventName).Value?.Invoke(args); } @@ -464,9 +464,9 @@ namespace CoopClient AddServerEvent(eventName, arg => action(arg)); } - public void TriggerServerEvent(string eventName, params object[] args) + public void SendTriggerEvent(string eventName, params object[] args) { - // TODO + Main.MainNetworking.SendTriggerEvent(eventName, args); } } } diff --git a/Client/Networking.cs b/Client/Networking.cs index 6cfd1cd..b795da4 100644 --- a/Client/Networking.cs +++ b/Client/Networking.cs @@ -1242,6 +1242,20 @@ namespace CoopClient } #endif } + + public void SendTriggerEvent(string eventName, params object[] args) + { + NetOutgoingMessage outgoingMessage = Client.CreateMessage(); + + new Packets.ServerClientEvent() + { + EventName = eventName, + Args = new List(args) + }.PacketToNetOutGoingMessage(outgoingMessage); + + Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableUnordered, (byte)ConnectionChannel.Event); + Client.FlushSendQueue(); + } #endregion } } diff --git a/Server/Client.cs b/Server/Client.cs index aeb12a9..8a545ca 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -227,7 +227,7 @@ namespace CoopServer } } - public void TriggerServerEvent(string eventName, params object[] args) + public void SendTriggerEvent(string eventName, params object[] args) { try { diff --git a/Server/Packets/Packets.cs b/Server/Packets/Packets.cs index 3ecc45d..85d5b0a 100644 --- a/Server/Packets/Packets.cs +++ b/Server/Packets/Packets.cs @@ -350,6 +350,7 @@ namespace CoopServer EventName = reader.ReadString(eventNameBytes); // Read args + Args = new List(); int argsCount = reader.ReadInt(); for (int i = 0; i < argsCount; i++) { diff --git a/Server/Server.cs b/Server/Server.cs index 192496d..33db1bd 100644 --- a/Server/Server.cs +++ b/Server/Server.cs @@ -33,6 +33,7 @@ namespace CoopServer public static Resource RunningResource = null; public static Dictionary> Commands; + public static readonly Dictionary> TriggerEvents = new(); public static readonly List Clients = new(); @@ -539,6 +540,47 @@ namespace CoopServer } } break; + case (byte)PacketTypes.ServerClientEvent: + { + try + { + int len = message.ReadInt32(); + byte[] data = message.ReadBytes(len); + + Packets.ServerClientEvent packet = new Packets.ServerClientEvent(); + packet.NetIncomingMessageToPacket(data); + + long senderNetHandle = message.SenderConnection.RemoteUniqueIdentifier; + Client client = null; + lock (Clients) + { + client = Util.GetClientByNetHandle(senderNetHandle); + } + + if (client != null) + { + if (TriggerEvents.Any(x => x.Key.EventName == packet.EventName)) + { + EventContext ctx = new() + { + Client = client, + Args = packet.Args.ToArray() + }; + + TriggerEvents.FirstOrDefault(x => x.Key.EventName == packet.EventName).Value?.Invoke(ctx); + } + else + { + Logging.Warning($"Player \"{client.Player.Username}\" attempted to trigger an unknown event! [{packet.EventName}]"); + } + } + } + catch (Exception e) + { + DisconnectAndLog(message.SenderConnection, type, e); + } + } + break; default: Logging.Error("Unhandled Data / Packet type"); break; @@ -1078,5 +1120,28 @@ namespace CoopServer RegisterCommand(attribute.Name, attribute.Usage, attribute.ArgsLength, (Action)Delegate.CreateDelegate(typeof(Action), method)); } } + + public static void RegisterEvent(string eventName, Action callback) + { + TriggerEvent ev = new(eventName); + + if (TriggerEvents.ContainsKey(ev)) + { + throw new Exception("TriggerEvent \"" + ev.EventName + "\" was already been registered!"); + } + + TriggerEvents.Add(ev, callback); + } + public static void RegisterEvents() + { + IEnumerable events = typeof(T).GetMethods().Where(method => method.GetCustomAttributes(typeof(TriggerEvent), false).Any()); + + foreach (MethodInfo method in events) + { + TriggerEvent attribute = method.GetCustomAttribute(true); + + RegisterEvent(attribute.EventName, (Action)Delegate.CreateDelegate(typeof(Action), method)); + } + } } } diff --git a/Server/ServerScript.cs b/Server/ServerScript.cs index b062a3e..cd34048 100644 --- a/Server/ServerScript.cs +++ b/Server/ServerScript.cs @@ -480,10 +480,43 @@ namespace CoopServer { Server.RegisterCommands(); } + + /// + /// Register a class of events + /// + /// The name of your class with functions + public static void RegisterEvents() + { + Server.RegisterEvents(); + } #endregion } - [AttributeUsage(AttributeTargets.Method)] + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public class TriggerEvent : Attribute + { + public string EventName { get; set; } + + public TriggerEvent(string eventName) + { + EventName = eventName; + } + } + + public class EventContext + { + /// + /// Gets the client which executed the command + /// + public Client Client { get; internal set; } + + /// + /// Arguments (all standard but no string!) + /// + public object[] Args { get; internal set; } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false)] public class Command : Attribute { ///