El blog personal de Morgul, donde escribe sobre sus aficiones, descubrimientos y actividades, compartiendo conocimientos.

23 de noviembre de 2008

MUnDoCAAD MUD Engine: pasado y presente

Se ha notado muchísimo que he sido el único desarrollador del motor del MUD para nuestro 'MUnDoCAAD' (el MUnDoCAAD MUD Engine), así como que no tenía mucha idea de cómo implementar un MUD... muestra de ello ha sido el largo tiempo que me ha llevado programar algo funcional, elegante y potente.

MUnDoCAAD MUD Engine nació en enero de 2003 (edito: aunque partes de él fueron programadas en 2002), escrito en C++ y usando tanto sockets POSIX como WinSocks (que eran un churro, puesto que se comían toda la CPU con madalenas al esperar en las llamadas select), según la plataforma de compilación usada (UNIX o Windows, respectivamente). Más tarde descubrí que la librería Qt proporcionaba manejo de sockets y otras abstracciones del sistema operativo que harían el código compatible no sólo en sistemas UNIX y Windows sino también para Mac OS, así que reescribí parte del código para hacerlo más portable utilizando la Qt.

La pega de la Qt - versión 3 en aquél entonces - era que requería enlazar con las librerías de interfaz gráfica, y ejecutarse desde X Window en sistemas UNIX, a pesar de que el motor del MUD no era más que una aplicación de consola.

Luego salió la versión 4 de la librería Qt, que permitía por fin independizarse de las librerías de interfaz gráfica. Mejoró mucho el código del motor del MUD por aquél entonces, pero sobre todo mejoró mi comprensión de qué debería tener el motor funcionalmente para manejar un MUD. Gracias a la Qt, ya me despreocupaba en gran medida del aspecto de comunicaciones en red, y mis ideas de diseño giraban en torno al almacenamiento de la base de datos del MUD y su cacheo en memoria (para evitar tener en memoria toda la base de datos se utilice o no, y no tener que estar guardando a disco constantemente las modificaciones realizadas).

Desde los inicios, pensé usar XML para almacenar las entidades (objetos, localidades, personajes y demás) del MUD en la base de datos. Creo recordar que llegué a implementar completamente la carga y almacenamiento de entidades con la librería libxml2, aunque revisando el historial del repositorio CVS de nuestro proyecto en SourceForge no encuentro dicha evidencia. En cuanto empecé a usar la librería Qt para el motor, me aproveché de las clases para el manejo de documentos XML que trae esta, de manera bastante similar a como se hacía con la libxml2.

Sin embargo, era relativamente lento cargar y escribir documentos XML para el poco contenido que tenía cada uno (los datos propios de cada entidad del MUD, pues pensé en almacenar cada una en un fichero aparte). No obstante, al tener el sistema de caché ya implementado (de nombre Archivero, en memoria de El Viejo Archivero), este amortiguaba un poco este impacto de coste temporal.

Llegué al punto en que tuve que plantearme cómo implementar la librería base, también llamada el modelo de mundo. No podía implementarla como el resto del motor, usando C++, puesto que cualquier cambio implicaría tener que recompilar y reiniciar el motor del MUD para que surtiera efecto. Debía utilizar algún lenguaje interpretado, que fuera ejecutado desde el motor del MUD. Pero yo no sabía ni quería embarcarme en la costosa tarea de inventar un lenguaje para el MUD.

Más tarde, descubría la librería QSA: Qt Scripting for Applications. Esta me proporcionaba un lenguaje interpretado y un intérprete para ejecutar su código desde aplicaciones que usaran la librería Qt. "Genial" - pensé, y me puse a implementar la librería base del MUD con este lenguaje, muy similar a C++ (el lenguaje era un subconjunto de ECMAScript, íntimamente relacionado con JavaScript).

Pronto descubrí limitaciones en esta forma de implementación del motor del MUD. Al parecer, QSA por aquella época tenía ciertos fallos al convertir variables y objetos del lenguaje QSA a variables Qt, y tuve que hacer apaños para solventar dichos problemas. Para colmo, QSA hacía que tuviera que volver a enlazar con librerías de interfaz gráfica, aunque esta vez no me obligaba a ejecutar el motor del MUD desde X Window en mi entorno de desarrollo Linux.

Por todo esto, y por la infactibilidad de la ejecución de código almacenado en las entidades de la base de datos (código relacionado con la reacción de las entidades ante acciones de los personajes o del modelo de mundo) de manera elegante y potente, abandoné por completo el desarrollo del MUD.

Por suerte, durante los dos siguientes años a este abandono, he descubierto el lenguaje Python y lo fácil y rápido que es programar en él. Era cuestión de tiempo que me planteara intentar reescribir MUnDoCAAD MUD Engine por completo en Python, así como usar Python mismo como el lenguaje interpretado embebido en las entidades del MUD.

Y así fue, hace unos pocos meses atrás ya estaba implementando una caché LRU para almacenar las entidades. Después vino la implementación del módulo Archivero (reutilicé el nombre de su predecesor en C++/Qt), utilizando mi flamante caché LRU en Python. Esta vez descarté usar XML como formato de los ficheros de entidad, a pesar de tener buen soporte en Python, porque no quería que fuera costosa la lectura y escritura de cada entidad de la base de datos, y utilicé en su lugar las ventajas del módulo cPickle de Python.

Los resultados eran más que satisfactorios: código sencillo, funcional y rápido de desarrollar. El mismo código que empezaba a escribir como prueba (en plan chapucilla) de la funcionalidad que quería, terminaba convirtiéndose en poco tiempo en código correcto y completo funcionalmente.

Hace unas pocas semanas, empecé a escribir lo que sería el nuevo módulo Servidor del mud, usando la implementación de sockets que trae Python. Tan sencillo empezó siendo este módulo, que sólo permitía una conexión simultánea al MUD, y durante bastante tiempo siguió así, como un motor para aventuras conversacionales tradicionales (de un sólo jugador) que requería conectarse por Telnet para jugar.

Se me ocurrió implementar la aventura conversacional del tutorial 'La Torre - Contruye tu propia aventura' creado por Uto para NMP y adaptado a InformATE! por Zak, porque quería comprobar si el nuevo motor en Python era capaz de dar vida a algo jugable. Inicié una base de datos de MUD con las entidades de la aventura de este tutorial, así como un parser (analizador sintáctico) muy sencillo de tipo VERBO + NOMBRE, y una librería modelo de mundo con vistas a que el juego eventualmente pudiera ser utilizado por varios jugadores a la vez.

Estaba tan contento de ver que todo funcionaba bien y que el motor Python era perfectamente capaz, que quería enseñárselo a mis colegas del CAAD, y les hablé de él en el canal de IRC y de su posible futura evolución. Esto ocurría ya hace menos de una semana. Para poder enseñar mi creación tenía que hacer que pudiera conectarse más de un jugador a la vez, así que implementé un módulo Servidor que atendiera las conexiones de red del MUD, para lo cual utilicé el módulo asyncore de Python en lugar de trabajar con los sockets directamente.

Aumenté la librería base y el parser para que los jugadores pudieran ver cómo los personajes cambiaban de localidad y añadí el comando decir, para que pudieran hablar entre ellos. Hice una invitación en el IRC, y se apuntaron unos cuantos a probar el nuevo MUD. Inmediatamente relució un fallo en el código de la librería base, ya que nombraba a los personajes así: "Aquí está un Juan, un Pepe y un Jacinto", en lugar de decir: "Aquí está Juan, Pepe y Jacinto". Corregí este fallo en un periquete, y descubrí que conforme estaba implementado el motor, para que la corrección surtiera efecto sólo podía reiniciar el MUD.

Estando el MUD con jugadores conectados, no es una opción factible echarlos a todos cada vez que se haga una corrección a la librería del modelo de mundo o a alguna otra parte del motor. Así que investigué un poco e implementé un módulo (Restaurador) que recarga a petición del administrador los módulos del motor del MUD que se deseen, incluido él mismo. Desde entonces el MUD puede mejorarse dinámicamente, sin necesidad de reinicios.

Algunos jugadores tenían problemas para leer y escribir tildes y eñes en el MUD, debido a que ellos usan la codificación de caracteres UTF-8 y el motor trabaja con ISO-8859-15. Así que también añadí a MUnDoCAAD MUD Engine la capacidad de realizar conversión de código de caracteres para aquellos jugadores que así lo deseen.

Básicamente, el motor del MUD en Python cuenta con toda la funcionalidad de su predecesor en C++/Qt, además de tener nuevas características que difícilmente habría podido implementar en aquél (ahora obsoleto) motor. Podría decir que este es el mejor MUD que he creado nunca :)

Por cierto, el código fuente del nuevo motor Python es GPL versión 2 (igual que el antiguo), y ya está disponible en el repositorio Subversion del proyecto en SourceForge: https://sourceforge.net/projects/mundocaad

¿Te ha gustado esta entrada? Vótala en Bitacoras.com: Votar

7 comentarios:

Anónimo dijo...

Morgul, sería estupendo si añadieses tu blog al Planeta Aventurero.

Si vas a tratar temas no relacionados con la aventura y no quieres que estos aparezcan, puedes añadir simplemente una etiqueta y que sea esa la que se sindique al planeta.

Morgul dijo...

Hola Planseldon, gracias por visitarme. Tu idea es genial, me pondré en contacto con los admins del Planeta Aventuraro.

Uto dijo...

Cuando me ha llegado el mail de la lista de MundoCAAD creí que a algún servidor de correo se le había ido la pinza, o que el correo había dormido años en un servidor apagado que alguien acababa de decidir encender. Pero no, la fecha es de hoy y el blog es de hoy.

Desde luego no puedo decir más que que te animo a continuar, me encantaría volver a tener un MUD operativo en CAAD y que mejor que uno hecho a medida para poder hacerlo.

En cuanto a los updates en caliente, no se como lo has hecho, pero sí estoy seguro de que se plantean ciertos problemas, como lo que pasa si un usuario esta en una localidad que desaparece.

No se si puedo hacer algo para ayudar, programando más bien poco porque ni se python ni tengo tiempo, pero si puedo aportar ideas o soluciones estaré encantado de hacerlo.

Sigue informando por la lista o por el foro ¡ánimo!

Sarganar dijo...

estupendo!
ya no tengo el tiempo de antaño pero desde aqui mis felicitaciones y apoyos morales a tu genial proyecto.

Anónimo dijo...

Buen trabajo Morgul, como te dije, estoy pensando en escribir un módulo de MUD para Rebot, así podrá conectarse a MUnDoCAAD e interactuar con sus usuarios. También funcionará en otros MUDs, claro.

Anónimo dijo...

Por lo que veo mas de uno tenemos ganas de ver eso funcionar! :D

Ya se que hacer eso no es facil y hay mucho en que trabajar...pero Animos!!!

Un Saludo.

Anónimo dijo...

Por cierto, no se mucho programar... pero si necesitases ayudas no dudes en pedirlas!!!