ここ数日、専用サーバーからゲーム サーバーをホストするプログラムの作成に費やしてきました。ユーザーは、どの WAD/PK3 (マップ情報、音楽などを保存するファイル)、その他いくつかのものを入力し、サーバーをホストできます。
WAD ファイルを調べて情報を収集するメソッドを作成した友人がいます。このメソッドは getLevelNames() を呼び出し、レベル名を配列で返します。それをサーバー ホストのコマンド ラインに追加し、適切なマップ。
これが私が重要だと思うコードの部分です:
public static byte[] getByteArrayFromFile(String filePath) throws IOException {
return Files.readAllBytes(new File(filePath).toPath());
}
/**
* Given a path to the file, this will extract the information into a byte array,
* and then it will read it, index the file locations and pass the appropriate byte
* data to other objects which will index the data in a useful way that the engine
* can read/use.
* Ideally after the data has been passed and indexed, the Wad object should be nullified and
* set for garbage collection.
* @param path The full path on the disk to the wad to be read from
* @throws IOException If the path to the file has an error
*/
public Wad(String path) throws IOException {
// Load wad data
wadData = ByteData.getByteArrayFromFile(path);
// Setup pointers
headerType = ByteData.bytesToString(Arrays.copyOfRange(wadData, 0, 4));
headerTotalLumps = ByteData.bytesToInt(wadData[4], wadData[5], wadData[6], wadData[7]);
headerPointerToDirectory = ByteData.bytesToInt(wadData[8], wadData[9], wadData[10], wadData[11]);
System.out.println("Wad data: " + headerType + ", " + headerTotalLumps + " total lumps, " + headerPointerToDirectory + " directory offset");
// Setup offset data
parseDirectory();
getLevelNames();
}
public void getLevelNames() {
String[] temp = new String[lumpName.length]; // Maybe I can divide this by 2, or 5 or something to save space since they all shouldn't be a map...
Arrays.fill(temp, "");
int tempIndex = 0;
List<String> listMapNames = Arrays.asList(lumpMapNames);
for (int i = 0; i < lumpName.length; i++)
// Make sure: 1) were not at an end piece, 2) its actually a marker, 3) the next lump contains a map file (like SEGS), 4) The marker itself isn't something like an empty reject table, 5) doesn't contain GL_xyzab
if (i != lumpName.length - 1 && fileSize[i] == 0 && listMapNames.contains(lumpName[i+1]) && !listMapNames.contains(lumpName[i]) && !lumpName[i].startsWith("GL_")) {
temp[tempIndex] = lumpName[i];
tempIndex++;
}
// If there's no levels
if (tempIndex == 0) {
levelNames = new String[0];
return;
}
levelNames = new String[tempIndex]; // We should be at levels + 1, or at least a proper length
for (int j = 0; j < tempIndex; j++)
levelNames[j] = temp[j];
// Sort the array just to make the server execution cleaner
Arrays.sort(levelNames);
}
private void parseDirectory() {
fileOffset = new int[headerTotalLumps];
fileSize = new int[headerTotalLumps];
lumpName = new String[headerTotalLumps];
int c = 0; // Counter for starting at index 0 and going upwards
System.out.println("Pointer: " + headerPointerToDirectory + ", total length: " + wadData.length + ", difference = " + (wadData.length - headerPointerToDirectory));
for (int off = headerPointerToDirectory; off < wadData.length; off += 16) {
fileOffset[c] = ByteData.bytesToInt(wadData[off], wadData[off+1], wadData[off+2], wadData[off+3]);
fileSize[c] = ByteData.bytesToInt(wadData[off+4], wadData[off+5], wadData[off+6], wadData[off+7]);
lumpName[c] = new String(Arrays.copyOfRange(wadData, off+8, off+16)).trim();
c++;
}
}
しかし、ジレンマに陥りました。PK3 ファイルは、基本的に、マップごとに個別の .WAD を maps/ ディレクトリに格納する .zip ファイルであるという点で完全に異なるため、それらにアクセスする方法がわかりません。
ファイル構造の例を次に示します。
- Level.pk3:
- 音楽
- マップ
- d2dm01.wad
- map01
- d2dm02.wad
- map02
- d2dm03.wad
- map03
- d2dm01.wad
- エクストラ
1つずつ抽出してforループでレベルをチェックせずに、pk3内のワッド内のファイルにアクセスする方法がわかりません。確かに、私も自分が何をしているのかわからないので、知りたいのは、pk3 内のファイルを読み取ってマップ (map01、map02、map03) を取得する方法です。
また、ファイル内のバイトを読み取って解析して情報を取得するための優れたリソースを誰かが知っていれば、それは本当に役に立ちます。私は今、かなり無知だと感じています。