Wie kann ich alle meine Level-Daten in einer einzigen Datei speichern, anstatt sie auf viele Dateien zu verteilen?

8

Ich generiere derzeit meine Level-Daten und speichere sie auf der Festplatte, um sicherzustellen, dass alle am Level vorgenommenen Änderungen gespeichert werden.

Ich speichere "Chunks" von 2048x2048 Pixel in einer Datei. Immer wenn sich der Spieler über einen Abschnitt bewegt, dem keine Position zugeordnet ist, wird eine neue Datei erstellt.

Das funktioniert super und ist sehr schnell. Mein Problem ist, dass beim Spielen die Anzahl der Dateien immer größer wird.

Ich frage mich, welche Techniken verwendet werden können, um die Anzahl der Dateien zu verringern, ohne einen Leistungseinbruch zu erleiden. Ich bin daran interessiert, wie Sie diese Daten in einer einzigen Datei anstatt in mehreren Dateien effizient speichern / suchen / aktualisieren würden.

jgallant
quelle
5
Grundsätzlich müsste man ein Miniatur-Dateisystem schreiben, um alles in einer einzigen Datei speichern zu können. Dies erhöht die Komplexität und ist es möglicherweise nicht wert.
Thedaian
1
Ich habe nicht wirklich viel Erfahrung mit dem Folgenden, aber vielleicht könnte eine dateibasierte nosql-Datenbank ( stackoverflow.com/questions/2403174/… ) eine Option sein.
Chris
Über wie viele Dateien sprechen wir hier? Generieren Spieler Zehntausende von Dateien oder nur Hunderte? Was ändern die Spieler im Block? Ist Chunk ein teurer Schritt (dh müssen Sie den gesamten Chunk gegen nur einen Unterschied zwischenspeichern?)
Leniency
Minecraft hat diese Konvertierung auch irgendwann durchlaufen. Ich glaube, es begann als Mod und wurde dann in den Haupt-Build integriert. Ein Blick wert. minecraftwiki.net/wiki/Region_file_format
MichaelHouse
1
@thedaian etwas komplexer, aber Sie können einige coole Sachen machen und die Suchzeiten wirklich verkürzen, wenn Sie bereit sind, zusätzliche Arbeit im Speicher zu leisten, damit das Dateisystem dies nicht auf der Festplatte tun muss.
ClassicThunder

Antworten:

7

Der schnellste Weg, dies zu tun, besteht darin, alles in einer Datei zu speichern und den Cursor auf den Block zu bewegen, den Sie lesen möchten. Sobald Sie auf die Festplatte drücken und eine Sequenz von dieser lesen, ist sein Punkt ziemlich schnell.

Die mehrfachen Treffer auf verschiedene INodes, um den Speicherort der Datei auf dem physischen Volume zu finden, nehmen die meiste Zeit in Anspruch und auch die Skalierung ist schlecht.

Da dies dynamisch ist, benötigen Sie auch eine Karte, in der der Versatz in der Datei für jeden Block gespeichert ist.

Auf der Festplatte

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

Sichtbar

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

Dann müssen Sie nur noch einen Stream öffnen, der aus der Datei liest, andere Streams / Prozesse jedoch nicht daran hindert, darauf zuzugreifen. Dann müssen Sie aus dem richtigen Versatz für den richtigen Abstand lesen. Ich glaube an C #, es ist das Folgende.

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

Aufgrund der Tatsache, dass Sie den Stream im schreibgeschützten Modus geöffnet haben und anderen das Lesen / Schreiben erlauben, können Sie am Ende immer wieder neue Blöcke hinzufügen. Behalten Sie einfach ihre Versatznummer im Auge und versuchen Sie nicht, sie zu lesen, bevor sie dort sind.

PS: Sie möchten den using-Block nicht verwenden, da Sie nur einen Lesestream über die gesamte Lebensdauer des von Ihnen verwendeten Levels benötigen. Außerdem müssen Sie wahrscheinlich die Chunk-Zuordnung beim Beenden in einer anderen Datei speichern, aber das ist nur eine Ladung, wenn Sie Ihr Level laden.

ClassicThunder
quelle
Das gibt mir einige großartige Ideen. Würde diese Methode erfordern, dass Sie jedem Block genau die gleiche Anzahl von Bytes schreiben? Ich würde mir vorstellen, wie die Offset-Suche es erfordern würde.
Jgallant
Solange Sie das erste Byte haben und wie lang jeder Block ist, müssen sie nicht gleich groß sein. Sie müssen nur etwas im Speicher haben, um diese beiden Daten zu verfolgen.
ClassicThunder
1
Wenn Sie nicht die gleiche Bytegröße hätten, müssten Sie natürlich viel verschieben, wenn die Größe zunehmen soll.
MichaelHouse
1

Abhängig von der Zeit, die zum Generieren eines Blocks erforderlich ist, können Sie nur Unterschiede oder einen aktuellen Status (feindliche Standorte usw.) speichern. Wenn der Player in einen Block zurückkehrt, generiert er erneut einen gespeicherten Startwert und lädt dann alle Änderungen, die an der Datei vorgenommen wurden.

Wenn Spieler signifikante Änderungen vornehmen dürfen, kann dies langsam sein und die Diff-Datei wird immer noch ziemlich groß sein, aber für nur kleine Änderungen sollte dies eine kostengünstige Operation sein. Mehrere Chunk-Diffs könnten auch in einer einzigen Datei zusammengefasst werden - eine vernünftige Größe, die in den Speicher geladen werden könnte.

Sie möchten wahrscheinlich nicht alle Unterschiede in eine einzige Datei verschieben - dies führt zu einer Reihe anderer Probleme mit dem Speicher oder zum Ändern der Mitte der Datei.

Nachsicht
quelle
1

Ich weiß, dass dies ein ziemlich alter Thread ist - aber ich möchte nur darauf hinweisen, dass ein ZIP-Archiv der beste Weg ist, um hierher zu gelangen. Sie erhalten eine Komprimierung Ihrer Daten (insbesondere wenn Sie unformatierte Bitmaps verwenden), Lesbarkeit im Betriebssystem und erhalten die einzelne Datei wie gewünscht.

Vaughan Hilts
quelle
0

Was ist mit einem Dir-Scan, um den Zeitstempel der Dateien im Level-Datenverzeichnis im Vergleich zur aktuell aktiven Datei zu überprüfen und die vorherige Datei und die Datei, die etwa alle 10 Sekunden vorwärts geht, und was auch immer nicht verwendet wird, zu bewerten lösche sie einfach.

Es sei denn, der Spieler muss zurück. Bereinigen Sie dann einfach die Level-Daten nach Abschluss des Levels oder nach dem Checkpoint? Könnte sicher groß werden, aber ich glaube nicht, dass hier viele Optionen verfügbar sind

RedactedProfile
quelle
0

Wie wäre es mit mehreren Chunks pro Datei? Sie sagen, Ihre Chunks sind 2048 x 2048, wie wäre es, wenn Sie 16384 x 16384 in eine Datei einfügen. Markieren Sie, welche irgendwie vorhanden sind, damit Sie wissen, ob Sie sie erstellen müssen.

Loren Pechtel
quelle
0

Wenn Sie die Chunks schnell genug generieren können, während der Player sie trotzdem erforscht, müssen Sie sie überhaupt nicht auf der Festplatte zwischenspeichern. Alles, was Sie tun müssen, ist, den Startwert für die Perlin-Rauschfunktionen zu speichern, die Sie verwenden, um Ihren prozeduralen Inhalt bei Bedarf erneut zu generieren.

Diese können in einer einzelnen Datei gespeichert und beim Laden nacheinander geschrieben und im RAM sortiert werden. Es ist keine komplizierte sortierte Struktur in der Datei selbst auf der Festplatte erforderlich. Sie können nur beim Start davon lesen und darauf schreiben, während Sie neue "Seiten" (wie sie genannt werden) in der Spielwelt generieren.

Wille
quelle