- Home /
YieldInstructions from unmanaged land e.g. WaitForSeconds. Possible?
I see lots of third party tools depending on events and callbacks, but I'd like to know if it's possible to create coroutine-like behaviors (YieldInstructions, Coroutines) from C++.
$$anonymous$$g. WaitForSeconds, WaitForFixedUpdate, Coroutine. Those aren't implemented on managed side (AFAI$$anonymous$$).
So if you have access to the main loop then you can do that - but I'm not sure how that would work as your probably don't. You could I guess write a C# wrapper and have it call into the C++ from the main loop as seen by the $$anonymous$$anaged code.
The principle of Unity Coroutines works based on the $$anonymous$$anaged ability to create state machines from functions that use the yield statement - so you would have to implement that kind of thing yourself, probably in a less "syntactically sweet" way (returning and expecting re-entrancy, probably be with a switch statement or some kind of function pointer manipulation).
@lvictorino Coroutines are decidely not threads, they are more like old fashioned non-pre emptive multitasking.
Not likely to have access to the main loop. I was wondering if Unity held any interface, header to help doing so. Thanks
Answer by Bunny83 · Feb 10, 2014 at 12:28 PM
Your question is very vague what exactly you want to achieve.
Some words about Unity's coroutine mechanism:
Unity's coroutine scheduler is the only one who can start, run or continue a "Coroutine". This scheduler of course can't be modified.
The only possible yield values the scheduler understands are: - classes derived from YieldInstruction (WaitForSeconds, WaitForEndOfFrame, WaitForFixedUpdate, AssetBundleCreateRequest, AssetBundleRequest and Coroutine - a WWW object - "any other value" which isn't one of the above.
The YieldInstruction is just an empty class without any useful interface. The behaviour of the scheduler for the different YieldInstructions is hardcoded into the scheduler.
if "any other value" is yielded (which includes "null" a string value any other basic type such as int, bool, ... or a reference to an arbitrary object which isn't one of the above mentioned) the scheduler will "schedule" the coroutine for the next frame.
Coroutines are managed objects which are under the control of the Unity scheduler.
Coroutines implement a cooperative multitasking and are executed on the main thread like any other scriptcode in unity. There's no parallel execution at all.
Since most built in classes are sealed, you can't derive your own class from them. Also it wouldn't work out since the schedulers behaviour is limited to the known values. Your best bet is to write a seperate coroutine which polls each frame / x amount of time if it should continue or not. Something like this:
//c#
public class CoHelper : MonoBehaviour
{
private static CoHelper m_Instance;
public static CoHelper Instance
{
get
{
if (m_Instance == null)
{
m_Instance = (new GameObject("helper")).AddComponent<CoHelper>();
// DontDestroyOnLoad(m_Instance.gameObject);
}
return m_Instance;
}
}
public static Coroutine WaitForSomeExternalCondition()
{
return Instance.StartCoroutine(_WaitForSomeExternalCondition)
}
private static IEnumerator _WaitForSomeExternalCondition()
{
bool done = false
while(not done)
{
// check your condition and set done to true if your done
yield null;
// yield new WaitForSeconds(UPDATE_INTERVALL);
}
}
}
With that helper you could do this in any coroutine:
IEnumerator SomeRoutine()
{
Dosomething();
yield CoHelper.WaitForSomeExternalCondition();
DoSomethingOther();
}
Keep in mind if you're using threads to use proper locking / synchronising.
edit
I forgot to mention that you could implement your own scheduler like this one: CoroutineScheduler. Unity's scheduler works in a very similar way, however the exact implementation we'll never see since it's implemented in the native part of the engines core. It might have some additional optimisations like a ordered queue for routines which yielded WaitForSeconds and so on.
Unfortunately the authors blog page about coroutines (which was great) doesn't exist anymore. However he kind of copied the content into this post. If you want to understand how coroutines and generator methods work, read it ;)
2. edit
Just re-read the question and i'm still confused what you want to do and where exactly. If this question was about if it's possible to implement coroutines in C++ the same way as in C# then the answer is clearly: no. That's because C# has the yield keyword which is a powerful compiler feature. A method containing a yield statement is translated into a class that implements IEnumerator and the method itself just returns an instance of that class. Since C++ doesn't have this feature you can't do it the same way. The C# compiler has to be very smart to translate your yield-code into a statemachine.
Hey @Bunny83 haven't seen your answer before. Thanks for your reply, all the information here is quite useful.
I'll try to explain it. A lot of third-parties (e.g. iOS GameCenter plug-in), and usually ones that depend on network connection are exposed though APIs that depend on C# events or callbacks most of the time. I'd like to know if it's possible to create non-managed code in C/C++ and use it from C# with the Unity coroutine scheduler (e.g. yield return new WaitForGameCenterAuthentication (), where WaitForGameCenterAuthentication is external, implemented in native code). That would require access to some kind of Unity API at native level, I suppose. I've checked the Xcode project Unity generates to try to find native code concerning this.. but seen nothing interesting.. I hope you get the idea of what I'm trying to achieve.
What I'm doing right now is wrapping those third party librares as coroutines as you explain in your answer. It just works, but I'm curious about the possibility of doing this, just as WWW probably does.
coroutines can't be "resumed" from an external event because, like is said, only the scheduler can resume a coroutine. The "things" you yield just get interpreted by the scheduler when it should resume the coroutine.
So if you yield a WaitForSeconds object the scheduler knows it should continue this coroutine after the specified amount of (game) time. Internally it has to check the state each frame and once the time has passed it resumes the coroutine.
There would be ways to implement resu$$anonymous$$g from "external events" but they have to be implemented inside the scheduler itself. This can't be changed unless you have a full source code license (which is very unlikely).
Alternatively you can implement your own scheduler and own coroutine mechanics if you like. However such an implementation doesn't use Unity's StartCoroutine / YieldInstruction objects, so the usage will be a bit different.
Your answer
Follow this Question
Related Questions
Import (mixed assembly) managed C++/CLI DLL plugin 0 Answers
WaitForSeconds problem with Unity Pro 3 Answers
Wait For Seconds to Load level C# 2 Answers
Corutine not behaving like it should? 1 Answer
Coroutine not running 1 Answer