To start-off, I have 5 coroutine managing functions:
function SetupCoroutineTable() coroutine_table = { };endfunction AddCoroutine(Item) table.insert(coroutine_table, Item);endfunction RemoveCoroutine(Index) table.remove(coroutine_table, Index);endfunction ResumeCoroutine(Index) Item = coroutine_table[Index]; if coroutine.status(Item) ~= 'dead' then coroutine.resume(Item); endendfunction ResumeAllCoroutines() for Index,Item in ipairs(coroutine_table) do ResumeCoroutine(Index); endend
I call SetupCoroutineTable at the start of my program. The major issue I see here is that I don't manage the table at all (just keep inserting and only remove when told to.) I could add a managing function that clears the dead coroutines, but this is the least of my concerns right now.
Now for my sample. The main idea behind this is to use for scripting scenes (move player here, show message, do this, etc.) So, I went with counting.
-- the function that my code calls. -- Would be somthing like an event's OnActivate function.function foo() count(10); display('Finished counting to 10.\n'); count(21); display('Finished counting to 21.\n');end-- This is the count function called above.function count(value) set_value(0); -- C# method count_to(value); -- C# method while get_value() < value do -- get_value() is another C# method coroutine.yield(); endend
This is one of my major issue: I don't want to have to write systems like this for everything that I want the script to be able to wait on (i.e. ideally count would be in the actual code.)
Now for the ugly part. I have a method in C#:
public void CallScriptFunction(string Name){ luaVM.DoString(@"local coro = coroutine.create(" + Name + "); InsertCoroutine(coro); coroutine.resume(coro);");}
The main issues being that: it's very hacked together and it's not flexible (doesn't support calling a method with arguments.)
What I'm wondering is if anyone has any insight into a better solution (or some suggestions to improve what I have.)
Edited at 4:25am
I just got done trying a new system. It uses the main portion, but is more flexible. I implemented a class named WaitInfo which contains a delegate that returns a bool. This is returned from any method I want to allow to wait. Then, in my lua code, I pass the WaitInfo to my wait function. Here's the revised code
public delegate bool WaitPredicate();public sealed class WaitInfo{ WaitPredicate predicate; public WaitInfo(WaitPredicate Predicate) { this.predicate = Predicate; } public bool IsFinished() { return predicate(); }}public WaitInfo CountTo(int Value){ TaskManager.Add(new CountTask((task) => { ++countValue; Output += countValue.ToString() + " "; if(countValue >= Value) task.Kill(); })); return new WaitInfo(new WaitPredicate(() => { return countValue >= Value; }));}
The new WaitInfo class and CountTo method (note that I tried just returning a WaitPredicate, but I can't get Lua to call it. I don't get any errors, it's just never called. I was thinking maybe I need to call Invoke or something, but I didn't try it.)
function wait(winfo) while not winfo:IsFinished() do coroutine.yield(); endendfunction foo() local winfo = count_to(10); wait(winfo); display('finished the first count!\n'); winfo = count_to(21); wait(winfo); display('finished the second count!\n');end
The new wait function and update foo function.
This new system is much better than what I had, but I'm still looking for suggestions; especially on the coroutine-wrapping code I've implemented (read: the major hack I have in place.)
Edited at 4:56am
Ok, I just went back through and yes, I can simply return a WaitPredicate and then in wait I just call winfo:Invoke().
Also, is using DoString() as I am even stable? If so, I could omit the wait function and set it up using DoString() straight from the methods (i.e. inside of CountTo and such.)
I'd also like to note that a lot of code is just for testing this (like the CountTo method's code and what-not.) I'm just trying to get the system nailed down.
[Edited by - Programmer16 on October 17, 2010 4:01:55 AM]