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-08 12:32:27 +00:00
|
|
|
private Task? _currentTask;
|
2020-07-26 12:47:56 +00:00
|
|
|
|
|
|
|
public BattleEventListener(BattleEventDelegate del)
|
|
|
|
{
|
|
|
|
_del = del;
|
|
|
|
_innerDel = OnEventPtr;
|
2020-08-14 14:15:19 +00:00
|
|
|
FunctionPtr = Marshal.GetFunctionPointerForDelegate(_innerDel);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void EnsureFinishedListening()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_currentTask?.Wait();
|
|
|
|
}
|
|
|
|
catch (AggregateException e)
|
|
|
|
{
|
|
|
|
LogHandler.Log(LogHandler.LogLevel.Error, e.GetBaseException().Message);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
LogHandler.Log(LogHandler.LogLevel.Error, e.Message);
|
|
|
|
}
|
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.
|
2020-08-14 14:15:19 +00:00
|
|
|
EnsureFinishedListening();
|
2020-08-07 18:28:38 +00:00
|
|
|
// 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:
|
2020-08-25 17:13:15 +00:00
|
|
|
return new DisplayTextEvent(evtType, ptr);
|
2020-08-14 14:15:19 +00:00
|
|
|
case EventDataKind.Miss:
|
2020-08-25 17:13:15 +00:00
|
|
|
return new MissEvent(evtType, ptr);
|
2020-08-14 14:15:19 +00:00
|
|
|
case EventDataKind.ChangeSpecies:
|
2020-08-25 17:13:15 +00:00
|
|
|
return new ChangeSpeciesEvent(evtType, ptr);
|
2020-08-14 14:15:19 +00:00
|
|
|
case EventDataKind.ChangeVariant:
|
2020-08-25 17:13:15 +00:00
|
|
|
return new ChangeFormeEvent(evtType, ptr);
|
2020-08-14 14:15:19 +00:00
|
|
|
case EventDataKind.AttackUse:
|
2020-08-25 17:13:15 +00:00
|
|
|
return new MoveUseEvent(evtType, ptr);
|
2021-01-31 11:48:02 +00:00
|
|
|
case EventDataKind.ChangeStatBoost:
|
|
|
|
return new ChangeStatBoostEvent(evtType, ptr);
|
2020-08-14 14:15:19 +00:00
|
|
|
case EventDataKind.WeatherChange:
|
|
|
|
break;
|
|
|
|
case EventDataKind.StatusChange:
|
|
|
|
break;
|
2020-08-04 15:32:20 +00:00
|
|
|
default:
|
2021-01-31 11:48:02 +00:00
|
|
|
throw new ArgumentOutOfRangeException();
|
2020-07-26 12:47:56 +00:00
|
|
|
}
|
|
|
|
throw new NotImplementedException($"Unhandled battle event: '{evtType}'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|