Ich habe das nicht selbst gemacht, daher basiert diese Antwort auf einem Artikel von exodrifter ( ich habe gerade "Unity Runtime Compile" gegoogelt und ganz oben 4 Antworten gefunden, also versäume nicht, dich selbst zu suchen!)
Was Sie beschreiben, ist möglich, aber nicht ohne Fallstricke:
Verwenden Sie die .NET 2.0-Kompatibilitätsstufe. Andernfalls fehlen möglicherweise einige von Ihnen benötigte Namespaces.
Nicht auf jeder Plattform können Sie zur Laufzeit neues C # aus Zeichenfolgen kompilieren - insbesondere Android und iOS verbieten dies.
Standardmäßig funktioniert dies unter Windows, jedoch nicht unter Macs / Linux, es sei denn, der Benutzer hat das Mono SDK installiert. Sie können den mcs-ICodeCompiler von aeroson einbinden , um diese Funktionalität als Plugin in Ihr Spiel zu integrieren.
Beispielcode des Exodrifters (geändert, um eine Komponente hinzuzufügen)
(Ausführliche Informationen finden Sie im Artikel. Ich möchte hier nur so viel aufnehmen, dass diese Antwort ein nützlicher Wegweiser ist, auch wenn der verlinkte Artikel ausfällt.)
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
using UnityEngine;
public class RuntimeCompileTest : MonoBehaviour
{
void Start()
{
var assembly = Compile(@"
using UnityEngine;
public class RuntimeCompiled : MonoBehaviour
{
public static RuntimeCompiled AddYourselfTo(GameObject host)
{
return host.AddComponent<RuntimeCompiled>();
}
void Start()
{
Debug.Log(""The runtime compiled component was successfully attached to"" + gameObject.name);
}
}");
var runtimeType = assembly.GetType("RuntimeCompiled");
var method = runtimeType.GetMethod("AddYourselfTo");
var del = (Func<GameObject, MonoBehaviour>)
Delegate.CreateDelegate(
typeof(Func<GameObject, MonoBehaviour>),
method
);
// We ask the compiled method to add its component to this.gameObject
var addedComponent = del.Invoke(gameObject);
// The delegate pre-bakes the reflection, so repeated calls don't
// cost us every time, as long as we keep re-using the delegate.
}
public static Assembly Compile(string source)
{
// Replace this Compiler.CSharpCodeProvider wth aeroson's version
// if you're targeting non-Windows platforms:
var provider = new CSharpCodeProvider();
var param = new CompilerParameters();
// Add ALL of the assembly references
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
param.ReferencedAssemblies.Add(assembly.Location);
}
// Or, uncomment just the assemblies you need...
// System namespace for common types like collections.
//param.ReferencedAssemblies.Add("System.dll");
// This contains methods from the Unity namespaces:
//param.ReferencedAssemblies.Add("UnityEngines.dll");
// This assembly contains runtime C# code from your Assets folders:
// (If you're using editor scripts, they may be in another assembly)
//param.ReferencedAssemblies.Add("CSharp.dll");
// Generate a dll in memory
param.GenerateExecutable = false;
param.GenerateInMemory = true;
// Compile the source
var result = provider.CompileAssemblyFromSource(param, source);
if (result.Errors.Count > 0) {
var msg = new StringBuilder();
foreach (CompilerError error in result.Errors) {
msg.AppendFormat("Error ({0}): {1}\n",
error.ErrorNumber, error.ErrorText);
}
throw new Exception(msg.ToString());
}
// Return the assembly
return result.CompiledAssembly;
}
}
Warnung
Seien Sie sehr vorsichtig, wenn Sie Ihr Spiel Skripte kompilieren und ausführen lassen, die Sie nicht selbst geschrieben haben. Diese Skripte können fast alles tun, wozu das Benutzerkonto des Players berechtigt ist - Benutzerdateien löschen oder beschädigen, Malware herunterladen und ausführen, persönliche Informationen abrufen, all das.
So sehr wir auch versuchen mögen, diese Fälle zu blockieren und zu erkennen, ich wäre nie besonders sicher, dass wir sie alle abgefangen haben - es besteht immer die Möglichkeit, dass eine C # -Sprachenfunktion, von der ich nichts wusste, ihnen den Zugriff auf Funktionen ermöglicht, von denen ich dachte, dass sie abgeschnitten sind .
Wenn das Skript nur vom lokalen Spieler erstellt wird, können sie das Spiel auf willkürliche Weise unterbrechen, aber nichts mit ihrem Computer tun, für das sie ohnehin keine Berechtigung hatten. Wenn Spieler jedoch Skripte freigeben, von einer Netzwerkressource herunterladen oder dazu verleitet werden können, ein nicht geschriebenes Skript zu kopieren und einzufügen, wird dies zu einem Angriffsvektor, der ausgenutzt werden kann.
Wenn Sie die Programmierung durch den Player zulassen möchten, ohne diese Art von Sicherheitsanfälligkeit zu öffnen, sollten Sie eine eigene virtuelle Maschine schreiben, um die Skripte des Players in einer eingeschränkteren Umgebung zu analysieren, zu interpretieren und auszuführen, die Sie vollständig steuern.