private static void GenerateUndubMap01(string datadir, string voicedir, string outdir, string mapcpkname, SubcpkInjectData[] injects) { Console.WriteLine(string.Format("processing {0}", mapcpkname)); var datastream = new DuplicatableFileStream(Path.Combine(datadir, mapcpkname)); var voicestream = new DuplicatableFileStream(Path.Combine(voicedir, mapcpkname)); var datacpk = new HyoutaTools.Tales.CPK.CpkContainer(datastream.Duplicate()); var voicecpk = new HyoutaTools.Tales.CPK.CpkContainer(voicestream); string outfile = Path.Combine(outdir, mapcpkname); var builder = new HyoutaTools.Tales.CPK.CpkBuilder(datastream.Duplicate()); foreach (var subdata in injects) { var subbuilder = new HyoutaTools.Tales.CPK.CpkBuilder(datacpk.GetChildByName(subdata.Name).AsFile.DataStream); var subvoicecpk = new HyoutaTools.Tales.CPK.CpkContainer(voicecpk.GetChildByName(subdata.Name).AsFile.DataStream); foreach (string subpath in subdata.Subpaths) { Console.WriteLine(string.Format("injecting {0}/{1}", subdata.Name, subpath)); var subvoicestream = subvoicecpk.GetChildByName(subpath).AsFile.DataStream.Duplicate(); var subfile = subbuilder.Files.Where(x => (x.Directory + "/" + x.Name) == subpath).First(); ReplaceFile(subfile, subvoicestream.CopyToByteArrayStreamAndDispose()); } MemoryStream subbuild = new MemoryStream(); subbuilder.Build(subbuild); var file = builder.Files.Where(x => x.Name == subdata.Name).First(); ReplaceFile(file, subbuild.CopyToByteArrayStreamAndDispose()); } CreateDirectory(outdir); WriteCpk(outfile, builder); }
private static void WriteCpk(string outfile, HyoutaTools.Tales.CPK.CpkBuilder cpk) { Console.WriteLine(string.Format("writing {0}", outfile)); using (var fs = new FileStream(outfile, FileMode.Create)) { cpk.Build(fs); // ToGf is buggy and fails to boot if bit 31 of the file length is set // (probably something somewhere is interpreted incorrectly as a signed 32 bit integer) // so work around that long length = fs.Length; if ((length % 0x100000000L) >= 0x80000000L) { fs.WriteAlign(0x80000000L); } } }
private static void GenerateUndubRoot(string datadir, string voicedir, string outdir, UndubVersion undubVersion) { Console.WriteLine(string.Format("processing {0}", "rootR.cpk")); var datastream = new DuplicatableFileStream(Path.Combine(datadir, "rootR.cpk")); var voicestream = new DuplicatableFileStream(Path.Combine(voicedir, "rootR.cpk")); var datacpk = new HyoutaTools.Tales.CPK.CpkContainer(datastream.Duplicate()); var voicecpk = new HyoutaTools.Tales.CPK.CpkContainer(voicestream); string outfile = Path.Combine(outdir, "rootR.cpk"); var builder = new HyoutaTools.Tales.CPK.CpkBuilder(datastream.Duplicate()); // audio containers: we can direct-copy these, no need to un/repack foreach (string name in new string[] { "RTS.nub", "VOBTL.nub", "VOBTLETC.nub", "VOCHT.nub", "VOSCE01.nub", "VOSCE02.nub", "VOSCE03.nub", "VOSCE04.nub", "VOSCE05.nub", "VOSCE06.nub", "VOSCE07.nub", "VOSCE08.nub", "VOSCE09.nub", "VOSCE15.nub", "VOSCE16.nub" }) { string subdir = "snd/strpck"; string subpath = subdir + "/" + name; Console.WriteLine(string.Format("injecting {0}", subpath)); var subfile = builder.Files.Where(x => x.Directory == subdir && x.Name == name).First(); ReplaceFile(subfile, voicecpk.GetChildByName(subpath).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()); } // skits: for all of these unpack them (FPS4 containers), copy over file with index 1, repack // some of them are mistimed now because of altered timing for english skits, this could be refined... for (long i = 0; i < datacpk.toc_entries; ++i) { var entry = datacpk.GetEntryByIndex(i); if (entry != null && entry.dir_name == "chat/chd" && entry.file_name.EndsWith(".chd") && entry.file_name != "debug_02.chd") { // for EU undub also exclude CHT_PR*.chd because those files are not on the EU disc (they look unused on US too...) if (!(undubVersion == UndubVersion.JpVoicesToEu && entry.file_name.StartsWith("CHT_PR"))) { string subpath = entry.dir_name + "/" + entry.file_name; Console.WriteLine(string.Format("injecting {0}", subpath)); var skitstreamen = datacpk.GetChildByIndex(i).AsFile.DataStream; var skitstreamjp = voicecpk.GetChildByName(subpath).AsFile.DataStream; var fps4en = new FPS4(skitstreamen); var fps4jp = new FPS4(skitstreamjp); List <PackFileInfo> packFileInfos = new List <PackFileInfo>(fps4en.Files.Count - 1); for (int j = 0; j < fps4en.Files.Count - 1; ++j) { var pf = new PackFileInfo(); pf.Name = fps4en.Files[j].FileName; if (j == 1) { pf.DataStream = fps4jp.GetChildByIndex(j).AsFile.DataStream.Duplicate(); } else { pf.DataStream = fps4en.GetChildByIndex(j).AsFile.DataStream.Duplicate(); } pf.Length = pf.DataStream.Length; packFileInfos.Add(pf); } packFileInfos = FPS4.DetectDuplicates(packFileInfos); MemoryStream newfps4stream = new MemoryStream(); FPS4.Pack(packFileInfos, newfps4stream, fps4en.ContentBitmask, EndianUtils.Endianness.BigEndian, fps4en.Unknown2, null, fps4en.ArchiveName, fps4en.FirstFileStart, 0x20); newfps4stream.Position = 0; var subfile = builder.Files.Where(x => x.Directory == entry.dir_name && x.Name == entry.file_name).First(); ReplaceFile(subfile, newfps4stream.CopyToByteArrayStreamAndDispose(), true); } } } // post-battle skits/quotes for (long i = 0; i < datacpk.toc_entries; ++i) { var entry = datacpk.GetEntryByIndex(i); if (entry != null && entry.dir_name == "btl/acf" && ( (entry.file_name.StartsWith("skt") && entry.file_name.EndsWith(".acf") && entry.file_name != "skt000.acf") || (entry.file_name.StartsWith("vav") && entry.file_name.EndsWith(".acf") && entry.file_name != "vav000.acf") )) { string subpath = entry.dir_name + "/" + entry.file_name; Console.WriteLine(string.Format("injecting {0}", subpath)); var subfile = builder.Files.Where(x => x.Directory == entry.dir_name && x.Name == entry.file_name).First(); ReplaceFile(subfile, voicecpk.GetChildByName(subpath).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()); } } CreateDirectory(outdir); WriteCpk(outfile, builder); }