Comment puis-je stocker toutes mes données de niveau dans un seul fichier au lieu de les répartir sur plusieurs fichiers?

8

Je génère actuellement mes données de niveau et j'enregistre sur le disque pour m'assurer que toutes les modifications apportées au niveau sont enregistrées.

Je stocke des "morceaux" de 2048x2048 pixels dans un fichier. Chaque fois que le joueur se déplace sur une section qui n'a pas de fichier associé à la position, un nouveau fichier est créé.

Cela fonctionne très bien et est très rapide. Mon problème, c'est que lorsque vous jouez, le nombre de fichiers augmente de plus en plus.

Je me demande quelles sont les techniques qui peuvent être utilisées pour réduire le nombre de fichiers, sans prendre un coup de performance. Je suis intéressé par la façon dont vous stockez / recherchez / mettez à jour ces données dans un seul fichier au lieu de plusieurs fichiers efficacement.

jgallant
la source
5
Il vous faudrait essentiellement écrire un système de fichiers miniature pour pouvoir tout stocker dans un seul fichier. Cela ajoutera à la complexité et n'en vaut peut-être pas la peine.
thedaian
1
Je n'ai pas vraiment beaucoup d'expérience avec ce qui suit, mais peut-être une base de données nosql basée sur des fichiers ( stackoverflow.com/questions/2403174/… ) pourrait être une option.
Chris
De combien de fichiers parle-t-on ici? Les joueurs génèrent-ils des dizaines de milliers de fichiers, ou seulement des centaines? Qu'est-ce que les joueurs changent dans le bloc? Le bloc génère-t-il une étape coûteuse (c.-à-d., Avez-vous besoin de mettre en cache le bloc entier contre juste un diff?)
Clémence
Minecraft est également passé par cette conversion. Je crois que cela a commencé comme un mod, puis a été intégré à la version principale. Ça vaut le coup. minecraftwiki.net/wiki/Region_file_format
MichaelHouse
1
@thedaian un peu plus de complexité mais vous pouvez faire des trucs sympas et vraiment réduire les temps de recherche si vous êtes prêt à travailler un peu plus en mémoire pour que le système de fichiers n'ait pas à le faire sur le disque.
ClassicThunder

Réponses:

7

Le moyen le plus rapide de le faire est de tout stocker dans un fichier et de déplacer le curseur sur le bloc que vous souhaitez lire. Une fois que vous frappez le disque en lisant une séquence, son point est assez rapide.

Les multiples hits vers différents INodes pour trouver l'emplacement du fichier sur le volume physique ce qui prend la plupart du temps et aussi ce qui évolue mal.

De plus, comme c'est dynamique, vous aurez également besoin d'une carte qui stocke le décalage dans le fichier pour chaque bloc.

Sur disque

[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]

Ensuite, il vous suffit d'ouvrir un flux qui lit à partir du fichier mais ne bloque pas l'accès à d'autres flux / processus. Ensuite, vous devez lire le décalage correct pour la bonne distance. Je crois qu'en C # c'est le dessous.

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

Maintenant, du fait que vous avez ouvert le flux en mode lecture seule et autorisez les autres à y lire / écrire, vous pouvez continuer à ajouter de nouveaux morceaux à la fin. Gardez simplement une trace de leur numéro de décalage et n'essayez pas de les lire avant qu'ils ne soient là.

PS vous n'allez pas vouloir utiliser le bloc using puisque vous ne voudrez qu'un seul flux de lecture à travers le cycle de vie que vous utilisez. De plus, vous devrez probablement enregistrer le mappage de morceaux dans un autre fichier à la sortie, mais ce n'est qu'une charge lorsque vous chargez votre niveau.

ClassicThunder
la source
Cela me donne de bonnes idées. Cette méthode vous obligerait-elle à écrire chaque bloc exactement le même nombre d'octets? J'imagine que la demande de compensation l'exigerait.
jgallant
Tant que vous avez le premier octet et la longueur de chaque bloc, ils ne doivent pas nécessairement être de taille égale. Il vous suffit d'avoir quelque chose en mémoire pour garder une trace de ces deux données.
ClassicThunder
1
Bien sûr, si vous ne les aviez pas de taille d'octet égale, vous auriez à faire beaucoup de changements si l'un devait croître en taille.
MichaelHouse
1

Selon le temps requis pour générer un morceau, vous pouvez simplement stocker des différences ou un état actuel (emplacements ennemis, etc.). Lorsque le joueur revient dans un bloc, il génère à nouveau en utilisant une graine stockée, puis charge toutes les modifications apportées à partir du fichier.

Si les joueurs sont autorisés à apporter des modifications importantes, cela peut être lent et le fichier diff sera toujours assez volumineux, mais pour de petites modifications, cela devrait être une opération peu coûteuse. Plusieurs différences de morceaux peuvent également être consolidées dans un seul fichier - quelque chose de taille raisonnable qui pourrait être chargé en mémoire.

Vous ne voudriez probablement pas déplacer tous les diffs dans un seul fichier - ce qui ouvre un certain nombre d'autres problèmes de mémoire ou de changer le milieu du fichier.

Clémence
la source
1

Je sais que c'est un fil assez ancien - mais j'aimerais juste carillon car je pense qu'une archive ZIP pourrait être le meilleur moyen d'aller ici. Vous obtenez la compression avec vos données (si vous utilisez des bitmaps bruts, en particulier), la lisibilité dans le système d'exploitation et vous obtenez le fichier unique comme vous le vouliez.

Vaughan Hilts
la source
0

Qu'en est-il d'un scan dir pour vérifier l'horodatage des fichiers dans le répertoire de données de niveau par rapport au fichier actif en cours et donner une grâce au fichier précédent et au fichier en cours toutes les 10 secondes environ, et tout ce qui n'est pas utilisé il suffit de les supprimer.

À moins que vous ne demandiez au joueur de revenir en arrière. Ensuite, nettoyez simplement les données de niveau à la fin du niveau ou au point de contrôle? Pourrait être grand à coup sûr, mais je ne pense pas qu'il existe de nombreuses options disponibles ici

ExpurgéProfil
la source
0

Que diriez-vous de plusieurs morceaux par fichier? Vous dites que vos morceaux sont de 2048 x 2048, que diriez-vous de mettre 16384 x 16384 dans un fichier. Indiquez ceux qui existent d'une manière ou d'une autre afin de savoir si vous devez les créer.

Loren Pechtel
la source
0

Si vous pouvez générer les morceaux assez rapidement pendant que le joueur explore de toute façon, alors vous n'avez pas du tout besoin de les mettre en cache sur le disque; tout ce que vous devez faire est de stocker la graine pour les fonctions de bruit perlin que vous utilisez pour générer à nouveau votre contenu procédural à la demande.

Ceux-ci peuvent être stockés dans un seul fichier, et peuvent être écrits séquentiellement et triés dans la RAM lorsqu'ils sont chargés; il n'y a pas besoin d'une structure triée compliquée dans le fichier lui-même sur le disque. Vous ne pouvez le lire qu'au démarrage et y écrire lorsque vous générez de nouvelles `` pages '' (comme on les appelle) dans le monde du jeu.

Volonté
la source