レベルデータをすべて複数のファイルに分散するのではなく、1つのファイルに保存するにはどうすればよいですか?


8

現在、レベルデータを生成しています。レベルに加えられた変更が確実に保存されるように、ディスクに保存しています。

2048x2048ピクセルの「チャンク」をファイルに保存しています。位置に関連付けられたファイルがないセクションにプレーヤーが移動するたびに、新しいファイルが作成されます。

これはうまく機能し、非常に高速です。私の問題は、再生しているとファイル数がどんどん大きくなることです。

パフォーマンスに影響を与えることなく、ファイル数を減らすために使用できるテクニックは何でしょうか。このデータを複数のファイルではなく単一のファイルに効率的に保存/検索/更新する方法に興味があります。


5
基本的に、すべてを1つのファイルに格納できるように、ミニチュアファイルシステムを作成する必要があります。それは複雑さを増し、価値がないかもしれません。
thedaian 2012年

1
私は以下についてはあまり経験がありませんが、おそらくファイルベースのnosql db(stackoverflow.com/questions/2403174/…)がオプションになるでしょう。
Chris

ここではいくつのファイルについて話しているのですか?プレーヤーは何万ものファイルを生成していますか、それとも何百ものファイルを生成していますか?チャンクでプレーヤーは何を変更しますか?チャンクは高価なステップを生成しますか(つまり、チャンク全体をキャッシュする必要があるか、差分だけをキャッシュする必要がありますか?)
Leniency

Minecraftもある時点でこの変換を行いました。私はそれがmodとして始まり、その後メインビルドに組み込まれたと信じています。見る価値があります。minecraftwiki.net/wiki/Region_file_format
MichaelHouse

1
@thedaianはもう少し複雑ですが、メモリ内の追加の作業に進んでファイルシステムがディスク上で実行する必要がない場合は、いくつかの素晴らしいことを実行してシーク時間を実際に短縮できます。
ClassicThunder 2012年

回答:


7

これを行う最も速い方法は、すべてを1つのファイルに格納し、読み取りたいチャンクにカーソルをジャンプすることです。ディスクを叩くと、それからシーケンスを読み取り、彼のポイントはかなり高速です。

物理ボリューム上のファイルの場所を見つけるためのさまざまなINodeへの複数のヒットは、ほとんどの時間を要し、スケーリングも不十分です。

また、これは動的であるため、各チャンクのオフセットをファイルに保存するマップも必要になります。

ディスク上

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

目に見える

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

次に、ファイルから読み取るストリームを開く必要がありますが、他のストリーム/プロセスがアクセスできないようにロックしません。次に、正しい距離の正しいオフセットから読み取る必要があります。私はC#を信じています、それは以下です。

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

ストリームを読み取り専用モードで開き、他のユーザーに読み取り/書き込みを許可したため、最後に新しいチャンクを追加し続けることができます。それらのオフセット番号を追跡し、それらが存在する前にそれらを読み取ろうとしないでください。

PSは、使用しているレベルのライフを通じて1つの読み取りストリームのみを必要とするため、usingブロックを使用する必要はありません。また、終了時にチャンクマッピングを別のファイルに保存する必要があるかもしれませんが、これはレベルをロードするときの1回のロードにすぎません。


これは私にいくつかの素晴らしいアイデアを与えています。この方法では、各チャンクに正確に同じバイト数を書き込む必要がありますか?オフセットシークにはそれが必要になるので、私は想像します。
jgallant 2012年

最初のバイトがあり、各チャンクの長さが同じである限り、それらは同じサイズである必要はありません。あなたは、メモリに何かがこれらの2つのデータを追跡する必要があります。
ClassicThunder 2012年

1
もちろん、それらのバイトサイズが同じでない場合、サイズが大きくなると、多くのシフトを実行する必要があります。
MichaelHouse

1

チャンクを生成するために必要な時間に応じて、差分または現在の状態(敵の場所など)を格納することができます。プレーヤーがチャンクに戻ると、格納されているシードを使用して再度生成され、ファイルから加えられた変更が読み込まれます。

プレーヤーが大幅な変更を行うことが許可されている場合、これは遅くなる可能性があり、diffファイルはかなり大きくなりますが、小さな変更のみの場合は、安価な操作である必要があります。複数のチャンクのdiffを1つのファイルに統合することもできます。これは、メモリにロードできる適切なサイズのファイルです。

ただし、すべてのdiffを1つのファイルに移動したくない場合もあります。これにより、メモリに関する他の多くの問題が発生したり、ファイルの中央が変更されたりします。


1

私はこれがかなり古いスレッドであることを知っていますが、ZIPアーカイブがここにアクセスするための最良の方法であると私は思います。データの圧縮(特に未加工のビットマップを使用している場合)、オペレーティングシステムの可読性、および必要に応じて単一のファイルを取得します。


0

レベルデータディレクトリ内のファイルと現在のアクティブファイルのタイムスタンプをチェックし、前のファイルと10秒ごとに転送されるファイル、および使用されていないものの猶予を与えるdirスキャンについてはどうですか削除してください。

プレーヤーに戻る必要がない限り。次に、レベルの完了時またはチェックポイント時にレベルデータをクリーンアップしますか?確かに大きくなるかもしれませんが、ここには多くのオプションがあるとは思いません


0

ファイルごとに複数のチャンクはどうですか?あなたのチャンクは2048 x 2048であると言いますが、16384 x 16384をファイルに入れるのはどうでしょう。存在するものにフラグを付けて、作成する必要があるかどうかを確認します。


0

プレーヤーがとにかく探索するのに十分な速さでチャンクを生成できれば、ディスクにキャッシュする必要はまったくありません。必要なのは、必要に応じて手続き型コンテンツを再度生成するために使用しているperlinノイズ関数のシードを保存することだけです。

これらは単一のファイルに格納でき、順次に書き込み、ロード時にRAMにソートできます。ディスク上のファイル自体に複雑なソート構造が必要ない。起動時にのみ読み取り、ゲームの世界で新しい(ページと呼ばれる)ページを生成するときに書き込むことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.