2020-07-26 12:47:56 +00:00
|
|
|
using System;
|
|
|
|
using System.Runtime.InteropServices;
|
2020-08-07 18:28:38 +00:00
|
|
|
using System.Threading.Tasks;
|
2020-07-26 12:47:56 +00:00
|
|
|
|
|
|
|
namespace PkmnLibSharp.Battling.Events
|
|
|
|
{
|
|
|
|
public class BattleEventListener
|
|
|
|
{
|
2020-08-07 18:28:38 +00:00
|
|
|
public delegate Task BattleEventDelegate(EventData evt);
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2020-07-26 12:47:56 +00:00
|
|
|
private delegate void BattleEventPtrDelegate(IntPtr ptr);
|
|
|
|
|
|
|
|
private readonly BattleEventDelegate _del;
|
|
|
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
|
|
|
private readonly BattleEventPtrDelegate _innerDel;
|
|
|
|
internal readonly IntPtr FunctionPtr;
|
2020-08-07 18:28:38 +00:00
|
|
|
private Task _currentTask;
|
2020-07-26 12:47:56 +00:00
|
|
|
|
|
|
|
public BattleEventListener(BattleEventDelegate del)
|
|
|
|
{
|
|
|
|
_del = del;
|
|
|
|
_innerDel = OnEventPtr;
|
2020-08-07 18:28:38 +00:00
|
|
|
FunctionPtr = Marshal.GetFunctionPointerForDelegate<BattleEventPtrDelegate>(_innerDel);
|
2020-07-26 12:47:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void OnEventPtr(IntPtr ptr)
|
2020-08-07 18:28:38 +00:00
|
|
|
{
|
|
|
|
// 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)
|
2020-07-26 12:47:56 +00:00
|
|
|
{
|
|
|
|
var wrapped = WrapEventPtr(ptr);
|
2020-08-07 18:28:38 +00:00
|
|
|
await _del.Invoke(wrapped);
|
2020-07-26 12:47:56 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 15:32:20 +00:00
|
|
|
private static EventData WrapEventPtr(IntPtr ptr)
|
2020-07-26 12:47:56 +00:00
|
|
|
{
|
2020-08-04 15:32:20 +00:00
|
|
|
var evtType = (EventDataKind)Creaturelib.Generated.EventData.GetKind(ptr);
|
2020-07-26 12:47:56 +00:00
|
|
|
switch (evtType)
|
|
|
|
{
|
|
|
|
case EventDataKind.Damage:
|
2020-08-04 15:32:20 +00:00
|
|
|
return new DamageEvent(evtType, ptr);
|
2020-07-26 12:47:56 +00:00
|
|
|
case EventDataKind.Heal:
|
2020-08-07 10:41:02 +00:00
|
|
|
return new HealEvent(evtType, ptr);
|
2020-07-26 12:47:56 +00:00
|
|
|
case EventDataKind.Faint:
|
2020-08-07 10:41:02 +00:00
|
|
|
return new FaintEvent(evtType, ptr);
|
|
|
|
case EventDataKind.Switch:
|
|
|
|
return new SwitchEvent(evtType, ptr);
|
|
|
|
case EventDataKind.TurnStart:
|
|
|
|
return new TurnStartEvent(evtType, ptr);
|
|
|
|
case EventDataKind.TurnEnd:
|
|
|
|
return new TurnEndEvent(evtType, ptr);
|
|
|
|
case EventDataKind.ExperienceGain:
|
|
|
|
return new ExperienceGainEvent(evtType, ptr);
|
2020-07-26 12:47:56 +00:00
|
|
|
case EventDataKind.DisplayText:
|
|
|
|
break;
|
2020-08-04 15:32:20 +00:00
|
|
|
default:
|
2020-08-07 10:41:02 +00:00
|
|
|
throw new ArgumentOutOfRangeException();
|
2020-07-26 12:47:56 +00:00
|
|
|
}
|
2020-08-04 15:32:20 +00:00
|
|
|
Creaturelib.Generated.EventData.Destruct(ptr);
|
2020-07-26 12:47:56 +00:00
|
|
|
throw new NotImplementedException($"Unhandled battle event: '{evtType}'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|