Come posso archiviare tutti i miei dati di livello in un singolo file anziché distribuirli su molti file?


8

Attualmente sto generando i miei dati di livello e sto salvando su disco per garantire che tutte le modifiche apportate al livello vengano salvate.

Sto memorizzando "blocchi" di 2048x2048 pixel in un file. Ogni volta che il giocatore si sposta su una sezione che non ha un file associato alla posizione, viene creato un nuovo file.

Funziona benissimo ed è molto veloce. Il mio problema è che mentre stai giocando il conteggio dei file diventa sempre più grande.

Mi chiedo quali sono le tecniche che possono essere utilizzate per alleviare il conteggio dei file, senza subire un calo delle prestazioni. Sono interessato a come archiviare / cercare / aggiornare questi dati in un singolo file anziché in più file in modo efficiente.


5
Fondamentalmente dovresti scrivere un file system in miniatura per poter archiviare tutto in un singolo file. Aumenterà la complessità e potrebbe non valerne la pena.
thedaian,

1
Io in realtà non ho molta esperienza con la seguente, ma forse un db NoSQL basato su file ( stackoverflow.com/questions/2403174/... ) potrebbe essere un'opzione.
Chris,

Di quanti file stiamo parlando qui? I giocatori generano decine di migliaia di file o solo centinaia? Cosa cambiano i giocatori nel pezzo? Il blocco genera un passaggio costoso (ad esempio, è necessario memorizzare nella cache l'intero blocco rispetto a un diff?)
Leniency

Minecraft ha attraversato questa conversione anche ad un certo punto. Credo che sia iniziato come mod, quindi è stato incorporato nella build principale. Vale la pena esaminare. minecraftwiki.net/wiki/Region_file_format
Michaelhouse

1
@thedaian è un po 'più complesso, ma puoi fare cose interessanti e davvero ridurre i tempi di ricerca se sei disposto a fare un lavoro extra in memoria, quindi il filesystem non deve farlo sul disco.
ClassicThunder

Risposte:


7

Il modo più veloce per farlo è archiviare tutto in un unico file e saltare il cursore sul blocco che si desidera leggere. Una volta che colpisci il disco leggendo una sequenza da quel punto il suo punto è piuttosto veloce.

I molteplici accessi a diversi INode per trovare la posizione del file sul volume fisico è ciò che richiede la maggior parte del tempo e anche ciò che si ridimensiona male.

Inoltre, poiché questo è dinamico, avrai anche bisogno di una mappa che memorizzi l'offset nel file per ogni blocco.

Su disco

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

Visibile

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

Quindi devi solo aprire un flusso che legge dal file ma non impedisce ad altri flussi / processi di accedervi. Quindi è necessario leggere l'offset corretto per la distanza corretta. Credo che in C # sia il seguito.

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);
    }
}

Ora, a causa del fatto che hai aperto lo stream in modalità sola lettura e hai permesso ad altri di leggere / scrivere su di esso, puoi continuare ad aggiungere nuovi blocchi alla fine. Tieni traccia del loro numero di offset e non provare a leggerli prima che siano lì.

PS non vorrai usare il blocco using poiché vorrai solo 1 flusso di lettura per tutta la vita di qualunque livello tu stia usando. Inoltre, probabilmente dovrai salvare la mappatura dei blocchi in un altro file all'uscita ma questo è solo un carico quando carichi il tuo livello.


Questo mi sta dando alcune grandi idee. Questo metodo richiederebbe di scrivere ogni blocco esattamente lo stesso numero di byte? Immagino, poiché la ricerca dell'offset lo richiederebbe.
Jgallant,

Finché si dispone del primo byte e della lunghezza di ogni blocco non devono avere le stesse dimensioni. Devi solo avere qualcosa in memoria per tenere traccia di questi due pezzi di dati.
ClassicThunder

1
Naturalmente, se non li avessi di uguale dimensione in byte, dovresti fare molti spostamenti se uno dovesse aumentare di dimensioni.
MichaelHouse

1

A seconda del tempo richiesto per generare un pezzo, potresti semplicemente memorizzare differenze o uno stato corrente (posizioni nemiche, ecc.). Quando il giocatore ritorna in un pezzo, si genera di nuovo usando un seme memorizzato, quindi carica tutte le modifiche apportate dal file.

Se i giocatori sono autorizzati ad apportare modifiche significative, questo potrebbe essere lento e il file diff sarà comunque abbastanza grande, ma solo per piccole modifiche dovrebbe essere un'operazione economica. Differenti blocchi multipli potrebbero essere consolidati anche in un singolo file - qualcosa di ragionevolmente dimensionato che potrebbe essere caricato in memoria.

Probabilmente non vorrai spostare tutte le differenze in un singolo file, ciò apre una serie di altri problemi con la memoria o cambia la parte centrale del file.


1

So che questo è un thread piuttosto vecchio, ma vorrei solo accennare al fatto che penso che un archivio ZIP potrebbe essere il modo migliore per andare qui. Ottieni compressione con i tuoi dati (specialmente se stai utilizzando bitmap non elaborate), leggibilità nel sistema operativo e ottieni il singolo file come desideri.


0

Che ne dite di una scansione dir per controllare il timestamp dei file nella directory dei dati di livello rispetto al file attivo corrente e dare una grazia del file precedente e del file che va avanti ogni 10 secondi circa, e tutto ciò che non viene utilizzato cancellali e basta.

A meno che non sia necessario che il giocatore torni indietro. Quindi ripulisci semplicemente i dati di livello al completamento del livello o checkpoint? Potrebbe diventare grande di sicuro, ma non credo che ci siano molte opzioni disponibili qui


0

Che ne dite di più blocchi per file? Dici che i tuoi pezzi sono 2048 x 2048, che ne dici di mettere 16384 x 16384 in un file. Segnala quali esistono in qualche modo in modo da sapere se è necessario crearlo.


0

Se riesci a generare i blocchi abbastanza velocemente mentre il giocatore esplora comunque, non è necessario memorizzarli su disco; tutto quello che devi fare è archiviare il seme per le funzioni di rumore perlin che stai usando per generare nuovamente il tuo contenuto procedurale su richiesta.

Questi possono essere memorizzati in un singolo file e possono essere scritti in sequenza e ordinati in RAM quando caricati; non è necessaria una struttura ordinata complicata nel file stesso sul disco. Puoi leggerlo solo all'avvio e scriverlo mentre generi nuove "pagine" (come vengono definite) nel mondo di gioco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.