- Home /
Generate and Run Coroutine at runtime
Okay, this has been eating at me for weeks and I'm at my wits' end. I use coroutines with some regularity in my game, but for this particular part, I'm needing to generate a coroutine on the fly and run it. I've already got some code generating and executing at runtime, but it needs to be a coroutine so I can do things like suspend while waiting for user's input. Here is what I have so far.
using Microsoft.CSharp;
using UnityEngine;
using System;
using System.Collections;
using System.CodeDom.Compiler;
using System.Reflection;
public class RuntimeCompiler : MonoBehaviour {
CSharpCodeProvider provider = new CSharpCodeProvider();
public static RuntimeCompiler instance { get; private set; }
void Awake()
{
if(instance == null)
instance = this;
else
Debug.Log("There are multiple instances of the RuntimeCompiler engine in the scene.");
}
void OnDestroy()
{
instance = null;
}
public class MethodWrapper
{
System.Reflection.MethodInfo method;
public MethodWrapper(System.Reflection.MethodInfo method)
{
this.method = method;
}
public void doIt()
{
IEnumerable en = (IEnumerable)method.Invoke(null, null);
}
}
public System.Action InterpretScript(string script){
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
parameters.ReferencedAssemblies.Add ("System.dll");
parameters.ReferencedAssemblies.Add ("System.Core.dll");
//parameters.ReferencedAssemblies.Add ("System.Collections.dll");
parameters.ReferencedAssemblies.Add (typeof(Transform).Assembly.Location);
parameters.ReferencedAssemblies.Add (typeof(MapExplore).Assembly.Location);
CompilerResults results = provider.CompileAssemblyFromSource(parameters, GetCode(script));
if(!results.Errors.HasErrors){
var cls = results.CompiledAssembly.GetType("DynamicCode");
var method = cls.GetMethod("DynamicMethod", BindingFlags.Static | BindingFlags.Public);
return (new MethodWrapper(method)).doIt;
}else{
foreach (CompilerError error in results.Errors)
{
Debug.Log(error.ErrorText);
}
throw new System.Exception("Dunno Man");
//return null;
}
}
public string[] GetCode(string script)
{
return new string[]
{
@"using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DynamicCode : MapShim
{
public static void DynamicMethod()
{
" + script + @"
}
}
"
};
}
}
public class MapShim : MonoBehaviour
{
//A bunch of methods to make accessing game variables easier
}
So far this all works just fine. "Script" is supplied externally in a string, which is then interpreted into code and run when I invoke it.
*My first disclaimer is that I've had help getting this code working, so I'm a bit lost when it comes to making adjustments. What I need to do is instead have "Script" compiled into a coroutine and then have the invoke trigger that instead. I keep getting problems with object references when I try to do it the way I know how, and I suspect I'm just not structuring something correctly. Any suggestions?
Answer by Captaingerbear · Apr 29, 2014 at 08:59 PM
I actually managed to piece it together today after setting up a new dummy project where I could muck around without fear of breaking things. This is what I came up with -
The following code -
return new string[]
{
@"using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DynamicCode : MapShim
{
public static void DynamicMethod()
{
" + script + @"
}
}
"
};
is replaced with this new code -
return new string[]
{
@"using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DynamicCode : MapShim
{
private static DynamicCode inst;
public static DynamicCode Instance{
get{
if(inst == null){
var go = new GameObject(""DynamicCode"");
inst = go.AddComponent<DynamicCode>();
}
return inst;
}
}
public static void DynamicMethod(){
DynamicCode.Instance.StartCoroutine(CR());
}
public static IEnumerator CR(){
"+script+@"
yield return new WaitForSeconds(0f);
}
}
"
};
This gives me the results I wanted. That said, I am still wide open for suggestions on how I could accomplish this more gracefully.
Your answer
Follow this Question
Related Questions
Tasks with Coroutines don't work properly on play mode 2 Answers
Light Flickering Problem - Wrong objects get referenced by the script 0 Answers
Return value from coroutine to non monobehaviour 1 Answer
Sync WaitForSeconds with Particles 1 Answer
How to create a delay in a function being called in update? 2 Answers