Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Looking for options to quickly evaluate/run scripts in editor

Discussion in 'General Discussion' started by Flavelius, Jun 3, 2018.

  1. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    Hi,
    i'm very familliar with all the options the UnityEditor namespace provides, but i'm looking for a different kind of solution. Something like an interpreter, that allows me to quickly do scripted batch operations on a scene in editor, by using unity APIs, like FindObjectsOfType, GetComponent etc. (without having to write an editor script and wait for recompilation on every iteration just to remove it again afterwards and recompile).
    Does anything like that exist?
     
  2. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
    Put [ContextMenu("Test")] on function and can run it from editor with right click on component.
     
  3. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    i know
     
  4. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I wonder if ironpython would run in Unity then you could create a editor window were you can write python code that executes on the fly
     
  5. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    I looked at moonsharp which would be a similar solution i guess, but wouldn't i have to write bindings for all APIs i want to expose there first? (from what i gathered about Moonsharp it seems to not be that straightforward to be able to just execute some statements to modify a scene)
     
  6. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I have written a .net app using ironpython, it's open source and can be found here

    https://github.com/AndersMalmgren/FreePIE

    You can exposure entire namespaces to ironpython and then instance classes etc in that namespace
     
  7. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    Interesting. As i have no experience with these sorts of language bindings; how does it handle existing objects from the other domain? For example if i want to access unity's scene graph with FindObjectsOfType. I'd imagine that instances must be serializable and that unity's special objects can't be handled that easily? And as unity's api is mostly static, does that cooperate well?
     
  8. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    It will just work with any CLR type
     
  9. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    Yes, i just tried Ironpython and got it to work the way i needed, thank you for this suggestion!
     
    astracat111 and AndersMalmgren like this.
  10. sxa

    sxa

    Joined:
    Aug 8, 2014
    Posts:
    741
  11. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    I haven't used this for a while, but hopefully someone might find it useful. It's basically an editor script where you can write some code (in form of a class) and then execute it, so no need to save anything. It has 2 scripts, ProtoTyper.cs and Compiler.cs. Place ProtoTyper.cs inside an 'Editor' folder, and Compiler.cs can be placed somewhere else. To open the ProtoTyper window simply click in the menu on Window and then on ProtoTyper. If you're going to try this and have troubles or questions let me know.

    Note: I made this on Windows and it may not work in the Linux editor, I tried that some time ago but didn't get that to work.

    Code (csharp):
    1.  
    2. //Compiler.cs
    3. using System.Reflection;
    4. using System;
    5. using Microsoft.CSharp;
    6. using System.CodeDom.Compiler;
    7. public static class Compiler
    8. {
    9.     public static void Compile(string source)
    10.     {
    11.         //find first occurrence of a class in source
    12.         int i = source.IndexOf(" class ");
    13.         string classname = source.Substring(i + 7);
    14.         classname = classname.Split(' ')[0];
    15.         classname = classname.Replace("\r", "");
    16.         classname = classname.Replace("\n", "");
    17.         classname = classname.Replace("\t", "");
    18.         classname = classname.Replace("{", "");
    19.         var assembly = CompileSource(source);
    20.         Type type = null;
    21.         try
    22.         {
    23.             type = assembly.GetType(classname);        
    24.          
    25.             //object instance = Activator.CreateInstance(test);
    26.             ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
    27.             ProtoTyper.Log("Compiled ok");
    28.             object classObject = constructor.Invoke(new object[] { }); //calls constructor  
    29.          
    30.         }
    31.         catch (Exception ex)
    32.         {
    33.             //Debug.Log("Couldn't create assembly: " + ex.Message);
    34.             ProtoTyper.Log("Couldn't create assembly: " + ex.Message);
    35.         }
    36.     }
    37.     private static Assembly CompileSource(string source)
    38.     {
    39.         var provider = new CSharpCodeProvider();
    40.         var param = new CompilerParameters();
    41.         // Add ALL of the assembly references
    42.         foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    43.         {
    44.             param.ReferencedAssemblies.Add(assembly.Location);
    45.         }
    46.         // Add specific assembly references
    47.         //param.ReferencedAssemblies.Add("System.dll");
    48.         //param.ReferencedAssemblies.Add("CSharp.dll");
    49.         //param.ReferencedAssemblies.Add("UnityEngines.dll");
    50.         // Generate a dll in memory
    51.         param.GenerateExecutable = false;
    52.         param.GenerateInMemory = true;
    53.         // Compile the source
    54.         var result = provider.CompileAssemblyFromSource(param, source);
    55.         if (result.Errors.Count > 0)
    56.         {
    57.             string msg = "";
    58.             foreach (CompilerError error in result.Errors)
    59.             {
    60.                 msg = "Error (" + error.ErrorNumber + "): " + error.ErrorText;
    61.                 ProtoTyper.Log(msg.ToString());
    62.             }
    63.             return null;
    64.         }
    65.         // Return the assembly
    66.         return result.CompiledAssembly;
    67.     }
    68. }
    69.  
    Code (csharp):
    1.  
    2. //ProtoTyper.cs
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Collections;
    6. using System.Collections.Generic;
    7. public class ProtoTyper : EditorWindow
    8. {
    9.     private static List<string> errorList;
    10.     private static Vector2 scrollpos = Vector2.zero;
    11.     private static Vector2 scrollpos2 = Vector2.zero;
    12.     private static string consoleText =
    13.     @"using UnityEngine;
    14.    using System;
    15.  
    16.    public class ProtoType
    17.    {
    18.        public ProtoType()
    19.        {
    20.            DoStuff();
    21.        }
    22.        public void DoStuff()
    23.        {
    24.            Debug.Log(""Hello world!"");
    25.        }
    26.    }";
    27.     [MenuItem("Window/ProtoTyper")]
    28.     private static void ShowEditor()
    29.     {
    30.         ProtoTyper editor = EditorWindow.GetWindow<ProtoTyper>();
    31.         editor.Init();
    32.     }
    33.     public void Init()
    34.     {
    35.         if (errorList == null)
    36.             errorList = new List<string>();
    37.     }
    38.     public void OnGUI()
    39.     {
    40.         GUILayout.BeginHorizontal();
    41.      
    42.         if (GUILayout.Button("Compile", GUILayout.Width(100)))
    43.         {
    44.             string source = consoleText;
    45.             Compiler.Compile(source);
    46.         }
    47.         if (GUILayout.Button("Clear Log", GUILayout.Width(100)))
    48.         {
    49.             errorList.Clear();
    50.         }
    51.         GUILayout.EndHorizontal();
    52.         scrollpos = GUILayout.BeginScrollView(scrollpos);
    53.         consoleText = EditorGUILayout.TextArea(consoleText, GUILayout.MinHeight(Screen.height-100));
    54.         GUILayout.EndScrollView();
    55.         scrollpos2 = GUILayout.BeginScrollView(scrollpos2, GUILayout.Height(100));
    56.         if (errorList.Count > 0)
    57.         {
    58.             GUILayout.BeginVertical();
    59.             for (int i = 0; i < errorList.Count; i++)
    60.             {
    61.                 GUILayout.Label(errorList[i]);
    62.             }
    63.             GUILayout.EndVertical();
    64.         }
    65.         GUILayout.EndScrollView();
    66.     }
    67.     public static void Log(string message)
    68.     {
    69.         errorList.Add(message);
    70.     }
    71. }
    72.  
     
    Last edited: Jun 4, 2018
    Flavelius and angrypenguin like this.
  12. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    Ah, i didn't think about this, thanks for suggesting it!
    Edit: It seems to have a few downsides though (like not being able to unload the assembly again)
     
    Last edited: Jun 5, 2018