Frage

Ich habe ein kleines Spiel in C# geschrieben.Es verwendet eine Datenbank als Backend.Es ist ein Sammelkartenspiel, und ich wollte die Funktion der Karten als Skript umsetzen.

Was ich meine ist, dass ich im Wesentlichen eine Schnittstelle habe, ICard, was eine Kartenklasse implementiert (public class Card056: ICard) und die eine Funktion enthält, die vom Spiel aufgerufen wird.

Um das Ding nun wartbar/veränderbar zu machen, möchte ich die Klasse für jede Karte als Quellcode in der Datenbank haben und sie im Wesentlichen bei der ersten Verwendung kompilieren.Wenn ich also eine Karte hinzufügen/ändern muss, füge ich sie einfach zur Datenbank hinzu und sage meiner Anwendung, dass sie aktualisiert werden soll, ohne dass eine Assembly-Bereitstellung erforderlich ist (insbesondere, da wir über eine Assembly pro Karte sprechen würden, was Hunderte von Assemblys bedeutet). .

Ist das möglich?Registrieren Sie eine Klasse aus einer Quelldatei und instanziieren Sie sie dann usw.

ICard Cards[current] = new MyGame.CardLibrary.Card056();
Cards[current].OnEnterPlay(ref currentGameState);

Die Sprache ist C#, aber ein zusätzlicher Bonus ist, wenn es möglich ist, das Skript in einer beliebigen .NET-Sprache zu schreiben.

War es hilfreich?

Lösung

Oleg Shilos C#-Skriptlösung (bei The Code Project) ist wirklich eine großartige Einführung in die Bereitstellung von Skriptfunktionen in Ihrer Anwendung.

Ein anderer Ansatz wäre, eine Sprache in Betracht zu ziehen, die speziell für die Skripterstellung entwickelt wurde, wie z IronRuby, IronPython, oder Lua.

IronPython und IronRuby sind beide ab sofort verfügbar.

Eine Anleitung zum Einbetten von IronPython finden Sie hierSo betten Sie die IronPython-Skriptunterstützung in 10 einfachen Schritten in Ihre bestehende App ein.

Lua ist eine Skriptsprache, die häufig in Spielen verwendet wird.Es gibt einen Lua-Compiler für .NET, erhältlich bei CodePlex – http://www.codeplex.com/Nua

Diese Codebasis ist eine großartige Lektüre, wenn Sie mehr über die Erstellung eines Compilers in .NET erfahren möchten.

Ein ganz anderer Blickwinkel ist es, es auszuprobieren Power Shell.Es gibt zahlreiche Beispiele für die Einbettung von PowerShell in eine Anwendung – hier ist ein ausführliches Projekt zu diesem Thema:Powershell-Tunnel

Andere Tipps

Möglicherweise können Sie dafür IronRuby verwenden.

Ansonsten würde ich vorschlagen, dass Sie ein Verzeichnis haben, in dem Sie vorkompilierte Assemblys ablegen.Dann könnten Sie in der Datenbank einen Verweis auf die Assembly und die Klasse haben und Reflektion verwenden, um die richtigen Assemblys zur Laufzeit zu laden.

Wenn Sie wirklich zur Laufzeit kompilieren möchten, können Sie CodeDOM verwenden und anschließend die dynamische Assembly mithilfe von Reflection laden. Microsoft-Dokumentationsartikel, der hilfreich sein könnte.

Wenn Sie das DLR nicht nutzen möchten, können Sie dies tun Verwenden Sie Boo (das einen Dolmetscher hat) oder Sie könnten darüber nachdenken das Script.NET (S#)-Projekt auf CodePlex.Mit der Boo-Lösung können Sie zwischen kompilierten Skripten oder der Verwendung des Interpreters wählen, und Boo erstellt eine schöne Skriptsprache, verfügt über eine flexible Syntax und eine erweiterbare Sprache durch seine offene Compiler-Architektur.Script.NET sieht jedoch auch gut aus und Sie können diese Sprache problemlos erweitern. Außerdem ist es ein Open-Source-Projekt und verwendet einen sehr benutzerfreundlichen Compiler-Generator (Irony.net).

Sie können jede der DLR-Sprachen verwenden, mit denen Sie ganz einfach Ihre eigene Skriptplattform hosten können.Allerdings müssen Sie hierfür keine Skriptsprache verwenden.Sie könnten C# verwenden und es mit dem C#-Codeanbieter kompilieren.Solange Sie es in einer eigenen AppDomain laden, können Sie es nach Herzenslust laden und entladen.

Ich würde vorschlagen, es zu verwenden LuaSchnittstelle Da es Lua vollständig implementiert hat, scheint Nua nicht vollständig zu sein und wahrscheinlich einige sehr nützliche Funktionen (Coroutinen usw.) nicht zu implementieren.

Wenn Sie einige der außerhalb vorgefertigten Lua-Module verwenden möchten, würde ich vorschlagen, etwas in der Art von 1.5.x zu verwenden, im Gegensatz zur 2.x-Serie, die vollständig verwalteten Code erstellt und die erforderliche C-API nicht verfügbar machen kann.

Ich verwende LuaInterface1.3 + Lua 5.0 für eine NET 1.1-Anwendung.

Das Problem mit Boo besteht darin, dass jedes Mal, wenn Sie Ihren Code im laufenden Betrieb analysieren/kompilieren/auswerten, eine Reihe von Boo-Klassen erstellt werden, sodass es zu Speicherverlusten kommt.

Lua hingegen macht das nicht, daher ist es sehr, sehr stabil und funktioniert wunderbar (ich kann Objekte von C# an Lua und zurück übergeben).

Bisher habe ich es noch nicht in PROD eingebunden, aber es scheint sehr vielversprechend zu sein.

Ich hatte in PROD mit LuaInterface + Lua 5.0 Probleme mit Speicherlecks, daher habe ich Lua 5.2 verwendet und mit DllImport direkt in C# verknüpft. Die Speicherlecks befanden sich innerhalb der LuaInterface-Bibliothek.

Lua 5.2:aus http://luabinaries.sourceforge.net Und http://sourceforge.net/projects/luabinaries/files/5.2/Windows%20Libraries/Dynamic/lua-5.2_Win32_dll7_lib.zip/download

Nachdem ich dies getan hatte, waren alle meine Speicherlecks verschwunden und die Anwendung lief sehr stabil.

Die Hauptanwendung, die meine Abteilung verkauft, hat eine ganz ähnliche Funktion, nämlich Kundenanpassungen bereitzustellen (was bedeutet, dass ich keine Quelle veröffentlichen kann).Wir haben eine C#-Anwendung, die dynamische VB.NET-Skripte lädt (obwohl jede .NET-Sprache problemlos unterstützt werden könnte – VB wurde ausgewählt, weil das Anpassungsteam einen ASP-Hintergrund hatte).

Mit CodeDom von .NET kompilieren wir die Skripte aus der Datenbank unter Verwendung der VB CodeDomProvider (Ärgerlicherweise ist die Standardeinstellung .NET 2. Wenn Sie 3.5-Funktionen unterstützen möchten, müssen Sie ein Wörterbuch mit „CompilerVersion“ = „v3.5“ an seinen Konstruktor übergeben.)Benutzen Sie die CodeDomProvider.CompileAssemblyFromSource Methode, um es zu kompilieren (Sie können Einstellungen übergeben, um zu erzwingen, dass es nur im Speicher kompiliert wird.

Dies würde zu Hunderten von Assemblys im Speicher führen, aber Sie könnten den gesamten Code der dynamischen Klassen in einer einzigen Assembly zusammenfassen und bei jeder Änderung die gesamte Menge neu kompilieren.Dies hat den Vorteil, dass Sie mit a ein Flag zum Kompilieren auf der Festplatte hinzufügen können PDB zum Testen, sodass Sie mithilfe des dynamischen Codes debuggen können.

Ja, darüber habe ich nachgedacht, aber mir wurde bald klar, dass eine andere Domain-Specific-Language (DSL) etwas zu viel wäre.

Im Wesentlichen müssen sie auf möglicherweise unvorhersehbare Weise mit meinem Spielstatus interagieren.Beispielsweise könnte eine Karte eine Regel haben: „Wenn diese Karte ins Spiel kommt, erhalten alle deine untoten Diener +3 Angriffskraft gegen fliegende Feinde, außer wenn der Feind gesegnet ist.“Da Sammelkartenspiele rundenbasiert sind, löst der GameState Manager OnStageX-Ereignisse aus und lässt die Karten andere Karten oder den GameState auf die von der Karte benötigte Weise modifizieren.

Wenn ich versuche, eine DSL zu erstellen, muss ich einen ziemlich großen Funktionsumfang implementieren und ihn möglicherweise ständig aktualisieren, wodurch sich die Wartungsarbeiten auf einen anderen Teil verlagern, ohne ihn tatsächlich zu entfernen.

Deshalb wollte ich bei einer „echten“ .NET-Sprache bleiben, um im Wesentlichen einfach das Ereignis auslösen zu können und die Karte den Spielstatus auf beliebige Weise manipulieren zu lassen (innerhalb der Grenzen der Codezugriffssicherheit).

In der nächsten Version von .NET (5.0?) wurde viel darüber gesprochen, den „Compiler als Dienst“ zu öffnen, der Dinge wie die direkte Skriptauswertung ermöglichen würde.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top