/// <summary> /// Like <see cref="WaitUntil{T}(T, BeaconConstraint)"/> /// but additionally include <see cref="Click{T}"/> in one yield. /// /// </summary> public static IEnumerator ClickWhen <T>(T beacon, BeaconConstraint bc) where T : Enum { yield return(WaitUntil(beacon, bc)); yield return(Click <T>(beacon)); }
public static void Beacon <BEACONTYPE>(BEACONTYPE beacon, E7.Minefield.BeaconConstraint bc) where BEACONTYPE : Enum { var result = bc.ApplyToBeacon(beacon); if (result.IsSuccess == false) { Assert.Fail(result.Description); } }
private static IEnumerator SpamInternal <T>(T beacon, BeaconConstraint bc, Func <IEnumerator> spamAction, bool lookFor) where T : Enum { while (Beacon.Check(beacon, bc) == lookFor) { if (spamAction != null) { yield return(spamAction()); } else { yield return(null); } } }
// public sealed class ThrowableWaitUntil : IEnumerator // { // Func<bool> m_Predicate; // public ThrowableWaitUntil(Func<bool> predicate) { m_Predicate = predicate; } // public object Current => null; // public bool MoveNext() // { // try // { // } // } // public void Reset() {} // } /// <summary> /// Remember that base condition for all constraints is that the beacon must be found, /// and to be found the game object must be active. /// /// It will not fail the test if the constraint doesn't happen yet, /// please check manually if you really have that type of /// beacon in the scene or it would wait forever when you actually forgot to add the beacon. /// (Unlike assertion where you immediately get /// an error message telling you about missing beacon.) /// </summary> public static IEnumerator WaitUntil <T>(T beacon, BeaconConstraint bc) where T : Enum { // Debug.Log($"Wait until {Time.frameCount} {bc}"); // yield return new WaitUntil(() => bc.ApplyToBeacon(beacon).IsSuccess); //Debug.Log($"Wait until {Time.frameCount} {bc} {bc.ApplyToBeacon(beacon).IsSuccess}"); while (true) { try { if (bc.ApplyToBeacon(beacon).IsSuccess) { break; } } catch (Exception e) { Debug.Log($"Caught sometihing >>> {e}"); throw; } yield return(null); } //Debug.Log($"Wait ok {Time.frameCount}"); }
/// <summary> /// Until the constraint returns `false`, repeat the action. /// /// The action could spans multiple frames because it works like a coroutine function. /// The constraint check occur again when the <paramref name="spamAction"/> has completed all of its frames. /// /// This is useful to create a "dumb AI" where normally complex actions are required to get through the scene, /// but a simple spam without considering any timing could also do so in a less ideal way. /// /// For example, testing a Mario stage with an objective if you could respawn after death or not, /// could be simplified to holding right and jump repeatedly. /// You are bound to die sooner or later that way. Then you could use this test regardless of stages. /// </summary> public static IEnumerator SpamWhile <T>(T beacon, BeaconConstraint bc, Func <IEnumerator> spamAction) where T : Enum => SpamInternal(beacon, bc, spamAction, lookFor : true);
/// <summary> /// Just check if the constraint passed or not, without affecting failing/passing of the test. /// </summary> public static bool Check <T>(T beacon, BeaconConstraint bc) where T : Enum => bc.ApplyToBeacon(beacon).IsSuccess;