Utiliser le compilateur Roslyn C# dans Unity
Dans ce tutoriel nous allons voir le principe "d'installation" du compilateur Roslyn (quelques éléments) dans Unity ainsi qu'un exemple d’évaluation d’un code C# avec la classe CSharpScript.
Nous ne verrons pas en ultra détail comment récupérer tous les .dll (processus long et fastidieux). Mais nous allons tout de même voir le principe ! En vous armant de motivation et de patience vous finirez tout de même par y arriver.
Pré-requis:
- Avoir SDK .NET Core (arrive avec CLI Tool)
- Au moins un projet “raw” C# (et pas Unity) initié pour récupérer les dll
Roslyn compiler c’est quoi ?
Et bien comme son nom l'indique c'est ce qui permet de compiler le code C# que vous écrivez, en langage compréhensible par la machine. Mais sous cette simple phrase se cache tout un tas d'étapes, comprenant des vérifications (analyse) entre autres de la justesse du code C# à compiler .. c'est sur cet aspect que nous allons nous attarder aujourd'hui.
En réalité son nom réel est le .NET Compiler Platform, et Roslyn c'est son surnom . C'est un ensemble open-source de compilateurs and d'analyseurs de code pour C#, VBasic
Roslyn est déjà embarqué sous Unity, mais on a pas la main dessus. Bien que sur la version 2020.2 de Unity (cf blog ), ils aient annoncé qu’on pouvait utiliser l’analyser , ce n'est pas ce que nous allons utiliser ici, car cela ne correspond pas à nos besoins.
Ici on va pouvoir compiler, plus exactement “évaluer” au runtime, directement dans notre application. L'intérêt d’avoir la main sur le compilateur, et de l’embarquer dans l’application, c’est que l’on va pouvoir évaluer, la qualité d’un code, sa justesse (erreur de parsing par exemple)... tout en ayant lancé l'application !
Bref ici nous allons voir comment exécuter du code C# au runtime.
Setup sous Unity
Principe de récupération des dll pour pouvoir utiliser la classe CSharpScript, et sa méthode EvaluateAsync().
Sachez qu'il n'est pas possible d'installer le package Nuget directement dans un projet Unity. On va donc devoir ruser et passer d'abord par un projet "raw" C# ...
=> Installer la package Nuget dans le projet “raw” C#
dotnet add package Microsoft.CodeAnalysis.CSharp.Scripting --version 3.8.0
=> récupérer les dll indiqués sur la photo ci-dessous, et placez les dans l'éditeur de Unity. A cette étape il va vous falloir fouiller un peu votre ordinateur . Catch 'em All !
=> déposer les dll dans Unity, sous Asset/Plugins (créer le dossier Plugin si ce dernier n’existe pas encore dans votre projet).
Évaluer au runtime un script C# dans Unity
Maintenant que les fichiers .dll sont dans Unity et bien chargés, on va pouvoir réaliser notre premier test.
Créez une scène vide, un nouveau GameObject que vous nommez comme vous voulez, ainsi qu’un nouveau script C# que l’on nommera RoslynConcept.cs.
Donnez le script à votre nouveau GameObject, et passez en édition du script, sous VSCode par exemple.
Dans ce script on va créer un méthode qui va permettre d'évaluer justement le code qu'on va lui fournir (sous forme de string)
public void execute(string codeToEvaluate)
{
try
{
var result = CSharpScript.EvaluateAsync(codeToEvaluate).GetAwaiter().GetResult();
Debug.Log("Result => " + codeToCompile);
Debug.Log(result);
}
catch (Exception e)
{
Debug.LogWarning("ERROR : " + e);
}
}
Notez le try/catch permettant d'éviter de faire crasher le programme ! Puis la seule instruction vraiment nouvelle ici, c'est celle concernant l'utilisation de la méthode EvaluateAsync. Comme à priori nous ne connaissons pas le type (int, bool ...) de retour final de la valeur qui sera stockée dans la variable result, nous utilisons var.
var result
La méthode est asynchrone et elle renvoie un objet de type Task. Nous récupérons ensuite l'awaiter , puis le résultat direct:
CSharpScript.EvaluateAsync(codeToEvaluate).GetAwaiter().GetResult();
Il suffit alors d'utiliser le contenu de la variable result pour continuer ...
Debug.Log(result);
using Microsoft.CodeAnalysis.CSharp.Scripting;//for evaluate
Et c'est tout ! Il suffit maintenant de prévoir une variable qui contiendra du code c# en string pour le donner à votre méthode lors de l'appel.
//dans la méthode start par exemple
string code = "int x=4;int y=2; return x+y;";
execute(code);
Si une une erreur est présente dans le code fourni, nous saurons exactement ce qu'il ne va pas. Et si le code est bon, il sera exécuté, et le résultat renvoyé (cf Debug.Log)!
Une démo vidéo d'utilisation de Roslyn dans Unity
Ainsi vous avez vu un tout premier exemple de l’utilisation du Roslyn Compiler. On peut bien sûr aller encore plus loin et coupler cela avec une interface (IHM) afin de pouvoir éditer le code soumis plus facilement et surtout dynamiquement.
N’oubliez pas la sécurité ! En effet en laissant au runtime la possibilité d'exécuter du code c'est dangereux ... si vous comptez utiliser ce principe dans une application, prévoyez d'interdire des méthodes, voir carrément des classes complètes !
Retrouvez quelques Assets très aboutis mais payants sur l'Asset Store qui permettent d'exécuter du code au runtime: