I'm developing an online game server that uses C# for its NPC scripts. To get stateless NPCs I'm using enumerators, yielding when I have to wait for a response from the client, and calling MoveNext once I got it.
Talk()
Msg("test");
Select("Yes", "No");
yield return true;
Msg(Response);
(Simplified example, the yielding is a little more complex in reality.)
This is working fine, but async/wait would make make it cleaner, easier, and more flexible.
Talk()
Msg("test");
Msg(await Select("Yes", "No"));
Playing around with async/wait I've found my only problem to be that the scripts aren't as simple as sending some messages. When calling other functions from the main Talk function I have to await them, since the execution wouldn't stop otherwise. The other functions could also call even more, creating an unknown amount of awaits.
Talk()
Msg("test");
await OtherTalk();
Msg("end"); // would be called right away
OtherTalk()
Msg("test2");
Msg(await Select("Yes", "No"));
If I close the NPC inside such a "sub talk" method I'd potentially leave quite a few tasks hanging in the air, because I wouldn't return up the chain. NPC closed, no more responses, tasks keep waiting.
The solution to this problem would be going the chain back up, with explicit checks after the await of such a function, to check if the NPC was closed somewhere down the line. But I want them to be as simple and straight forward as possible, and frankly, having an if after each call of a function would be too tedious for my taste. The server software will also be used by newbies, who might forget such a check, which could lead to problems, depending on what the script does.
My actual question now is if someone can think of a way to cancel the Tasks, without explicit checks in the scripts themselves.