const fs = require('fs'); const execFile = require('child_process').execFile; const path = require('path'); const rimraf = require('rimraf'); rimraf.sync('tmp'); const mkdirp = require('mkdirp'); mkdirp.sync('tmp'); mkdirp.sync('mogg_input'); mkdirp.sync('mogg_output'); mkdirp.sync('game_input'); mkdirp.sync('game_output'); const fileExists = async path => !!(await fs.promises.stat(path).catch(e => false)); const readFile = async path => await fs.promises.readFile(path); async function moggify() { const files = await fs.promises.readdir('mogg_input'); for(const file of files) { console.log(file); const from = path.join('mogg_input', file); const tmp = path.join('tmp', path.parse(file).name + '.mogg'); const to = path.join('mogg_output', path.parse(file).name + '.mogg'); await new Promise(resolve => { execFile('ogg2mogg.exe', [from, tmp], () => { execFile('MoggcryptCpp.exe', [tmp, '-e', to], () => { resolve(); }); }); }) } } async function replace() { if (process.argv.length !== 4) { console.error('Usage: node replace.js '); console.log('(No file extensions)'); return; } const mogg_file = process.argv[2] + '.mogg'; const game_file = process.argv[3]; const mogg_exists = await fileExists(`mogg_output/${mogg_file}`); const uexp_exists = await fileExists(`game_input/${game_file}.uexp`); const uasset_exists = await fileExists(`game_input/${game_file}.uasset`); if (!mogg_exists) { console.error(`Couldn't find the .mogg file '${mogg_file}'.`); return; } if (!uexp_exists || !uasset_exists) { console.error(`Couldn't find a .uexp and .uasset combo for '${game_file}'.`); return; } const out_uexp = path.join('game_output', game_file + '.uexp'); const out_uasset = path.join('game_output', game_file + '.uasset'); // Read .mogg const mogg_buffer = await readFile(`mogg_output/${mogg_file}`); console.log('Mogg', mogg_buffer); // Modify .uexp const data_buffer = await readFile(`game_input/${game_file}.uexp`); const old_uexp_length = data_buffer.length; const start_offset = data_buffer.indexOf('MoggSampleResource') + 19; console.log('uexp', data_buffer); console.log('uexp length', old_uexp_length); // Write new MOGG Buffer length + 32 to offset start_offset data_buffer.writeInt32LE(mogg_buffer.length + 32, start_offset); // Write new MOGG Buffer length to offset start_offset + 36, store old for buffering const old_1_length = data_buffer.readInt32LE(start_offset + 36); console.log("Old 1 length", old_1_length); data_buffer.writeInt32LE(mogg_buffer.length, start_offset + 36); console.log("New 1 length", data_buffer.readInt32LE(start_offset + 36)); // Insert MOGG at start_offset + 36 + 4, then offset to the new position const pre_buffer_1 = data_buffer.slice(0, start_offset + 36 + 4); const post_buffer_1 = data_buffer.slice(start_offset + 36 + 4 + old_1_length); // Concat buffers const song_1_insert_buffer = Buffer.concat([pre_buffer_1, mogg_buffer, post_buffer_1]); // Only replace 2nd MoggSampleResource if numResourceFiles === 3 let final_buffer = song_1_insert_buffer; const filenameLength = final_buffer.readInt16LE(28); const numResourceFiles = final_buffer.readInt16LE(28 + filenameLength + 12); console.log(final_buffer.length); if (numResourceFiles === 3) { const new_offset = song_1_insert_buffer.indexOf('MoggSampleResource', mogg_buffer.length) + 19; console.log("New Offset", new_offset); console.log("InsertBufferLength", song_1_insert_buffer.length); // Write new MOGG Buffer length + 32 to offset new_offset song_1_insert_buffer.writeInt32LE(mogg_buffer.length + 32, new_offset); // Write new MOGG Buffer length to offset new_offset + 36, store old for buffering const old_2_length = song_1_insert_buffer.readInt32LE(new_offset + 36); console.log("Old 2 length", old_2_length); song_1_insert_buffer.writeInt32LE(mogg_buffer.length, new_offset + 36); console.log("New 2 length", song_1_insert_buffer.readInt32LE(new_offset + 36)); // Insert MOGG at new_offset + 36 + 4, then offset to the new position const pre_buffer_2 = song_1_insert_buffer.slice(0, new_offset + 36 + 4); const post_buffer_2 = song_1_insert_buffer.slice(new_offset + 36 + 4 + old_2_length); // Concat buffers final_buffer = Buffer.concat([pre_buffer_2, mogg_buffer, post_buffer_2]); } // Finally, write await fs.promises.writeFile(out_uexp, final_buffer); // Modify .uasset const uasset_buffer = await readFile(`game_input/${game_file}.uasset`); console.log('Uassetbuffer', uasset_buffer); const update_size_offset = uasset_buffer.lastIndexOf(old_uexp_length - 4); console.log("Update size offset", update_size_offset); uasset_buffer.writeInt32LE(final_buffer.length - 4, update_size_offset); // Finally, write await fs.promises.writeFile(out_uasset, uasset_buffer); } moggify().then(replace);