Search Unity

[Released] Roslyn C# - Runtime C# compiler

Discussion in 'Assets and Asset Store' started by scottyboy805, Mar 27, 2019.

  1. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Ok, That all looks fine to me and you should be able to access it with no problem from external code. All that is needed is an assembly reference. Could you try adding the following code before you call a 'Compile' method and see if that changes anything:

    Code (CSharp):
    1. domain.RoslynCompilerService.ReferenceAssemblies.Add(AssemblyReference.FromAssembly(typeof(Main).Assembly));
     
  2. BeastBomber24

    BeastBomber24

    Joined:
    Jun 10, 2019
    Posts:
    5
    That works! thanks
     
  3. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Glad to hear it's working now. I am not sure why it it did not work correctly when adding a reference via the settings window. Perhaps the name was mistyped or the file extension should be excluded? Anyway, as long as the code reference is working well for you.

    let me know if there is anything else.
     
  4. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# version 1.5.0 has been submitted to the asset store for review and will be available within the next couple of days.

    This version includes breaking changes and a fresh install is required to avoid errors on import. Always make a project backup before doing so. See also the 'Upgrade guide' section of User Guide for steps to upgrade your project.

    The update includes the following changes:
    • Restructured the scripting API to allow expansion assets to be easily added.
    • Added event handler support for events defined in external code.
    • Minor bug fixes.
    New feature - Events
    The update also includes support for events defined in external code in a similar way that fields and properties are handled. This makes it quite simply to add and remove event handlers for external events. Here is a quick example:
    Code (CSharp):
    1. class Example : MonoBehaviour
    2. {
    3.     string externalCode = @"
    4.    class EventExample { public event Func<string, int> exampleEvent; }";
    5.  
    6.     public void Start()
    7.     {
    8.         // Create a script proxy as you normally would
    9.         ScriptProxy proxy = ...
    10.  
    11.         // Access an event named 'exampleEvent' and add a listener
    12.         proxy.SafeEvents["exampleEvent"].AddListener<string, int>(CustomEventHandler);
    13.     }
    14.  
    15.     public int CustomEventHandler(string input)
    16.     {
    17.         Debug.Log("This message will be displayed when the external code raises the event");
    18.         return 0;
    19.     }
    20. }
    It can be even simpler if the event does not return a value as the compiler can infer the generic paremeters:
    Code (CSharp):
    1. class Example : MonoBehaviour
    2. {
    3.     string externalCode = @"
    4.    class EventExample { public event Action<string, int, object> anotherExampleEvent; }";
    5.  
    6.     public void Start()
    7.     {
    8.         // Create a script proxy as you normally would
    9.         ScriptProxy proxy = ...
    10.  
    11.         // Access an event named 'anotherExampleEvent' and add a listener
    12.         proxy.SafeEvents["anotherExampleEvent"].AddListener(CustomEventHandler);
    13.     }
    14.  
    15.     public void CustomEventHandler(string input, int value, object obj)
    16.     {
    17.         Debug.Log("This message will be displayed when the external code raises the event");
    18.     }
    19. }
    You can also access static events via a ScriptType instance like so:
    Code (CSharp):
    1. ScriptType scriptType = ...
    2.  
    3. scriptType.EventsStatic["MyEvent"].AddListener(...)
    4. scriptType.SafeEventsStatic["MyEvent"].AddListener(...)
     
    Last edited: Mar 8, 2021
    Yavvn likes this.
  5. Yavvn

    Yavvn

    Joined:
    May 8, 2019
    Posts:
    18
    Keep up the great work! A lot of value in this asset.
     
    scottyboy805 likes this.
  6. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Thanks for the support!
    Let me know if there are any features you would like to see :)
     
  7. Armithaig

    Armithaig

    Joined:
    Aug 8, 2020
    Posts:
    1
    Pardon if this has already been implemented in a more recent version (we're on 1.2 I think until I ask our very busy project lead to update) but'd like to get at the deterministic flag of the CSharpCompilationOptions so the generated CompilationResult.OutputAssemblyImage would (hopefully) be identical between compiles.
     
  8. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Thanks for requesting this feature.
    It is not something that is available in the latest verion of the asset, but we will be sure to add it in the next update. We will add a new option in the settings window to enable or disable the deterministic option for the compiler.

    Let me know if there is anything else you would like to see added, or if there is anything else.
     
    Armithaig likes this.
  9. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# version 1.5.1 has been submitted to the asset store for review. This version includes:
    • Added new settings option 'Deterministic' to produce the same output assembly for an identical input.
    • Added new feature: Compilation support for syntax trees.
    • Minor bug fixes.
    Syntax Tree Compilation
    We have added a number of new 'Compile' methods to the ScriptDomain type to support compilation from syntax tree objects. This allow you to compile source code that you have already pre-parsed at some point, reducing the overall compilation time by not repeating operations. It also allow you to generate executable code on the fly which brings a whole array of new possibilities.

    Here is a quick example of generating some code on the fly using the new API's:

    Generate a syntax tree using the 'Microsoft.CodeAnalysis' APi's:

    Code (CSharp):
    1. CompilationUnitSyntax syntax = SyntaxFactory.CompilationUnit()
    2.             .AddUsings(
    3.                 SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("UnityEngine")))
    4.             .AddMembers(
    5.                 SyntaxFactory.ClassDeclaration("Example")
    6.                 .AddMembers(              
    7.                     SyntaxFactory.MethodDeclaration(SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), "SayHello")
    8.                     .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))
    9.                     .AddBodyStatements(
    10.                         SyntaxFactory.ExpressionStatement(
    11.                             SyntaxFactory.InvocationExpression(
    12.                                 SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
    13.                                 SyntaxFactory.IdentifierName("Debug"),
    14.                                 SyntaxFactory.IdentifierName("Log"))
    15.                         .WithOperatorToken(SyntaxFactory.Token(SyntaxKind.DotToken))
    16.                         ).WithArgumentList(
    17.                                 SyntaxFactory.ArgumentList(
    18.                                     SyntaxFactory.SingletonSeparatedList<ArgumentSyntax>(
    19.                                         SyntaxFactory.Argument(
    20.                                             SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression,
    21.                                             SyntaxFactory.Literal("Hello World"))))))))));
    This syntax tree building code is essentially generating the following C# code representation:

    Code (CSharp):
    1. using UnityEngine;
    2. public class Example
    3. {
    4.     public static void SayHello()
    5.     {
    6.         Debug.Log("Hello World");
    7.     }
    8. }

    You can then compile and execute that syntax tree using the new methods like so:

    Code (CSharp):
    1. // Get syntax tree
    2. CSharpSyntaxTree syntaxTree = CSharpSyntaxTree.Create(syntax) as CSharpSyntaxTree;
    3.  
    4. // Compile the syntax tree with references
    5. ScriptType type = domain.CompileAndLoadMainSyntaxTree(syntaxTree);
    6.  
    7. // Invoke the say hello method
    8. type.CallStatic("SayHello");
    9.  
    10. // Output: 'Hello World'
    The resulting assembly will still be security validated when compiled, or you can elect to not run security checks if the syntax tree is being generated by your own code by passing 'ScriptSecurityMode.EnsureLoad' to the compile method.
     
    Last edited: Mar 19, 2021
  10. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    IL2CPP Update 3
    We have made some more progress on our side project to support IL2CPP and have added support for a few more features, as well as fixed a few bugs. We have also been doing quite a bit of testing to make sure everything is working as expected, although there are some features that still need work. The main news though is that we have started an early public beta so that we can get much better feedback and bug reports for the add-on:

    Early Public Beta
    We have decided to publish a beta version of the asset so that we can speed up the testing process. We have already got tests in place for the core functionality which are all passing, as well as a few example games that we have put toghether for testing purposes. We figure that bugs will come up much more often in real world use cases/projects and we can then work to fix them accordingly. All beta versions can be downloaded on our discord server under the 'Roslyn C# - IL2CPP WIP' category, where there are also channels for reporting bugs and discussing the add-on in general. There is no documentation at present however there are a couple of example scripts and demo games included.

    If you do come accross a bug or error when trying out the beta, we would highly appreciate it if you could report it either on this forum, on the discord server, or via our website (Use all '0s' for invoice number). Ideally the bug report should include the following items:

    • All error messages/exception messages that are logged in the console or build (not duplicates), or the editor/player log file.
    • The test code you are compiling in interpreted mode as C# source code, or the pre-compiled managed .dll file.
    • Anything else you feel may be related/important.

    We have also created another basic example game (Snake) since the last update which through up a few issues that we have now fixed. The full game source code was defined in a text asset which is loaded, compiled and interpreted at runtime and works very well indeed. Here is the full source code for the snake game that we created for this test:

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. namespace TrivialCLR.Example
    5. {
    6.     public class SnakeGame : MonoBehaviour
    7.     {
    8.         // Types
    9.         private enum TileType
    10.         {
    11.             Empty,
    12.             Wall,
    13.             Food,
    14.         }
    15.  
    16.         private enum SnakeDirection
    17.         {
    18.             Up,
    19.             Down,
    20.             Left,
    21.             Right,
    22.         }
    23.  
    24.         // Private
    25.         private TileType[,] map = null;
    26.         private SnakeDirection currentDirection = SnakeDirection.Left;
    27.         private List<Vector2Int> snakeBody = new List<Vector2Int>();
    28.         private List<GameObject> snakeTiles = new List<GameObject>();
    29.         private GameObject foodInstance = null;
    30.         private float moveTimer = 0f;
    31.         private bool gameOver = false;
    32.  
    33.         private GameObject snakeTile = null;
    34.         private GameObject foodTile = null;
    35.         private GameObject backgroundTile = null;
    36.         private GameObject wallTile = null;
    37.  
    38.         public const int gameWidth = 32;
    39.         public const int gameHeight = 18;
    40.         public const float updateRate = 0.15f;
    41.  
    42.         // Methods
    43.         public void Start()
    44.         {
    45.             snakeTile = Resources.Load<GameObject>("Snake");
    46.             foodTile = Resources.Load<GameObject>("food");
    47.             backgroundTile = Resources.Load<GameObject>("background");
    48.             wallTile = Resources.Load<GameObject>("wall");
    49.  
    50.  
    51.             // Initialize map
    52.             map = new TileType[gameWidth, gameHeight];
    53.             BuildMap();
    54.             BuildSnake();
    55.  
    56.             CreateFood();
    57.         }
    58.  
    59.         public void Update()
    60.         {
    61.             if (gameOver == true)
    62.                 return;
    63.  
    64.             // Inputs
    65.             if (Input.GetKey(KeyCode.UpArrow) == true) currentDirection = SnakeDirection.Up;
    66.             else if (Input.GetKey(KeyCode.DownArrow) == true) currentDirection = SnakeDirection.Down;
    67.             else if (Input.GetKey(KeyCode.LeftArrow) == true) currentDirection = SnakeDirection.Left;
    68.             else if (Input.GetKey(KeyCode.RightArrow) == true) currentDirection = SnakeDirection.Right;
    69.  
    70.             // Move snake
    71.             if(Time.time > moveTimer + updateRate)
    72.             {
    73.                 MoveSnake(currentDirection);
    74.                 moveTimer = Time.time;
    75.             }
    76.         }
    77.  
    78.         private void MoveSnake(SnakeDirection direction)
    79.         {
    80.             Vector2Int offset = new Vector2Int();
    81.  
    82.             switch (direction)
    83.             {
    84.                 case SnakeDirection.Up: offset = new Vector2Int(0, 1); break;
    85.                 case SnakeDirection.Down: offset = new Vector2Int(0, -1); break;
    86.                 case SnakeDirection.Left: offset = new Vector2Int(-1, 0); break;
    87.                 case SnakeDirection.Right: offset = new Vector2Int(1, 0); break;
    88.             }
    89.  
    90.             // Get target index
    91.             Vector2Int targetIndex = snakeBody[0] + offset;
    92.  
    93.             // Check for wall
    94.             if(map[targetIndex.x, targetIndex.y] == TileType.Wall || snakeBody.Contains(targetIndex) == true)
    95.             {
    96.                 gameOver = true;
    97.                 return;
    98.             }
    99.  
    100.             // Check for food
    101.             if(map[targetIndex.x, targetIndex.y] == TileType.Food)
    102.             {
    103.                 // Collect the food
    104.                 map[targetIndex.x, targetIndex.y] = TileType.Empty;
    105.                 Destroy(foodInstance);
    106.  
    107.                 // Grow snake
    108.                 snakeBody.Add(snakeBody[snakeBody.Count - 1]);
    109.                 snakeTiles.Add(Instantiate(snakeTile, IndexToPosition(snakeBody[snakeBody.Count - 1]), Quaternion.identity, transform));
    110.  
    111.                 CreateFood();
    112.             }
    113.  
    114.             // Move snake      
    115.             //for (int i = 1; i < snakeBody.Count; i++)
    116.             for(int i = snakeBody.Count - 1; i >= 1; i--)
    117.             {
    118.                 snakeBody[i] = snakeBody[i - 1];
    119.                 snakeTiles[i].transform.position = IndexToPosition(snakeBody[i]);
    120.             }
    121.  
    122.             snakeBody[0] += offset;
    123.             snakeTiles[0].transform.position = IndexToPosition(snakeBody[0]);
    124.         }
    125.  
    126.         private void CreateFood()
    127.         {
    128.             Vector2Int index = new Vector2Int();
    129.             bool validIndex = false;
    130.  
    131.             while(validIndex == false)
    132.             {
    133.                 index = new Vector2Int(Random.Range(0, gameWidth), Random.Range(0, gameHeight));
    134.  
    135.                 if (map[index.x, index.y] == TileType.Empty && snakeBody.Contains(index) == false)
    136.                     validIndex = true;
    137.             }
    138.  
    139.             map[index.x, index.y] = TileType.Food;
    140.             foodInstance = Instantiate(foodTile, IndexToPosition(index), Quaternion.identity, transform);
    141.         }
    142.  
    143.         private void BuildMap()
    144.         {
    145.             for(int x = 0; x < gameWidth; x++)
    146.             {
    147.                 for(int y = 0; y < gameHeight; y++)
    148.                 {
    149.                     map[x, y] = TileType.Empty;
    150.  
    151.                     if (x == 0 || y == 0 || x == gameWidth - 1 || y == gameHeight - 1)
    152.                         map[x, y] = TileType.Wall;
    153.  
    154.                     // Build tile
    155.                     GameObject tile = Instantiate((map[x, y] == TileType.Wall) ? wallTile : backgroundTile);
    156.  
    157.                     // Set parent and position
    158.                     tile.transform.SetParent(transform);
    159.                     tile.transform.localPosition = IndexToPosition(new Vector2Int(x, y), 1f);
    160.                 }
    161.             }
    162.         }
    163.  
    164.         private void BuildSnake()
    165.         {
    166.             int x = gameWidth / 2;
    167.             int y = gameHeight / 2;
    168.  
    169.             for(int i = 0; i < 5; i++)
    170.             {
    171.                 snakeBody.Add(new Vector2Int(x, y));
    172.                 snakeTiles.Add(Instantiate(snakeTile, IndexToPosition(new Vector2Int(x, y)), Quaternion.identity, transform));
    173.                 x++;
    174.             }
    175.         }
    176.  
    177.         private Vector3 IndexToPosition(Vector2Int index, float z = 0)
    178.         {
    179.             return new Vector3(-(gameWidth / 2) + index.x, -(gameHeight / 2) + index.y, z);
    180.         }
    181.     }
    182. }
    183.  

    This works perfectly fine on IL2CPP standalone builds. We would have linked to a WebGL build but we are currently having issues getting it to work at the moment. The problem is not related at all to the interpreter, but from some initial investigation, it looks like the WebGL process is freezing when trying to compile the source code above. The above source code works perfectly in a standalone IL2CPP build, and our other maze crawler demo game also works without issue in a WebGL build, so a bit more investigation is required. If anyone has experience debugging WebGL builds, then it would be great to hear from you.

    In case you were interested in the problems that this source code identified:

    • Generic member arguments: We found and fixed a bug with invoking generic methods defined in non-generic types thanks to the use of 'Instantiate<T>' in this source code. Generic methods now work fine.
    • Multidimensional arrays: This one was a little trickier as we discovered that the standard runtime environment performs a little bit of trickery when it comes to 2 or more dimensional arrays. Essentially there are 'magic methods' that are injected by the runtime to initialize, get and set mutlidimensional array elements. We have now replicated this behaiviour and the arrays now work just as expected.
    That is all for now.

    IL2CPP project is renamed to dotnow-interpreter and is now open source on github under the MIT license: https://github.com/scottyboy805/dotnow-interpreter
     
    Last edited: Dec 19, 2021
    buzmez_simbt and Kirsche like this.
  11. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# version 1.6.0 has been submitted to the asset store for review. This version includes:
    • Fixed a bug where the compiler could generate incorrect metadata assembly names.
    • Added new feature 'Domain Broadcasts'
    • Added new feature 'Moddable script Replacement'.
    • Minor bug fixes.
    Domain Broadcasts
    This feature allows you to easily invoke static or instance methods for all loaded script types or script proxies. This is particularity useful if you want to implement custom events similar to Unity (Start, Update etc.). It is used in a similar way to Unity's 'BroadcastMessage' but is much more versatile since it is not limited to instance methods or game objects. Here is a quick example:

    Code (CSharp):
    1. class BroadcastExample : MonoBehaviour
    2. {
    3.     private ScriptDomain domain = null;
    4.     private const string sourceCode = @"
    5.    using UnityEngine;
    6.    class ExampleStatic
    7.    {
    8.        void StaticExample(string input)
    9.        {
    10.            Debug.Log(""Hello "" + input);
    11.        }
    12.    }
    13.  
    14.    class ExampleBehaviour : MonoBehaviour
    15.    {
    16.        void BehaviourExample(string input)
    17.        {
    18.            Debug.Log(""Hello "" + input);
    19.        }
    20.    }
    21.  
    22.    class ExampleInstance
    23.    {
    24.        void InstanceExample(string input)
    25.        {
    26.            Debug.Log(""Hello "" + input);
    27.        }
    28.    }";
    29.  
    30.     public void Start()
    31.     {
    32.         // Create domain
    33.         domain = ScriptDomain.CreateDomain("Example Domain");
    34.  
    35.         // Compile and load code
    36.         ScriptType type = domain.CompileAndLoadMainSource(sourceCode);
    37.  
    38.         // We need to create an instance to receive the broadcast
    39.         type.CreateInstance();
    40.  
    41.         // Invoke all static methods named 'StaticExample' on loaded types with matching argument list
    42.         domain.StaticBroadcast("StaticExample", "World");
    43.      
    44.         // Invoke all instance methods named 'ExampleMethod"' on loaded monobehaviour components with matching argument list
    45.         domain.BroadcastActiveScene("ExampleBehaviour", "World");
    46.  
    47.         // Invoke all instance methods named 'InstanceExample' on loaded non-monobehaviour instance with matching argument list
    48.         domain.BroadcastInstance(typeof(object), "InstanceExample", "World");
    49.     }
    50. }

    Moddable Script Replacement
    Another new feature which may be useful if you are using Roslyn C# to add modding support to your game. This feature allows you to replace in game behaviour scripts with externally compiled replacements in order to provide new or changed behaviour.

    Simply add the 'ModReplaceableBehaviour' attribute to your game scripts to indicate that they can be replaced by external code. Via the attribute declaration, you can provide an optional script name that the external code must use in order to be selected (Default script name is used if no name is provided). You can also specify a base type that the external script must inherit from in order to be considered, as well as a collection of interface types which must be implemented:

    Code (CSharp):
    1. public class MyGameBaseClass : MonoBehaviour {}
    2.  
    3. [ModReplaceableBehaviour("MyOverrideGameClass", typeof(MyGameBaseClass))]
    4. public class MyGameClass : MyGameBaseClass
    5. {
    6.     public Transform target;
    7. }
    Once you have a suitable replaceable game component setup, you can then use the new 'ModScriptReplacer' to override components at runtime:

    Code (CSharp):
    1. public class Example : MonoBehaviour
    2. {
    3.     string source = @"public class MyOverrideGameClass : MyGameBaseClass
    4.    {
    5.        public Transform target;
    6.    }";
    7.    
    8.     void Start()
    9.     {
    10.         // Create domain as usual
    11.         ScriptDomain domain = ...
    12.        
    13.         // Compile code as usual using any method
    14.         ScriptAssembly asm = domain.CompileAndLoadSource(...)
    15.        
    16.        
    17.         // Use the script replacer to replace code
    18.         ModScriptReplacer.ReplaceScriptsForActiveScene(asm);
    19.     }
    20. }
    This will construct a new instance of the type 'MyOverrideGameClass' to replace the original game version, as setup in the attribute declaration. Another useful feature is that all public or serialized fields will be copied over from the original script by default, meaning that the 'target' field value will be transfered over in this example.

    You can find the 'ModScriptReplacer' type and all of its associated components under the new namespace 'RoslynCSharp.Modding'.

    Hopefully these new features will allow you to do many more amazing things with our asset :)
     
  12. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    IL2CPP Update 4
    Just a quick update for IL2CPP platforms. We have just released beta version 0.0.4b over on our discord server which has some big improvements in performance and stability. It will be some time before we can release anything official on the asset store as much more real world testing and optimization is required, but we are working on it. The beta is open to anyone who is interested, and we would love to see some more users come and try it out in real world applications. Just join our discord server where you will have access to download the package, as well as support from myself and other users who are also interested in this project.

    IL2CPP project is renamed to dotnow-interpreter and is now open source on github under the MIT license: https://github.com/scottyboy805/dotnow-interpreter
     
    Last edited: Dec 19, 2021
    buzmez_simbt and dmenefee like this.
  13. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.1 has been submitted to the asset store for review. This version includes:
    • Added new compile method 'CompileAndLoadDirectory' which can be used to compile all source files in a given directory. Supports options such as file filtering and top level/nested directories.
    • ModScriptReplacer now supports copying non-serialized fields for potential use with hot reloading
    • API compatibility changes (Non-breaking)
    • Minor bug fixes.
     
  14. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.1 has been submitted to the asset store for review. This version includes:
    • Added new feature 'Runtime hot reloading'.
    • Added 'Hot Reloading' section to the settings window.
    The hot reloading feature allows you to quickly make changes to C# scripts while in play mode and see the effects almost instantly. It is designed for quick iteration/testing of decoupled components and can speed up the workflow greatly for such tasks. The feature works by utilising the Roslyn compiler to compile and load only modified source files while in play mode. The original script will then be replaced and execute as normal, with the option to copy serialized and non-serialized fields to preserve state.

    There are some limitations:
    • If the script references other user defined script, compiation may fail. This is why it is only recommended for decoupled/independant scripts.
    • Other scripts in the scene that hold references to a reloaded script will loose their references when a hot reload occurs. The feature may not be useful to you in this scenario.
    • You must disable auto referesh in the Unity preferences in order to have any gain. Failing to do so will cause Unity to perform an full runtime teardown, compilation and reload sequence when a script is changed, killing any chance at a speedy reload.
    We will be expanding/improving the feature in future updates and we would be interested to hear any feedback you might have.
     
  15. DylanF

    DylanF

    Joined:
    Jun 25, 2013
    Posts:
    55
    Hot Reload looks amazing - nice work!

    It doesn't quite work in this version though. The fileOperations list in RealtimeScriptWatcher is never acted on. It does work after a quick code change that runs OnReloadScript though. Really cool!

    I don't think disabling Auto Refresh is necessary though. Isn't it enough to set "Script changes while playing" to "Recompile after finished playing"?
     
    scottyboy805 likes this.
  16. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Glad to hear that you like the hot reload feature.

    Thanks for letting me know that it is not working as expected. It looks like an experimental testing branch was submitted by mistake instead of the release version. We have resubmitted the package and it should be live within a day or two as version 1.6.2. Feel free to email us with your invoice number if you need it sooner: info(at)trivialinteractive.co.uk

    We also took the opportunity to add in a new option 'Security Check Reloaded Code' which is disabled by default. This will prevent security checks from running when hot reloading code to improve the reload time. We are seeing an average reload time of about 100ms for a simple behaviour script (First reload is about 10x more due to JIT of the large compiler code base).

    You are correct about the auto refresh option. You can just use the script changes option to not compile scripts while in play mode.
     
    Last edited: Jun 11, 2021
    DylanF likes this.
  17. DylanF

    DylanF

    Joined:
    Jun 25, 2013
    Posts:
    55
    This is a great system. I love being able to hotload monobehaviours that live right in the project (instead of in an external assembly). It's working well even in a large project.

    Feature Request: A simple way to update runtime-created objects to their most recent version at creation. Right now, a newly-instantiated object won't get update to the latest hotload version until the source file changes while it's alive. It would be nice for it to automatically update when created. Maybe it could inherit from a base class that takes care of it, or it could call some global utility function when created to update itself if needed.

    Quick change: With this small change, ReplaceScriptsForScene (in ModScriptReplacer.cs) can replace objects on inactive gameobjects as well as active ones:
    foreach (MonoBehaviour behaviour in gameObject.GetComponentsInChildren<MonoBehaviour>(true))
     
  18. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Glad to hear you are enjoying the hot reloading feature.
    It is also nice to hear that it is working well in a larger project since we have only tested it out in relatively small projects so far.

    Instantiated objects is a tricky problem to solve, since the is no easy event or anything for when an object is added to the scene. We will have to have a think about how would could do something to support that use case while making it as simple and automatic as possible. We would like to avoid requiring specific base classes or attributes if at all possible, as we would like the feature to work on 'normal' Unity scripts. If you can think of any possible ways to do it, then please let us know :), otherwise we will have a think and do some teting to see what we can come up with.

    We have now integrated your requested change to support non active objects and it will be coming in the next update. We chose to make it an optional feature that is enabled by default though to give developers more flexibility. You can toggle the option via the 'Hot Reload' tab in the settings window.
     
  19. DylanF

    DylanF

    Joined:
    Jun 25, 2013
    Posts:
    55
    I haven't thought of a totally clean way to do it unfortunately. It's not that big of an issue for me though since objects instantiated from scene objects (instead of prefabs) and pooled objects work great as it is now.
     
    scottyboy805 likes this.
  20. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,090
    Default interfaces implementation since Unity 2021.2?

    I'm interested in this asset but what about mobile/il2cpp etc? Is it ever going to be supported?
     
  21. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Yep, that would be one way of doing it, although we would rather keep it completely automatic if at all possible. We don't want to force a user to implement an interface so that they can have working hot reloading if we can help it. We may be able to create a system that watches for spawned objects in play mode, and makes sure that they are using the latest hot reload script. It will require further testing though when we get chance, but we will look into it shortly.

    We hope to support IL2CPP in the future. We have a working proof of concept at the moment which can run on IL2CPP platforms using a custom MSIl interpreter that we have developed. However, some runtime features are not 100% implemented at the moment/bug free. For example, structs are treated as reference types for the moment. We will keep working on it as and when we get chance and I will continue to post updates here as we make progress. It is a big undertaking though and will take time to get there. It is also a side project for us at the moment since it is not saleable in its current state, so progres may not be as quick as some of our released assets. Feel free to give it a try though as it is in open beta and we would welcome any feedback/bug reports.
     
  22. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,090
    2 more questions:

    What "Fully commented partial C# source code included" means exactly. For ex. if there's a bug in il2cpp will I be able to fix it myself or not as it's compiled?

    Any idea if it works on iOS the same way it's on Android? There's some misinformation going around the internet but they've changed their TOS in recent years to allow it:
     
  23. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Partial source code means that there is a mix of C# source code and managed assemblies that we include. All included C# source code is fully commented. Here is a quick breakdown:

    Assemblies Include:
    • Microsoft Roslyn Compiler binaries and dependencies
    • Trivial.CodeSecurity: Our proprietary code analysis tool used to detect potentially harmful code
    Source code included:
    • The whole runtime and editor RoslynCSharp API that we have built for Unity. This includes runtime compilation API's, Useful modding utilities, hot reloading features and more.
    • Supporting editor scritps

    You can take a look at the package contents on the asset store to see what is included. Simply find the asset page and select the 'Package Content' button to view a list of assets in the package.

    The IL2CPP feature is not released yet as I mentioned, and likley wont be for some time. It is only available at the moment via our discord server for early access/beta testing and feedback. For that reason, it is closed source for the moment but we will include all C# souce code we can when we release it officially.


    IOS cannot work the same way as Android because it requires IL2CPP, where Android can still run on Mono. For this reason, it is possible with a bit of work to get Roslyn C# running on Android right now using the Mono backend, and everything will work nicely. For IOS, our MSIL interpreter will be required to execute any compiled code, since it is not possible to load any code on AOT platforms.

    The IOS TOS are not a concern to us since we only intend to support IL2CPP platforms in general. If you choose to use our tool on IOS, then it will be up to you to follow the rules. We are only interested in what is technically possible and how we can do that. We have no plan to deal with IOS ourselfs, but simply provide a platform that is capable.
     
  24. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# version 1.6.3 has been submitted to the asset store for review. This version includes:
    • Hot reloading will now parse the .csproj file generated by Unity and add reference assemblies automatically. This saves the process of identifying and adding lots of references to the settings window.
    • Added new option to the settings window 'Parse .csproj References' to enable or disable the above feature.
    • Added new API 'RoslynCSharp.Project' for parsing and analysing .csproj files via code (Read only)
    • Fixed a bug in the code security engine where using the 'Deny' behaviour as default for namespaces would cause user defined namespaces to also be flagged as violations.
    • Fixed a bug in the code security engine where generic types supplied as generic arguments to a method call could cause an unexpected empty security error to be reported.
    • Source code for 'RoslynCSharp.Compiler' is now included.
     
    Last edited: Jul 5, 2021
  25. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.4 has been submitted to the asset store. This version fixes an issue introduced in the last update where RoslynCSharp.Compiler could fail to compile due to missing dependencies when using netstandard. This hot fix will take a few days to be approved so if you need the update asap, feel free to contact us at info(at)trivialinteractive.co.uk with your invoice number, and we can send you the update direct.
     
  26. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.5 has been released on the asset store. This version includes:
    • Fixed an issue with editor asmdef which could cause standalone builds to fail.
    • Fixed an issue where calling dispose on a default ScriptDomain in the editor could cause the Unity editor to crash the next time play mode starts.
    • Fixed a bug where the compiler would generate pdb debug symbols with incorrect file extensions.
    • Added assembly processor system for patching assemblies immediately after compilation.
     
    Kamyker likes this.
  27. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    IL2CPP Update 5

    There has been a bit of a change in direction for this side project to support IL2CPP platforms via our CIL interpreter. Originally we planned to eventually release it as a paid add on for Roslyn C# once it was feature complete and stable enough for release. That plan has now changed though for a couple of reasons:
    • Development is not moving along fast enough for our liking due to other projects, work and asset support taking up a lot of our time. As a result, it would probably be many more months or possibly years before we have anything stable to release at the current rate.
    • There will always be some quite serious limitations/drawbacks to the interpreter due to the nature of the problem we are trying to solve. It does not feel quite right for us to offer a paid asset that has inherent limitations that require workarounds / nasty hacks to solve.
    • Community feedback / support. A number of users have requested source code access and also have supported us greatly by providing valuable bug reports, feedback and even sponsorship.
    With the above in mind, we have decided that the best course of action would be to make the project completely free and open source under the MIT license. This means that the community can actively use and contribute to the project, and hopefully it can grow into something really useful.
    We will still work on the project when we have chance, and thanks to sponsorship, we should be able to spend at least a few hours a week working on it.

    The project named 'dotnow' is available on github here. We welcome any contributions, or just feel free to use it in your project if it would be useful to you.

    The current state of the project is that most CIl instructions are implemented and work correctly, along with the necessary runtime framework. This means that most C# code will run just fine including arrays, collections, generics, user types, inheritance etc, although there are still bugs and issues with some features. You can find the demo snake game here running on purely runtime loaded code. The code for this demo is also in the repository, so feel free to check it out.

    We have also setup sponsorship over on github so that you can support the project if you would like to. Please do not feel compelled to sponsor the project if you use it. It is only there so that we can spend more time working on the project if we see a little bit of income from it.
     
    buzmez_simbt likes this.
  28. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.6 has been released on the asset store. This version includes a quick fix for integration with our IL2CPP dotnow interpreter and other potential add ons.
     
  29. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.7 has been released on the asset store. This version includes the following:
    • Fixed an issue where the compiler output would not be logged in non-debug builds due to conditional attributes. The compiler output will now be logged in release builds to avoid confusion.
    • Disable 'RolsynCSharpCompiler.loadCompiledAssemblies' by default to prevent issues with assembly patching, and to improve portability.
    • Debug symbols will now be loaded automatically if they are produced by the compiler ('Generate Symbols' = true).
    • Added a collection of methods 'LoadAssemblyWithSymbols' to support loading non-compiled assemblies with debug symbols so that the debugger can be attached.
    • Improved support for debugging compiled code.
     
  30. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.8 has been released on the asset store. This version includes:
    • Fixed a bug in the code security engine where generic types would not be resolved correctly in some cases.
    • Fixed a bug in the code security engine where types that exist inside a whitelisted namespace would be marked as illegal if the default type behaviour is set to deny, and the type is not explicitly listed.
    • Fixed a bug in the code security engine where members that exist inside a whitelisted type would be marked as illegal if the default member behaviour is set to deny, and the member is not explicitly listed.
     
  31. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.6.9 has been released on the asset store. This version adds support for regex in the code security restrictions to support matching of more complex names such as generic types. Simply enable the 'Use Regex Matching' option in the security settings to allow regex patters to be used for security entries.
     
    Kamyker likes this.
  32. MM47

    MM47

    Joined:
    Sep 7, 2012
    Posts:
    25
    Hi,
    I'm getting this error in webgl when running through the browser. Any ideas what this is about?

    Code (CSharp):
    1. Web.framework.js:2 ArgumentException: The specified assembly is not referencable because it's 'Location' property is empty. You will need to reference the assembly explicitly by filepath, filestream or assembly image data
    2.  at RoslynCSharp.Compiler.AssemblyReferenceFromAssemblyObject..ctor (System.Reflection.Assembly assembly) [0x00000] in <00000000000000000000000000000000>:0
     
  33. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    You will need to use assembly reference assets if you are not building for a desktop platform. The included example game makes use of assembly reference assets for adding compiler references, so you might like to take a look at that to see how they are used. I also posted a guide a while back for Android that might be useful to you (Android Guide). Pretty much all things mentioned there apply to WebGL too.
    You should also make sure that all assembly references added in the settings menu are removed too, as mentioned in the guide. This is most likely the cause of the error, since those references are added using paths by default, but that is only supported on desktop.

    I hope that help you. Let me know if you are still having issues.
     
    MM47 likes this.
  34. MM47

    MM47

    Joined:
    Sep 7, 2012
    Posts:
    25
    Thanks. I followed the guide and removed all assembly loading from code and from the settings.
    I also had to uncheck concurrent compile.
    Now I got this error when compiling the script:

    Code (CSharp):
    1. Web.framework.js:2 C:\Program Files\Unity\Hub\Editor\2020.3.14f1\Editor\Data\il2cpp\libil2cpp\icalls\mscorlib\System\AppDomain.cpp(181) : Unsupported internal call for IL2CPP:AppDomain::LoadAssemblyRaw - "This icall is not supported by il2cpp."
    My settings:

     
  35. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi again,
    Sorry, I didn't realize that you were not aware of the current IL2CPP state.
    Basically, loading code on IL2CPP platforms is not supported natively, since the code is compiled AOT. Roslyn C# relies on native loading, so that won't work as is and requires a different solution. This is just one reason why we only list PC, Mac and Linux as supported platforms using the mono backend.
    The good news is that it can be made to work with a bit of effort using an add on that we are currently developing in our spare time. You can use our dotnow interpreter over on github to run code on IL2CPP platforms. Be aware though, that there is no documentation, the system is in active development and there will be bugs, and there are some limitations.
    You can read more about the interpreter via our development posts: Update #1 - Update #2 - Update #3 - Update #4 - Update #5
     
    MM47 likes this.
  36. MM47

    MM47

    Joined:
    Sep 7, 2012
    Posts:
    25
    I was aware that there was an interpreter. I just thought it's integrated with the Roslyn asset. I remember it worked out of the box a few months ago? Anyway, thanks I'll try to integrate dotnow. Thank you!
     
  37. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Ahh I see. The interpreter was not integrated at any point since we were planning to sell it as an add-on at some point, so not sure what happened there. Perhaps you tested in the editor only, or it could possibly work in a build if you already included the code you were compiling in the project.
     
    MM47 likes this.
  38. Rytif

    Rytif

    Joined:
    Dec 28, 2012
    Posts:
    8
    I'm really interested in this asset, but I have a couple questions.

    Isn't this just importing the roslyn scripting libraries? We can call compile script during runtime, so what does this asset do differently? Security measures?

    I'm more interested in the Hot Reloading feature since Unity takes way too long to compile/kills productivity. So are you expecting a DLL to be generated from a class library that implements the modding interface? Class libs on .net core take about 4-5 seconds to build on a near empty project then compilation/loading within the game...doesn't seem too fast for hot reloading?

    Considering you can compile the scripts directly using roslyn which is nearly instant. So I guess I don't see the point?
     
  39. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Thanks for your interest in our asset.
    Yes, this asset is based on the Roslyn binaries, but it also offers a lot more on top of that. Here are some of the major features that we include in the asset:
    • Code security verification: A feature that scans all loaded code to check whether it uses potentially harmful Api's. Things like file access, reflection, p/invoke and more could be considered dangerous if you do not know where the source code originated from. Our system will check code at the IL level and simply not load anything that might be harmful. You have full control over blacklisting and whitelisting assemblies, namespaces, types and members.
    • A complete scripting reflection system to quickly and easily find types, call methods and much more. It supports constructing instances of any type (MonoBehaviour, ScriptableObject, normal C# instance) as well as many more useful features to make communication with unknown script types as easy as possible. You can also use normal C# reflection if needed.
    • Assembly Reference Assets. A nice feature that allows assembly references to be packaged as Unity assets for portability. It saves the compiler from searching for reference assemblies using paths which can cause issues on some platforms.
    • Editor hot reloading of scripts. A recent addition that adds support for hot reloading of scripts while in play mode (Editor only). It is a great feature to see script changes reflected in the game almost immediately, but has a few limitations mostly regarding debugging.
    As for compile times: I guess you are talking about compiling a project in IDE. Compilation at runtime is quite speedy actually with compile times often less than 1 second on the first run (The first run is always much slower as the actual compiler code gets jitted). I should also mention that those times include code security verification checks which is also quite a quick process. After that, we see hot reload times in editor that are around the 100ms mark, and often much lower. A very welcome improvement to Unity compilation times these days I would say. Basically save the script and by the time you have focused the Editor again, the changes are already loaded.

    That is some of the main features that our asset includes. There is also many more minor features and Api's that might be useful to you depending upon your use case, so I like to think we add a lot on top of the Roslyn foundation to justify the price of the asset.

    I hope that helps you. Let me know if you have any more questions or if there is anything else.
     
  40. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.7.0 has been released on the asset store. This version fixes an issue where code security checks using the deny default behavior could falsely report illegal access to other types defined in the same assembly using the global namespace.
     
  41. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Roslyn C# 1.7.1 has been released on the asset store. This version includes:
    • Fix an issue where the Roslyn C# settings window could sometimes cause issues when open during script compilation or domain reloads.
    • Fix a bug in code security checks where some type references could be allowed in some conditions when they are not whitelisted but the 'Deny' option is used as default behaviour.
    • Fix a bug in code security checks where some member references could be allowed in some conditions when they are not whitelisted but the 'Deny' option is used as default behaviour.
    • Assembly reference assets will now store the relative path to the referenced assembly if it exists within the 'Assets', 'Library' or 'Packages' folder so that they will continue to link correctly if the same project is used on multiple devices (Requires existing assembly reference assets to be updated manually).
     
  42. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    HOW TO: Getting the Roslyn C# maze crawler example running with dotnow on IL2CPP

    Hey all, I couldn't find this documented elsewhere all in one place, so here are the steps I did to get the maze crawler example running with dotnow on IL2CPP platforms:-

    1) Grab the latest dotnow-interpreter from git and open up the project in Unity.
    2) Import Roslyn C#.
    3) Switch the scripting backend to IL2CPP.
    4) Add ROSLYNCSHARP to the scripting define symbols in the project settings.
    5) Change CompileAndLoadMainSource to CompileAndLoadMainSourceInterpreted in MazeCrawlerExample.cs.
    6) Add a proxy class for the MazeCrawler class, like this:
    Code (CSharp):
    1. [dotnow.CLRProxyBinding(typeof(MazeCrawler))]
    2. public class MazeCrawlerProxy : MazeCrawler, dotnow.Interop.ICLRProxy
    3. {
    4.     dotnow.AppDomain domain;
    5.     dotnow.CLRInstance instance;
    6.     public void InitializeProxy(dotnow.AppDomain domain, dotnow.CLRInstance instance)
    7.     {
    8.         this.domain = domain;
    9.         this.instance = instance;
    10.     }
    11.  
    12.     System.Reflection.MethodInfo decideDirectionMethod = null;
    13.     public override MazeDirection DecideDirection(Vector2Int position, bool canMoveLeft, bool canMoveRight, bool canMoveUp, bool canMoveDown)
    14.     {
    15.         if(decideDirectionMethod == null)
    16.             decideDirectionMethod = instance.Type.GetMethod(nameof(DecideDirection), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.DeclaredOnly);
    17.        
    18.         return (MazeDirection)decideDirectionMethod.Invoke(instance, new object[]{ position, canMoveLeft, canMoveRight, canMoveUp, canMoveDown });
    19.     }
    20. }
    7) Remove all the default assembly references from the Roslyn C# compiler settings (to avoid errors caused by referencing assemblies by location).
    8) Add mscorlib to the maze crawler's list of assembly reference assets (as it's no longer in the default references).

    You should now be able to make a standalone IL2CPP build and the example should work properly. Hope this helps anyone else who gets stuck on this! Cheers.
     
  43. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Many thanks for posting this guide. I have linked to it from the main post to help out other users and have credited your user name. Hope that is Ok with you.
     
    danger726 likes this.
  44. WrapJared

    WrapJared

    Joined:
    Feb 3, 2021
    Posts:
    2
    I'm trying to play with dotnow in a project and I'm getting

    Multiple precompiled assemblies with the same name Mono.Cecil.dll included or the current platform. Only one assembly with the same name is allowed per platform. (Assets/dotnow/Plugin/Mono.Cecil.dll)​

    Multiple precompiled assemblies with the same name Mono.Cecil.dll included or the current platform. Only one assembly with the same name is allowed per platform. (MYPROJECT/Library/PackageCache/com.unity.nuget.mono-cecil@1.10.1/Mono.Cecil.dll)​

    I believe the second Mono.Cecil is installed because of Burst, which is required by MLAPI (Network for GameObjects). When I remove the dotnow/Plugin/Mono.Cecil.dll, delete Library/PackageCache, Library/ScriptAssemblies, and restart the editor I still get plenty of script errors that I'm unable to fix. Such as

    Assets\dotnow\Scripts\Core\Reflection\CLRMethodBody.cs(7,35): error CS0433: The type 'MethodBody' exists in both 'Mono.Cecil, Version=0.10.0.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e' and 'Unity.Burst.Cecil, Version=0.10.0.0, Culture=neutral, PublicKeyToken=fc15b93552389f74'
    Any advice on how to proceed?
     
    Last edited: May 11, 2022
  45. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    We have come across similar issues with other plugins like 'Newtonsoft.Json' when working with Unity, and it is always a pain to sort out. I guess burst is using a different version of Mono.Cecil with breaking changes, and it is not possible to have multiple versions of the same assembly because Unity does not support strong named assemblies.
    I would have to look into it when I have chance, but my first thought would be to try importing the source for Mono.Cecil since it is available on github. I would make sure that it is imported in a dotnow subfolder so that it is covered under the dotnow asmdef, and I think the compiler should then be able to automatically reference the source file version of Mono.Cecil, and it will be compiled into the dotnow assembly to rule out any conflict. I hope that make sense. I am not sure if it will solve the problem, or simply create new problems but that is the only way I can think at the moment without requiring major changes to the code base.
    I might have some free time tomorrow to try it out on my end and try to find a solution, but for not I think that is the best I can think of without trying it out. Let me know if you do try that approach and how you get on, and maybe I can add some documentation/notes to the wiki about this issue.
     
  46. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,090
    I don't know if dotnow has asmdef but if it does check Override references and add one assembly reference.
     
  47. WrapJared

    WrapJared

    Joined:
    Feb 3, 2021
    Posts:
    2
    I was able to get it working by importing Mono.Cecil and changing the namespace to Dotnow.Mono.Cecil. I'm just messing around so that'll do for now. Thanks for pointing me in the right direction.
     
    scottyboy805 likes this.
  48. stfunity

    stfunity

    Joined:
    Sep 9, 2018
    Posts:
    65
    I'm trying to build a backend DLL that goes into a Unity environment and I'm having an issue trying to reference netstandard. I can add
    using RoslynCSharp; using RoslynCSharp.Compiler;
    to my .cs scripts and I've got the Unity-compiled Library DLLs for Roslyn referenced in my Visual Studio Solution file, but when I try to run a command out of the ScriptDomain dot syntax it tells me:

    upload_2022-7-6_22-16-45.png

    I can't seem to get the reference right in either Unity or VSCode. If I go to the Unity Settings to add a path to the library it crashes immediately on any attempt to Edit the assembly references:
    upload_2022-7-6_22-17-40.png
    I cannot add to these, and if I delete or even cancel on add, it still crashes Unity immediately either way.
    So I can delete references from this list and get a crash, or fail to add one and get a crash. Then I have to reimport if I want to restore the references.

    I am not at a stage where I can use the scriptable objects yet because this is the back end project. Need to include the reference another way.

    If I take the below netstandard path and try to add it as a referenced DLL in my ClassLibrary solution, it basically breaks all of the System default types like bool int string etc., hundreds and hundreds of undefined type errors everywhere:
    upload_2022-7-6_22-19-10.png
    upload_2022-7-6_22-20-15.png

    And then this is the error I get:
    upload_2022-7-6_22-20-32.png

    Curiously, if I set the Properties of netstandard "Embed Interop Types" to True, then I get less errors, but still hundreds of them.

    I don't know what to do with this situation really.

    In the interest of time for my company I will probably put a bounty up on this. We want to go with Roslyn so we stay compatible going forward so this is the compiler for us, unless there's some insurmountable roadblock to the way this is packaged.
     
    Last edited: Jul 7, 2022
  49. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Not sure what the issue is here but adding assembly references via the Library/ScriptAssemblies has always worked just fine for me. From the error messages you are getting though it looks like it could possibly be incompatible project types. In your Unity project, which scripting backend are you using: Net Framework or NetStandard? Did you use the matching framework when creating your own standalone C# project? Anther thing you could try if you are targeting NetStandard is recreating your C# project targeting Net Framework, as this is what we do with some of our own products for best compatibility. It will still work just fine NetStandard and NetFramework, and could hopefully solve the compiler reference errors you are getting. If you are still having trouble let me know which Unity version you are using and I can see if I can setup a working standalone C# project referencing Roslyn C#.
     
  50. stfunity

    stfunity

    Joined:
    Sep 9, 2018
    Posts:
    65
    Thanks. I am now able to call

    scriptDomain = ScriptDomain.CreateDomain("RoslynCS", initCompiler, true, null);
    , wasn't able to before.

    Although my Unity Project's involvement in the Core DLL build is minimal, it does compile the Roslyn projects into assemblies. It was on Framework but I switched it to netstandard and then back to framework to force a recompile. Then I went and doubletriplequadruplequintuple-checked my Class Library's target type and it was at Framework 4.8 but didn't work last night, set it to 4.5 and went to bed. Woke up to your reply and set it back to 4.8 just to force some kind of re-evaluation. It worked? Somewhere in there.

    One thing I noticed is that even with all the Roslyn csprojs imported to my solution AND the built Roslyn DLLs referenced in my output class library section, I would get an unresolved yellow error on UnityEditor and UnityEngine.UI references in the Roslyn projects.

    -- BUT -- Not if I open the Roslyn csproj directly and let VS2022 automatically load my solution. Not sure why opening the governing SLN itself wouldn't catch those references considering they work in each individual .csproj

    Having just opened my SLN indirectly through the RoslynCSharp.csproj, all the types and references are resolving correctly now.

     
    scottyboy805 likes this.