[Released] Roslyn C# - Runtime C# compiler

4364407--395152--FeatureTrimmed.png

Asset Store | Documentation | Discord

Roslyn C# allows runtime loading of assemblies and C# scripts using the Roslyn compiler making it easy to add modding support or in-game programming to your project. In addition, Roslyn C# also includes code security verification that allows you to specify a number of security restrictions that loaded code must adhere to including illegal namespaces and types. This makes it much safer to load 3rd party code from unknown sources.

Features

  • Compile and run C# scripts at runtime
  • Leverage the latest C# language features using the Roslyn C# compiler
  • Fast execution. Once compiled, external scripts will run as fast as game scripts
  • Allows modding support to be added easily
  • Code security validation means that unsafe code can be identified and discarded
  • Code security generates a detailed report upon failure containing information about illegal types used and every usage occurrence in the external code
  • Simple and easy to use API for assembly, type and instance reflection
  • Support for non-concrete communication using script proxies
  • Automatic type construction using correct method (AddComponent, CreateInstance, new)
  • Cached member tables for quick reflection
  • All scripts and example are organised into namespaces to avoid type name clashes
  • Fully commented partial C# source code included
  • Comprehensive .chm documentation of the API for quick and easy reference

Limitations

  • Requires .Net 4.x API compatibility level
  • AOT platforms such as IOS are not supported
  • IL2CPP builds will fail to execute at the moment - Read on for possible solution (dotnow-interpreter).

PC, Mac and Linux platforms are supported

Demo

Includes a small programming based game where the objective is to navigate a mouse out of a maze by writing code that performs the direction decision making. The code is written in game using the UI code editor and then compiled and executed to see how it performs.

4364407--395155--Screenshot1.png

This example game demonstrates some of the compiler API's available as well as the script communication methods that Roslyn C# offers and it is also quite a fun challenge to try and create a simple AI that can reach the end of the maze consistently. All the code for this game is included in 2 fully commented C# scripts so you can clearly understand how it works.

Need an code editor for your game?
4364407--417205--FeatureTrimmed.png
Check out our other asset asset 'InGame Code Editor' which is an advanced text input field with line numbering and fully customizable syntax highlighting for C# and many other languages. Check out the asset store or forum page for more info.

Roslyn C# + dotnow IL2CPP Interpreter Setup Guide (09/2022)

There is a new setup guide available to get Roslyn C# working with dotnow interpreter to run the Roslyn C# demo game on IL2CPP platforms such as WebGL. You can find the setup guide on the github wiki. Thanks to Dustin_00 for creating this guide.

IL2CPP Update(08/2021)

Introducing the dotnow CIL interpreter that is designed to load and execute CIL bytecode at runtime on IL2CPP platforms. CIL bytecode is the language that your pure C# source code gets compiled into, and our interpreter provides a runtime environment that is able to run managed code on any platform. The interpreter is written in pure C#, hence the portability, and supports arrays, collections, generics, delegates and more. It is designed to replicate the .net runtime entirely although it does have some limitations.

dotnow is open source on github under the MIT license. Feel free to try it out in your projects to get code running on IL2CPP platforms (Note that it only works with Assembly Definition assets at the moment, and code stripping is a know issue). It is currently in active development, but is mostly feature complete as far as the runtime goes. This means that most code samples should execute just fine as is, although some code might throw up issues. We have also implemented full Roslyn C# integration to make it as easy as possible to use.

Development updates: Update #1 - Update #2 - Update #3 - Update #4 - Update #5

Android Update (02/2021)

We have created a mini guide for getting Roslyn C# to run on Android platforms. Android is still not an officially supported platform, but many users have had success following the steps outlined here.

IL2CPP Update (11/2020)

We now have a working proof of concept WebGL demo where you can compile and execute C# source code in a game built with IL2CPP. Read more here.

Roslyn C# and dotnow integration (IL2CPP platform support)

Check out this guide to setup Roslyn C# and dotnow so that the maze crawler demo and other compiled code can run on IL2CPP platforms including WebGL and Android. Many thanks to danger726 for putting this guide together

4364407--395149--UserGuide.pdf (753 KB)

7 Likes

Roslyn C# is now available on the Asset Store!

1 Like

Purchased! Looks great

[quote=“pauliusuza”, post:3, topic: 737225]
Purchased! Looks great
[/quote]

Thanks for purchasing. Let me know if you do anything cool with it :slight_smile:

We are not giving up on Web GL and IL2CPP builds yet. We can see no theoretical reason (Apart from the build error we are receiving) that Roslyn C# cannot run under IL2CPP and not only that but WebGL as well. We have reported the IL2CPP build error we are receiving to the Unity team and will keep you posted with any updates.

1 Like

Small update on IL2CPP support. The Unity QA team have reproduced the bug that is causing IL2CPP builds using Roslyn C# to fail so hopefully once fixed we can try once again to support IL2CPP and webGL. That does not mean we will not have any more issues building for IL2CPP after this bug is fixed but it will be a step in the right direction. Here is the bug causing us problems on the issue tracker.

2 Likes

Roslyn C# version 1.0.1 has been submitted to the asset store for review and should be available for download within a couple of days. This version adds whitelist support to the security restrictions so you can now list references, namespace and types which are allowed instead of listing all restrictions.

2 Likes

Hey quick question, I bought your asset and came across something I'm too stupid to fix.

Say I have an external class called A and another external class called B.

If I try to have A contain a variable of type B, a bunch of exceptions will pop up, so I guess external classes don't know anything about each other. How would you tackle this? In my case, I have a class Actor and a class Attribute, and i just want the Actor to have a variable of type Attribute but that's when shit gets crazy.

Thanks!!

[quote=“lThanatosl”, post:8, topic: 737225]
Hey quick question, I bought your asset and came across something I’m too stupid to fix.

Say I have an external class called A and another external class called B.

If I try to have A contain a variable of type B, a bunch of exceptions will pop up, so I guess external classes don’t know anything about each other. How would you tackle this? In my case, I have a class Actor and a class Attribute, and i just want the Actor to have a variable of type Attribute but that’s when S*** gets crazy.

Thanks!!
[/quote]

Hi,
Are these external classes compiled separately? If so you should be receiving compiler errors about undefined types? Is that correct. If this is the case the you will need to add an assembly reference to the assembly that type B is defined in before compiling type A. Here is a shot example:

using RoslynCSharp;
using UnityEngine;

class Example : MonoBehaviour
{
    void Start()
    {
        ScriptDomain domain = ScriptDomain.CreateDomain("Example", true);
     
        // Compile source for type B
        ScriptAssembly asm = domain.CompileAndLoadFile("insert type B source file");
     
        // Add an assembly reference
        domain.RoslynCompilerService.ReferenceAssemblies.Add(asm.RawAssembly);
     
        // Compile source for type A which should now allow access to types defined in source B
        domain.CompileAndLoadFile("insert type A source file");
    }
}

This should allow you to use types defined in source B from source A.

Oh I see, my design is basically the following:

  • Visual Studio Project: Contains classes that will be turned into the game's DLL. Basically has the absolute bare minimum the game is expected to have.
  • Unity Project (Mod creator): Uses the game's DLL and creates a folder of all the external scripts (the mod). Used to further enhance and create new functionality.
  • Unity Project (Main game): Uses the game's DLL, contains code such as System.IO, etc. Reads the external scripts from a mod by compiling them with your asset.

The Main game project goes through all the scripts in a particular folder and compiles them like this (https://i.imgur.com/izX2dXc.png) Which is basically only good enough for the script to be placed in the scene attached to the given gameObject, and so its Start/Update/etc funcs are called. But yeah my issue is that doing this isn't enough for the script to know about other scripts.

It seems like the solution you proposed will bring issues though, because the main game is what compiles the external code and the user will not be able to simply decide what gets compiled before what since they cant change that code.

I was thinking maybe I need to compile all the external code into a DLL and have the main game load in 2 DLLs instead of 1, so 1 DLL done by me, and 1 DLL which contains the mod. The issue with this is that I wanted to keep mod code visible to others, but now it will be hidden behind the DLL unless a mod author decides to release not only the DLL but also the source, which just adds extra steps.

Awesome asset btw!

[quote=“lThanatosl”, post:10, topic: 737225]
Oh I see, my design is basically the following:

  • Visual Studio Project: Contains classes that will be turned into the game’s DLL. Basically has the absolute bare minimum the game is expected to have.
  • Unity Project (Mod creator): Uses the game’s DLL and creates a folder of all the external scripts (the mod). Used to further enhance and create new functionality.
  • Unity Project (Main game): Uses the game’s DLL, contains code such as System.IO, etc. Reads the external scripts from a mod by compiling them with your asset.

The Main game project goes through all the scripts in a particular folder and compiles them like this (https://i.imgur.com/izX2dXc.png) Which is basically only good enough for the script to be placed in the scene attached to the given gameObject, and so its Start/Update/etc funcs are called. But yeah my issue is that doing this isn’t enough for the script to know about other scripts.

It seems like the solution you proposed will bring issues though, because the main game is what compiles the external code and the user will not be able to simply decide what gets compiled before what since they cant change that code.

I was thinking maybe I need to compile all the external code into a DLL and have the main game load in 2 DLLs instead of 1, so 1 DLL done by me, and 1 DLL which contains the mod. The issue with this is that I wanted to keep mod code visible to others, but now it will be hidden behind the DLL unless a mod author decides to release not only the DLL but also the source, which just adds extra steps.

Awesome asset btw!
[/quote]

Would it be possible for you to compile all of the mod scripts in the folder together. Roslyn C# supports compiling batches of source files which then act as though you are compiling a C# project in visual studio. Ie all the source files belong to the same assembly and as a result can communicate normally. If this is what you are looking for then you just need to use the overload of ‘CompileAndLoadSources’ or ‘CompileAndLoadFiles’ which accepts a string array. I may have had the wrong idea as I assumed that you wanted to compile the files individually.

Oh that sounds sweet I'll look into that. No no I do all the loading of all the scripts at once, Basically I go through the mod's folder and all its subfolders and get all the scripts onto a list, and then i loaded each one the way i showed on the picture, but if the function that you mentioned allows them to know about each other then my problems would go away.

I'll get started right away, thanks!!

[quote=“lThanatosl”, post:12, topic: 737225]
Oh that sounds sweet I’ll look into that. No no I do all the loading of all the scripts at once, Basically I go through the mod’s folder and all its subfolders and get all the scripts onto a list, and then i loaded each one the way i showed on the picture, but if the function that you mentioned allows them to know about each other then my problems would go away.

I’ll get started right away, thanks!!
[/quote]

Yest that would be the easiest and probably the least time consuming way of doing it. You will then need to change your loading code to something like this to process all types in the assembly instead of just the main type:

void CompileFiles(ScriptDomain domain, GameObject go, string[] filePaths)
{
    ScriptAssembly asm = domain.CompileAndLoadFiles(filePaths);

    foreach(ScriptType type in asm.EnumerateAllMonoBehaviourTypes())
        type.CreateInstance(go);
}

Good news! It worked like a charm!

I decided to do something like this though (https://i.imgur.com/moAGnV4.png)

Basically every external script can implement the static function OnScriptLoad, so that the user can decide what to do when the script is loaded. Maybe the mod creator wants the script to be attached to a gameObject, maybe not, so I'll let them decide.

Thanks a lot for the help!

1 Like

[quote=“lThanatosl”, post:14, topic: 737225]
Good news! It worked like a charm!

I decided to do something like this though (https://i.imgur.com/moAGnV4.png)

Basically every external script can implement the static function OnScriptLoad, so that the user can decide what to do when the script is loaded. Maybe the mod creator wants the script to be attached to a gameObject, maybe not, so I’ll let them decide.

Thanks a lot for the help!
[/quote]

Glad to hear you got it working. Yes you can choose whatever works best for you. I was only showing how you can assess all types in the assembly rather than the main type :). Let me know if you need anything else.

Hi,

I use Roslyn C# with Unity to run a script added as a Component to a GameObject.
It works fine when running into the Editor.
But it doesn't works when running outside the Editor as build.
Is there a build setting to do or some dll to add ?

Thanks.

[quote=“albor63”, post:16, topic: 737225]
Hi,

I use Roslyn C# with Unity to run a script added as a Component to a GameObject.
It works fine when running into the Editor.
But it doesn’t works when running outside the Editor as build.
Is there a build setting to do or some dll to add ?

Thanks.
[/quote]

Hi,
No there is nothing special you need to do for a build. Can you try a debug build to see if you are getting any exceptions or anything. Also I assume you are running on Windows, Mac or Linux.

Hi Sorry, it's an error on my part.
The file containing the script was not found at runtime.
All works fine. It's a real pleasure.

1 Like

[quote=“albor63”, post:18, topic: 737225]
Hi Sorry, it’s an error on my part.
The file containing the script was not found at runtime.
All works fine. It’s a real pleasure.
[/quote]

Glad to hear that you got it working. Let me know if you have any more issues or questions.

Isn't this just the same as Dynamic C# which I have..why is this not just an update?