Añadiendo funcionalidad de scripting a aplicaciones .NET

77

Tengo un pequeño juego escrito en C #. Utiliza una base de datos como back-end. Es un juego de cartas coleccionables y quería implementar la función de las cartas como un script.

Lo que quiero decir es que esencialmente tengo una interfaz, ICardque implementa una clase de tarjeta ( public class Card056: ICard) y que contiene una función que es llamada por el juego.

Ahora, para que la cosa sea mantenible / modificable, me gustaría tener la clase para cada tarjeta como código fuente en la base de datos y esencialmente compilarla en el primer uso. Entonces, cuando tenga que agregar / cambiar una tarjeta, simplemente la agregaré a la base de datos y le diré a mi aplicación que se actualice, sin necesidad de implementar ningún ensamblaje (especialmente porque estaríamos hablando de 1 ensamblaje por tarjeta, lo que significa cientos de ensamblajes) .

¿Es eso posible? Registre una clase desde un archivo fuente y luego cree una instancia, etc.

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

El lenguaje es C # pero es una ventaja adicional si es posible escribir el script en cualquier lenguaje .NET.

Michael Stum
fuente
1
Es gracioso, un amigo y yo estábamos pensando en escribir un juego de cartas coleccionables en C # hace un tiempo, ¿no supongo que todavía tienes la fuente para esto? Interesado en cómo te acercaste a esto.
mattytommo
@mattytommo No, no me queda nada, estaba en las primeras etapas y esencialmente estaba funcionando como lo describí anteriormente. Hoy en día, buscaría en Roslyn para hacer la compilación de C #: blogs.msdn.com/b/csharpfaq/archive/2011/10/19/… - Alternativamente, JavaScript usando Jint - jint.codeplex.com
Michael Stum
Ah, gracias, pero buscaba más la implementación del juego de cartas coleccionables en sí y la estructura que usaste, en contraposición al motor de secuencias de comandos. Gracias de todos modos :)
mattytommo

Respuestas:

41

La solución de secuencia de comandos C # de Oleg Shilo (en The Code Project ) realmente es una excelente introducción para proporcionar capacidades de secuencia de comandos en su aplicación.

Un enfoque diferente sería considerar un lenguaje que esté específicamente diseñado para secuencias de comandos, como IronRuby , IronPython o Lua .

IronPython e IronRuby están disponibles hoy.

Para obtener una guía para incrustar IronPython, lea Cómo incrustar el soporte de scripts de IronPython en su aplicación existente en 10 sencillos pasos .

Lua es un lenguaje de secuencias de comandos que se usa comúnmente en los juegos. Hay un compilador Lua para .NET, disponible en CodePlex - http://www.codeplex.com/Nua

Ese código base es una excelente lectura si desea aprender a crear un compilador en .NET.

Un ángulo completamente diferente es probar PowerShell . Hay numerosos ejemplos de incrustación de PowerShell en una aplicación; aquí hay un proyecto completo sobre el tema: Powershell Tunnel

Leon Bambrick
fuente
1
Por cierto, elegí esta como la respuesta aceptada porque quería mirar Python e IronPython de todos modos, por lo que el enfoque de IronPython funciona mejor para .
Michael Stum
LuaInterface es un intérprete de lua que también funciona fantástico.
RCIX
Implementé C # Script en un sistema de flujo de trabajo en noviembre de 2009. Nos ha funcionado muy bien.
David Robbins
8

Es posible que pueda usar IronRuby para eso.

De lo contrario, le sugiero que tenga un directorio donde coloque los ensamblados precompilados. Luego, podría tener una referencia en la base de datos al ensamblado y la clase, y usar la reflexión para cargar los ensamblados adecuados en tiempo de ejecución.

Si realmente desea compilar en tiempo de ejecución, puede usar CodeDOM, entonces puede usar la reflexión para cargar el ensamblado dinámico. Artículo de documentación de Microsoft que podría ayudar .

Eric Haskins
fuente
7

Si no desea usar el DLR, puede usar Boo (que tiene un intérprete) o podría considerar el proyecto Script.NET (S #) en CodePlex . Con la solución Boo puede elegir entre scripts compilados o usar el intérprete, y Boo crea un lenguaje de scripting agradable, tiene una sintaxis flexible y un lenguaje extensible a través de su arquitectura de compilación abierta. Sin embargo, Script.NET también se ve bien, y podría extender fácilmente ese lenguaje, así como también es un proyecto de código abierto y utiliza un Generador de compiladores muy amigable ( Irony.net ).

Nathan
fuente
6

Puede utilizar cualquiera de los lenguajes DLR, que proporcionan una forma de alojar fácilmente su propia plataforma de secuencias de comandos. Sin embargo, no es necesario que utilice un lenguaje de secuencias de comandos para esto. Puede usar C # y compilarlo con el proveedor de código C #. Siempre que lo cargue en su propio AppDomain, puede cargarlo y descargarlo al contenido de su corazón.

Jesse Ezell
fuente
5

Sugeriría usar LuaInterface ya que ha implementado Lua por completo donde parece que Nua no está completo y probablemente no implemente alguna funcionalidad muy útil (corrutinas, etc.).

Si desea utilizar algunos de los módulos Lua preempaquetados externos, le sugiero que use algo similar a 1.5.x en lugar de la serie 2.x que crea código completamente administrado y no puede exponer la API C necesaria.

harningt
fuente
5

Estoy usando LuaInterface1.3 + Lua 5.0 para una aplicación NET 1.1.

El problema con Boo es que cada vez que analiza / compila / evalúa su código sobre la marcha, crea un conjunto de clases boo para que tenga pérdidas de memoria.

Lua, por otro lado, no hace eso, por lo que es muy estable y funciona de maravilla (puedo pasar objetos de C # a Lua y hacia atrás).

Hasta ahora no lo he puesto en PROD, pero parece muy prometedor.

Tuve problemas de fugas de memoria en PROD usando LuaInterface + Lua 5.0 , por lo tanto, usé Lua 5.2 y me vinculé directamente a C # con DllImport. Las pérdidas de memoria estaban dentro de la biblioteca LuaInterface.

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

Una vez que hice esto, todas mis pérdidas de memoria desaparecieron y la aplicación era muy estable.

Kat Lim Ruiz
fuente
4

La aplicación principal que vende mi división hace algo muy similar para proporcionar personalizaciones al cliente (lo que significa que no puedo publicar ninguna fuente). Tenemos una aplicación C # que carga scripts dinámicos de VB.NET (aunque cualquier lenguaje .NET podría ser fácilmente compatible; se eligió VB porque el equipo de personalización provenía de ASP).

Usando CodeDom de .NET compilamos los scripts de la base de datos, usando el VB CodeDomProvider(molestamente por defecto es .NET 2, si desea admitir características 3.5, debe pasar un diccionario con "CompilerVersion" = "v3.5" a su constructor ). Use el CodeDomProvider.CompileAssemblyFromSourcemétodo para compilarlo (puede pasar configuraciones para forzarlo a compilar solo en memoria.

Esto daría como resultado cientos de ensamblados en la memoria, pero podría juntar todo el código de las clases dinámicas en un solo ensamblado y volver a compilar todo el lote cuando haya algún cambio. Esto tiene la ventaja de que puede agregar una marca para compilar en disco con un PDB para cuando esté probando, lo que le permite depurar a través del código dinámico.

Keith
fuente
4

Sí, pensé en eso, pero pronto me di cuenta de que otro lenguaje específico de dominio (DSL) sería demasiado.

Esencialmente, necesitan interactuar con mi estado de juego de formas posiblemente impredecibles. Por ejemplo, una carta podría tener una regla: "Cuando estas cartas entran en juego, todos tus esbirros no muertos ganan +3 de ataque contra enemigos voladores, excepto cuando el enemigo está bendecido". Como los juegos de cartas coleccionables se basan en turnos, GameState Manager activará eventos OnStageX y permitirá que las cartas modifiquen otras cartas o GameState de la forma que necesite la carta.

Si intento crear un DSL, tengo que implementar un conjunto de funciones bastante grande y posiblemente actualizarlo constantemente, lo que traslada el trabajo de mantenimiento a otra parte sin eliminarlo.

Es por eso que quería quedarme con un lenguaje .NET "real" para poder básicamente disparar el evento y dejar que la tarjeta manipule el estado del juego de cualquier manera (dentro de los límites de la seguridad de acceso al código).

Michael Stum
fuente
(No es necesario marcar esto; si bien esto debería ser una actualización de comentario / respuesta, pero está protegido desde antes de que fueran opciones)
3

La próxima versión de .NET (¿5.0?) Se ha hablado mucho sobre la apertura del "compilador como servicio", lo que haría posible cosas como la evaluación directa de scripts.

Eric Falsken
fuente
2
Si. Aunque Roslyn todavía está en el horizonte, Mono.CSharp (disponible en NuGet) incluye todas las mismas funciones.
Eric Falsken
Agregar una actualización para mantener las opciones relevantes: La plataforma del compilador .NET ("Roslyn") está disponible. Entonces es una alternativa viable a todas las demás mencionadas. github.com/dotnet/roslyn .
Riv