Estoy buscando ideas sobre cómo hacer lo siguiente: Quiero escribir un simple "mundo" en Java. Uno que podría comenzar y luego agregar nuevos objetos más adelante para simular / observar diferentes comportamientos entre los objetos existentes. El plan es codificar los objetos más nuevos después de mirar los viejos por un tiempo y luego cargarlos / soltarlos en el mundo existente. El problema es que no quiero detener o reiniciar el mundo una vez que haya comenzado, quiero que se ejecute durante unas semanas, pero necesito la capacidad de soltar objetos y rehacer / reescribir / eliminar / crear / mutarlos con el tiempo sin necesidad de reiniciar. El mundo podría ser tan simple como una matriz de 100 x 100 de ubicaciones X / Y, con una posible GUI de mapa en mosaico para representar visualmente el mundo. Sé que necesito algún tipo de proceso de temporizador para monitorear objetos y darles a cada uno una 'oportunidad de actuar'
Ejemplo: codifico World.java el lunes y lo dejo en funcionamiento. Luego, el martes escribo una nueva clase llamada Rock.java (que no se mueve). Luego lo cargo / lo dejo (¿de alguna manera?) En este mundo que ya se está ejecutando (que simplemente lo deja en algún lugar al azar en la matriz mundial y nunca se mueve). Luego, el miércoles, creo una nueva clase llamada Cat.java y la dejo caer al mundo, nuevamente colocada al azar, pero este nuevo objeto puede moverse alrededor del mundo (durante una unidad de tiempo), luego el jueves escribo una clase llamada Perro. Java, que también se mueve pero puede "actuar" en otro objeto si está en la ubicación vecina y viceversa.
Aquí está la cosa. No sé qué tipo de estructura / diseño necesitaría para codificar la clase mundial real para saber cómo detectar / cargar / rastrear objetos futuros (y actualmente no existentes).
¿Alguna idea de cómo harías algo así usando Java?
Respuestas:
Lo que básicamente está buscando es un sistema conectable en caliente. Ejecuta una aplicación principal y luego agrega complementos en tiempo de ejecución que se integran en el bucle de eventos. Primero, comienza a pensar en lo que tu mundo espera de una entidad de juego. Por ejemplo (según su descripción):
Por supuesto, puede agregar otros métodos que considere necesarios. Tenga en cuenta el parámetro World con los dos métodos relevantes. Esto le permite a su nueva entidad considerar el mundo al configurar o actualizar. En tu clase de perro, por ejemplo, puedes preguntarle al mundo por todos los gatos del vecindario. Luego, crea su mundo que funciona con esta interfaz y un sistema para compilar y cargar dinámicamente código Java. Un ejemplo de esto se puede encontrar aquí .
Llame a este método desde la GUI mundial para agregar nuevas entidades. Dependiendo de su implementación mundial, una función de inicio de entidad puede verse así:
fuente
Hicimos algo así en Stendhal para las redadas.
No buscamos evitar por completo los reinicios. Por lo tanto, los cambios en nuestros servicios básicos de infraestructura, como la comunicación cliente / servidor, necesitan reiniciarse. Pero agregar entidades, criaturas y NPC y modificar objetos existentes sí funciona. (Ah, y a veces la corrección de errores en vivo, la reflexión se puede utilizar para manipular incluso campos privados).
Dado que no solo queremos nuevos objetos basados en nuevos datos (como otra máscara), sino que queremos agregar un nuevo comportamiento, el programa mundial debe poder cargar nuevos archivos de clase . Los llamamos "scripts", pero son verdaderas clases Java compiladas. Esas clases implementan la interfaz Script.java .
Maria.java es un ejemplo simple. Ella es una nueva APN que vende bebidas y comida a los jugadores. También podemos definir objetos muy complejos allí.
Una nueva clase se carga de esta manera:
Si puede garantizar nombres únicos y nunca quiere descargar clases, ya ha terminado con las cosas de bajo nivel.
La descarga , sin embargo, parece bastante importante. Para lograr eso, debe crear una instancia de un nuevo cargador de clases cada vez que desee inyectar un nuevo código. Para que el GC pueda hacer su trabajo después de borrar la última referencia a ese código.
Tenemos un comando / unload que invoca un método de descarga en nuestra interfaz para que los scripts puedan realizar la limpieza. La descarga real se realiza automáticamente por el GC.
A menudo creamos muchos objetos temporales durante las redadas. Y queremos que todos se eliminen una vez que finalice la redada. Por ejemplo, el Gnomes Raid, que genera varios gnomos cerca del administrador invisible, usamos este código: GnomeRaid.java extiende CreateRaid.java .
El script podría acceder al mundo directamente (como muestra el primer ejemplo) y hacer su propia limpieza en el método unload (). Pero los codificadores Java no están acostumbrados a limpiar, y es molesto. Entonces creamos un sandbox que los scripts pueden usar. Al descargar, se eliminan todos los objetos agregados al mundo a través de la clase Sandbox.
fuente
Salva el mundo (sin juego de palabras) y todo su estado (posiciones, velocidades, todas las variables).
Sin embargo, esta es una solución general, no sé los detalles de Java para saber si puede implementar dinámicamente bloques de código y clases como espera ...
La opción 2 es enlazar un lenguaje de scripts que se puede cargar sobre la marcha.
fuente
Para Java, todo lo que necesita es una plataforma OSGi . Con eso es trivial para los módulos o aplicaciones de intercambio en caliente, e incluso hacer administración remota o actualizaciones parciales.
fuente