Make event handler async, while preserving the order of incoming events.

This commit is contained in:
Deukhoofd 2020-08-07 20:28:38 +02:00
parent 90d5c2a16c
commit 1acd32b986
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
4 changed files with 23 additions and 5 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PkmnLibSharp.Battling.ChoiceTurn;
using PkmnLibSharp.Battling.Events;
@ -173,8 +174,10 @@ namespace PkmnLibSharp.Battling
return Creaturelib.Generated.Battle.HasVolatileScript(Ptr, key.ToPtr()) == 1;
}
private List<BattleEventListener> _listeners = new List<BattleEventListener>();
public void RegisterEventListener(BattleEventListener listener)
{
_listeners.Add(listener);
Creaturelib.Generated.Battle.RegisterEventListener(Ptr, listener.FunctionPtr).Assert();
}

View File

@ -1,29 +1,42 @@
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace PkmnLibSharp.Battling.Events
{
public class BattleEventListener
{
public delegate void BattleEventDelegate(EventData evt);
public delegate Task BattleEventDelegate(EventData evt);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void BattleEventPtrDelegate(IntPtr ptr);
private readonly BattleEventDelegate _del;
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly BattleEventPtrDelegate _innerDel;
internal readonly IntPtr FunctionPtr;
private Task _currentTask;
public BattleEventListener(BattleEventDelegate del)
{
_del = del;
_innerDel = OnEventPtr;
FunctionPtr = Marshal.GetFunctionPointerForDelegate(_innerDel);
FunctionPtr = Marshal.GetFunctionPointerForDelegate<BattleEventPtrDelegate>(_innerDel);
}
private void OnEventPtr(IntPtr ptr)
{
// If we're still registering another event, wait until that's done. This ensures events always arrive in
// the correct order.
_currentTask?.Wait();
// We do however want to run the event handler async, so that the battle code can keep running up till its
// next event.
_currentTask = Task.Run(() => InternalRunner(ptr));
}
private async Task InternalRunner(IntPtr ptr)
{
var wrapped = WrapEventPtr(ptr);
_del.Invoke(wrapped);
await _del.Invoke(wrapped);
}
private static EventData WrapEventPtr(IntPtr ptr)

BIN
PkmnLibSharp/Native/libCreatureLib.so (Stored with Git LFS)

Binary file not shown.

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using PkmnLibSharp.Battling;
using PkmnLibSharp.Battling.ChoiceTurn;
@ -94,6 +95,7 @@ namespace PkmnLibSharpTests.Battling.BattleTests
battle.RegisterEventListener(new BattleEventListener(evt =>
{
evts.Add(evt);
return Task.CompletedTask;
}));
battle.SwitchPokemon(0, 0, p1.GetAtIndex(0));