¿Cómo puedo almacenar todos mis datos de nivel en un solo archivo en lugar de distribuirlos en muchos archivos?


8

Actualmente estoy generando mis datos de nivel y los estoy guardando en el disco para garantizar que se guarden las modificaciones realizadas en el nivel.

Estoy almacenando "fragmentos" de 2048x2048 píxeles en un archivo. Cada vez que el jugador se mueve sobre una sección que no tiene un archivo asociado con la posición, se crea un nuevo archivo.

Esto funciona muy bien y es muy rápido. Mi problema es que a medida que juegas, el recuento de archivos aumenta cada vez más.

Me pregunto cuáles son las técnicas que se pueden utilizar para aliviar el recuento de archivos, sin tener un impacto en el rendimiento. Estoy interesado en cómo almacenar / buscar / actualizar estos datos en un solo archivo en lugar de múltiples archivos de manera eficiente.


55
Básicamente, tendría que escribir un sistema de archivos en miniatura para poder almacenar todo en un solo archivo. Se agregará a la complejidad y puede que no valga la pena.
Thedaian

1
Realmente no tengo mucha experiencia con lo siguiente, pero quizás una base de datos nosql db ( stackoverflow.com/questions/2403174/… ) podría ser una opción.
Chris

¿De cuántos archivos estamos hablando aquí? ¿Los jugadores generan decenas de miles de archivos, o solo cientos? ¿Qué están cambiando los jugadores en la parte? ¿El fragmento genera un paso costoso (es decir, ¿necesita almacenar en caché todo el fragmento versus solo una diferencia?)
Leniency

Minecraft pasó por esta conversión en algún momento también. Creo que comenzó como un mod y luego se incorporó a la compilación principal. Vale la pena investigarlo. minecraftwiki.net/wiki/Region_file_format
MichaelHouse

1
@thedaian es un poco más complejo, pero puedes hacer algunas cosas geniales y realmente reducir los tiempos de búsqueda si estás dispuesto a trabajar un poco más en la memoria para que el sistema de archivos no tenga que hacerlo en el disco.
ClassicThunder

Respuestas:


7

La forma más rápida de hacer esto es almacenar todo en un archivo y saltar el cursor al fragmento que desea leer. Una vez que golpeas el disco leyendo una secuencia, su punto es bastante rápido.

Los múltiples accesos a diferentes INodes para encontrar la ubicación del archivo en el volumen físico es lo que toma la mayor parte del tiempo y también lo que escala mal.

Además, dado que esto es dinámico, también necesitará un mapa que almacene el desplazamiento en el archivo para cada fragmento.

En el disco

[Chunk 1][Chunk 2][Chunk 3][Chunk 4][Chunk 5][Chunk 6][Chunk 7][Chunk 8][Chunk 9]

Visible

[7][8][9]
[6][1][2]
[5][4][3]

Luego, solo necesita abrir una secuencia que lea el archivo pero no bloquee el acceso de otras secuencias / procesos. Entonces necesita leer desde el desplazamiento correcto para la distancia correcta. Creo en C # es el siguiente.

var chunk = new byte[4194304];
using (var file = new FileStream (openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var reader = new StreamReader (file, Encoding.Unicode)) {
        reader.Read(chunk, offset * 4194304, 4194304);
    }
}

Ahora, debido al hecho de que abrió la secuencia en modo de solo lectura y permitió que otros lean / escriban, puede seguir agregando nuevos fragmentos al final. Simplemente haga un seguimiento de su número de desplazamiento y no intente leerlos antes de que estén allí.

PD: no va a querer usar el bloque de uso, ya que va a querer solo 1 flujo de lectura a lo largo de la vida de cualquier nivel que esté usando. También es probable que tenga que guardar la asignación de fragmentos en otro archivo al salir, pero eso es solo una carga cuando carga su nivel.


Esto me está dando algunas ideas geniales. ¿Requiere este método que escriba cada fragmento exactamente el mismo número de bytes? Me imagino, ya que la búsqueda de compensación lo requeriría.
jgallant

Siempre que tenga el primer byte y la longitud de cada fragmento, no tienen que ser del mismo tamaño. Solo tiene que tener algo en la memoria para realizar un seguimiento de estos dos datos.
ClassicThunder

1
Por supuesto, si no tuviera un tamaño de byte igual, tendría que hacer muchos cambios si fuera a crecer de tamaño.
MichaelHouse

1

Dependiendo del tiempo requerido para generar un fragmento, puede almacenar diferencias o un estado actual (ubicaciones enemigas, etc.). A medida que el jugador regresa a un fragmento, se genera nuevamente utilizando una semilla almacenada, luego carga los cambios que se hicieron desde el archivo.

Si a los jugadores se les permite hacer cambios significativos, esto podría ser lento y el archivo de diferencias seguirá siendo bastante grande, pero solo para pequeños cambios, debería ser una operación económica. También se pueden consolidar varios diferenciales de fragmentos en un solo archivo, algo de un tamaño razonable que se puede cargar en la memoria.

Sin embargo, es probable que no desee mover todos los diferenciales en un solo archivo, lo que abre una serie de otros problemas con la memoria o el cambio del medio del archivo.


1

Sé que este es un hilo bastante antiguo, pero me gustaría comentar que creo que un archivo ZIP podría ser la mejor manera de ir aquí. Obtiene compresión con sus datos (si está utilizando mapas de bits sin procesar, especialmente), legibilidad en el sistema operativo y obtiene el archivo único que deseaba.


0

¿Qué pasa con una exploración de directorio para verificar la marca de tiempo de los archivos en el directorio de datos de nivel frente al archivo activo actual y dar una gracia del archivo anterior y el archivo que avanza cada 10 segundos más o menos, y lo que no se está utilizando solo bórralos.

A menos que requiera que el jugador regrese. Entonces, ¿simplemente limpiar los datos del nivel al finalizar el nivel o el punto de control? Seguramente podría crecer, pero no creo que haya muchas opciones disponibles aquí


0

¿Qué tal múltiples fragmentos por archivo? Dices que tus fragmentos son 2048 x 2048, ¿qué tal si colocas 16384 x 16384 en un archivo? Marque cuáles existen de alguna manera para que sepa si necesita crearlo.


0

Si puede generar los fragmentos lo suficientemente rápido como el jugador explora de todos modos, entonces no necesita almacenarlos en el caché; todo lo que necesita hacer es almacenar la semilla de las funciones de ruido perlin que está utilizando para generar su contenido de procedimiento nuevamente a pedido.

Estos pueden almacenarse en un solo archivo, y pueden escribirse secuencialmente y ordenarse en RAM cuando se cargan; no hay necesidad de una estructura ordenada complicada en el archivo en el disco. Puede leerlo solo en el inicio y escribir en él a medida que genera nuevas 'páginas' (como se las denomina) en el mundo del juego.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.