//TODO: we could write mvalue's to own onion struct in cpp to better share it but we would need to execute at least getorcreate entity when it contains a entity type in main thread //TODO: or lock entities dictionary so entity can't get removed until thread got it from dictionary //TODO: lock dictionary for async maybe as well for use cases like this public override void OnClientEventEvent(IPlayer player, string name, ref MValueArray args, MValue[] mValues, object[] objects) { base.OnClientEventEvent(player, name, ref args, mValues, objects); if (AsyncEventHandlers.Count != 0 && AsyncEventHandlers.TryGetValue(name, out var eventHandlers)) { if (mValues == null) { mValues = args.ToArray(); } if (objects == null) { var length = mValues.Length; objects = new object[length]; for (var i = 0; i < length; i++) { objects[i] = mValues[i].ToObject(BaseBaseObjectPool); } } Task.Run(async() => { foreach (var eventHandler in eventHandlers) { var invokeValues = eventHandler.CalculateInvokeValues(objects, player); if (invokeValues != null) { try { var task = eventHandler.InvokeTaskOrNull(invokeValues); if (task != null) { await task; } } catch (Exception e) { AltAsync.Log($"Execution of {name} threw an error: {e}"); } } else { AltAsync.Log("Wrong function params for " + name); } } }); } if (clientEventAsyncDelegateHandlers.Count != 0 && clientEventAsyncDelegateHandlers.TryGetValue(name, out var eventDelegates)) { if (mValues == null) { mValues = args.ToArray(); } if (objects == null) { var length = mValues.Length; objects = new object[length]; for (var i = 0; i < length; i++) { objects[i] = mValues[i].ToObject(BaseBaseObjectPool); } } Task.Run(() => { foreach (var eventHandler in eventDelegates) { AsyncEventHandler <ClientEventAsyncDelegate> .ExecuteEventAsyncWithoutTask(eventHandler, @delegate => @delegate(player, objects)); } }); } if (PlayerClientEventAsyncEventHandler.HasEvents()) { if (mValues == null) { mValues = args.ToArray(); } if (objects == null) { var length = mValues.Length; objects = new object[length]; for (var i = 0; i < length; i++) { objects[i] = mValues[i].ToObject(BaseBaseObjectPool); } } Task.Run(() => { foreach (var eventHandler in PlayerClientEventAsyncEventHandler.GetEvents()) { AsyncEventHandler <PlayerClientEventAsyncDelegate> .ExecuteEventAsyncWithoutTask(eventHandler, @delegate => @delegate(player, name, objects)); } }); } }