- 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
 koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                