( packsData: Pack[], path: string, enabledMods: Mod[], startGameOptions: StartGameOptions, )
| 2142 | } |
| 2143 | }; |
| 2144 | export const writeStartGamePack = async ( |
| 2145 | packsData: Pack[], |
| 2146 | path: string, |
| 2147 | enabledMods: Mod[], |
| 2148 | startGameOptions: StartGameOptions, |
| 2149 | ) => { |
| 2150 | let outFile: BinaryFile | undefined; |
| 2151 | try { |
| 2152 | const header = gameToPackHeader[appData.currentGame]; |
| 2153 | const byteMask = 3; |
| 2154 | const refFileCount = 0; |
| 2155 | const pack_file_index_size = 0; |
| 2156 | const packFiles: PackedFile[] = []; |
| 2157 | if (startGameOptions.isMakeUnitsGeneralsEnabled) |
| 2158 | createBattlePermissionsData(packsData, packFiles, enabledMods); |
| 2159 | if (startGameOptions.isSkipIntroMoviesEnabled) createIntroMoviesData(packFiles); |
| 2160 | if (startGameOptions.isScriptLoggingEnabled) createScriptLoggingData(packFiles); |
| 2161 | if (startGameOptions.isAutoStartCustomBattleEnabled) createAutoStartCustomBattleData(packFiles); |
| 2162 | if (packFiles.length < 1) return; |
| 2163 | outFile = new BinaryFile(path, "w", true); |
| 2164 | await outFile.open(); |
| 2165 | const index_size = packFiles.reduce((acc, pack) => acc + new Blob([pack.name]).size + 1 + 5, 0); |
| 2166 | // Use BufferAccumulator to batch header writes |
| 2167 | const startGameHeaderAccumulator = new BufferAccumulator(outFile); |
| 2168 | startGameHeaderAccumulator.addString(header); |
| 2169 | startGameHeaderAccumulator.addInt32(byteMask); |
| 2170 | startGameHeaderAccumulator.addInt32(refFileCount); |
| 2171 | startGameHeaderAccumulator.addInt32(pack_file_index_size); |
| 2172 | startGameHeaderAccumulator.addInt32(packFiles.length); |
| 2173 | startGameHeaderAccumulator.addInt32(index_size); |
| 2174 | startGameHeaderAccumulator.addInt32(0x7fffffff); // header_buffer |
| 2175 | await startGameHeaderAccumulator.flush(); |
| 2176 | // Use BufferAccumulator to batch file index writes |
| 2177 | const startGameIndexAccumulator = new BufferAccumulator(outFile); |
| 2178 | for (const packFile of packFiles) { |
| 2179 | const { name, file_size } = packFile; |
| 2180 | // console.log("file size is " + file_size); |
| 2181 | startGameIndexAccumulator.addInt32(file_size); |
| 2182 | if (supportsCompression[appData.currentGame]) startGameIndexAccumulator.addInt8(0); // is_compressed |
| 2183 | startGameIndexAccumulator.addString(name + "\0"); |
| 2184 | // Flush periodically to avoid excessive memory usage |
| 2185 | await startGameIndexAccumulator.flushIfNeeded(); |
| 2186 | } |
| 2187 | await startGameIndexAccumulator.flush(); |
| 2188 | for (const packFile of packFiles) { |
| 2189 | if (!packFile.schemaFields) continue; |
| 2190 | if (packFile.guid != null) { |
| 2191 | const guid = packFile.guid; |
| 2192 | // console.log("guid is " + guid); |
| 2193 | await outFile.write(Buffer.from([0xfd, 0xfe, 0xfc, 0xff])); // guid marker |
| 2194 | await outFile.writeInt16(guid.length); |
| 2195 | const twoByteGUID = guid |
| 2196 | .split("") |
| 2197 | .map((str) => str + "\0") |
| 2198 | .join(""); |
| 2199 | // console.log(twoByteGUID); |
| 2200 | await outFile.write(Buffer.from(twoByteGUID, "utf-8")); |
| 2201 | } |
no test coverage detected