PkmnLibSharp/PkmnLibSharp/Battling/Events/BattleEventListener.cs

70 lines
2.7 KiB
C#
Raw Normal View History

2020-07-26 12:47:56 +00:00
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
2020-07-26 12:47:56 +00:00
namespace PkmnLibSharp.Battling.Events
{
public class BattleEventListener
{
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;
private Task _currentTask;
2020-07-26 12:47:56 +00:00
public BattleEventListener(BattleEventDelegate del)
{
_del = del;
_innerDel = OnEventPtr;
FunctionPtr = Marshal.GetFunctionPointerForDelegate<BattleEventPtrDelegate>(_innerDel);
2020-07-26 12:47:56 +00:00
}
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)
2020-07-26 12:47:56 +00:00
{
var wrapped = WrapEventPtr(ptr);
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}'");
}
}
}