using System; using System.Collections.Generic; using Vellum; namespace Ariadne.Vellum.UnitTests { /// /// The context the trigger wait scripts run in, with the triggers they wait on and a log they write to. /// public class Hallway { public Trigger Door = new Trigger(); public Trigger Alarm = new Trigger(); public List Log = new List(); } public class HallwayConverter : SaveConverter { public override SaveNode Write(Hallway value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["door"] = session.ToNode(value.Door); returnMe.Entries["alarm"] = session.ToNode(value.Alarm); returnMe.Entries["log"] = session.ToNode(value.Log); return returnMe; } public override Hallway Read(SaveNode node, SaveSession session) { var returnMe = new Hallway(); session.Publish(node, returnMe); returnMe.Door = session.FromNode(node.RequireEntry("door")); returnMe.Alarm = session.FromNode(node.RequireEntry("alarm")); returnMe.Log = session.FromNode>(node.RequireEntry("log")); return returnMe; } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode door; SaveNode alarm; SaveNode log; if (!node.TryGetEntry("door", out door) || !node.TryGetEntry("alarm", out alarm) || !node.TryGetEntry("log", out log)) { return false; } children.Add(door, typeof(Trigger)); children.Add(alarm, typeof(Trigger)); children.Add(log, typeof(List)); return true; } } /// /// A hallway and what runs in it, which are saved and loaded together. /// public class Scene { public Hallway Hallway; public ContentType Content; } public class SceneConverter : SaveConverter> { public override SaveNode Write(Scene value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["hallway"] = session.ToNode(value.Hallway); returnMe.Entries["content"] = session.ToNode(value.Content); return returnMe; } public override Scene Read(SaveNode node, SaveSession session) { var returnMe = new Scene(); session.Publish(node, returnMe); returnMe.Hallway = session.FromNode(node.RequireEntry("hallway")); returnMe.Content = session.FromNode(node.RequireEntry("content")); return returnMe; } public override bool TryListChildren(SaveNode node, ChildList children) { SaveNode hallway; SaveNode content; if (!node.TryGetEntry("hallway", out hallway) || !node.TryGetEntry("content", out content)) { return false; } children.Add(hallway, typeof(Hallway)); children.Add(content, typeof(ContentType)); return true; } } /// /// A hallway and what runs in it, whose converter doesn't say what it holds, so a load can't plan ahead. /// public class UnplannedScene { public Hallway Hallway; public ContentType Content; } public class UnplannedSceneConverter : SaveConverter> { public override SaveNode Write(UnplannedScene value, SaveSession session) { SaveNode returnMe = SaveNode.NewTable(); returnMe.Entries["hallway"] = session.ToNode(value.Hallway); returnMe.Entries["content"] = session.ToNode(value.Content); return returnMe; } public override UnplannedScene Read(SaveNode node, SaveSession session) { var returnMe = new UnplannedScene(); session.Publish(node, returnMe); returnMe.Hallway = session.FromNode(node.RequireEntry("hallway")); returnMe.Content = session.FromNode(node.RequireEntry("content")); return returnMe; } } /// /// Waits for the door, then logs. /// public partial class HallDoorScript : Arc { protected override void Run(Hallway hallway) { hallway.Log.Add("start"); door: Wait(hallway.Door); hallway.Log.Add("door"); } } /// /// Waits for either trigger with a time limit, and logs which one came. /// public partial class HallTimedScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(Hallway hallway) { hallway.Log.Add("start"); either: Trigger fired = WaitAny(timeout: Limit, hallway.Door, hallway.Alarm); hallway.Log.Add(fired == null ? "timed out" : fired == hallway.Alarm ? "alarm" : "door"); } } /// /// Waits for the alarm with a time limit, then for the door. /// public partial class HallTimedThenDoorScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(Hallway hallway) { alarm: Wait(hallway.Alarm, timeout: Limit); hallway.Log.Add("alarm window over"); door: Wait(hallway.Door); hallway.Log.Add("door"); } } /// /// Waits for the door, then logs its name. /// public partial class HallNamedScript : Arc { public string Name; protected override void Run(Hallway hallway) { door: Wait(hallway.Door); hallway.Log.Add(Name); } } /// /// Waits for either trigger, and logs which one it was. /// public partial class HallEitherScript : Arc { protected override void Run(Hallway hallway) { either: Trigger fired = WaitAny(hallway.Door, hallway.Alarm); hallway.Log.Add(fired == hallway.Alarm ? "alarm" : "door"); } } /// /// Waits for both triggers, and logs which one came last. /// public partial class HallBothScript : Arc { protected override void Run(Hallway hallway) { both: Trigger last = WaitAll(hallway.Door, hallway.Alarm); hallway.Log.Add(last == hallway.Alarm ? "alarm last" : "door last"); } } /// /// Waits for the door twice, with a local counting the trips. /// public partial class HallTwiceScript : Arc { protected override void Run(Hallway hallway) { int count = 0; while (count < 2) { spin: Wait(hallway.Door); ++count; hallway.Log.Add("door " + count); } } } /// /// Offers a passage for other arcs to run, which waits for the door. /// public partial class HallLookoutScript : Arc { public void Watch(Hallway hallway) { watch: Wait(hallway.Door); hallway.Log.Add("seen"); } protected override void Run(Hallway hallway) { } } /// /// Runs the passage of another arc that waits for the door. /// public partial class HallRelayScript : Arc { public HallLookoutScript Lookout; protected override void Run(Hallway hallway) { relay: Lookout.Watch(hallway); hallway.Log.Add("relayed"); } } /// /// Waits in a generic passage, which keeps its locals in a frame of its own. /// public partial class HallGenericScript : Arc { private Trigger Choose(Hallway hallway, ItemType marker) { inner: return WaitAny(hallway.Door, hallway.Alarm); } protected override void Run(Hallway hallway) { outer: Trigger picked = Choose(hallway, 5); hallway.Log.Add(picked == hallway.Alarm ? "alarm" : "door"); } } }