internal static Stream InjectEnglishContainedVoice(Config config, FileFetcher _fc, string name, DuplicatableStream wstream, DuplicatableStream jstream, DuplicatableStream ustream, ContainedVoiceInfo cvi, SkitTexCache skitTexCache) { var fps4 = new HyoutaTools.Tales.Vesperia.FPS4.FPS4(wstream.Duplicate()); var se3stream = fps4.GetChildByIndex(cvi.SE3Index).AsFile.DataStream; var se3 = new HyoutaTools.Tales.Vesperia.SE3.SE3(se3stream.Duplicate(), EndianUtils.Endianness.BigEndian, TextUtils.GameTextEncoding.ASCII); var se3ms = se3.ExtractSe3HeaderStream(); var nubms = se3.ExtractNubStream(); var nubstream = new DuplicatableByteArrayStream(nubms.CopyToByteArrayAndDispose()); var newnubstream = RebuildNubStream(nubstream, Path.Combine(config.EnglishVoiceProcessingDir, "other"), cvi.WiiType, x => Path.GetFileNameWithoutExtension(name)); var newse3stream = new MemoryStream(); se3ms.Position = 0; newnubstream.Position = 0; StreamUtils.CopyStream(se3ms, newse3stream); StreamUtils.CopyStream(newnubstream, newse3stream); if (cvi.IsSkit) { using (var texIdStream = fps4.GetChildByIndex(3).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()) { int idx = 4; uint[] texIds = texIdStream.ReadUInt32Array(texIdStream.Length / 4, EndianUtils.Endianness.BigEndian); foreach (uint texId in texIds) { skitTexCache.AddTextureIfNotExists(texId, fps4.GetChildByIndex(idx).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()); ++idx; } } } newse3stream.Position = 0; MemoryStream newfps4stream = new MemoryStream(); using (var ufps4 = new HyoutaTools.Tales.Vesperia.FPS4.FPS4(ustream.Duplicate())) { uint[] utexIds = null; if (cvi.IsSkit) { using (var texIdStream = ufps4.GetChildByIndex(3).AsFile.DataStream.Duplicate().CopyToByteArrayStreamAndDispose()) { utexIds = texIdStream.ReadUInt32Array(texIdStream.Length / 4, EndianUtils.Endianness.BigEndian); } } List <HyoutaTools.Tales.Vesperia.FPS4.PackFileInfo> packFileInfos = new List <HyoutaTools.Tales.Vesperia.FPS4.PackFileInfo>(fps4.Files.Count); for (int i = 0; i < (cvi.IsSkit ? ufps4 : fps4).Files.Count - 1; ++i) { var pf = new HyoutaTools.Tales.Vesperia.FPS4.PackFileInfo(); pf.Name = (cvi.IsSkit ? ufps4 : fps4).Files[i].FileName; if (i == cvi.SE3Index) { pf.DataStream = new DuplicatableByteArrayStream(newse3stream.CopyToByteArrayAndDispose()); } else if (cvi.IsSkit && (i == 0 || i == 2 || i == 3)) { // copy over the actual skit script/timing from the EN version so the voice timing and lipsync matches with the skit pf.DataStream = ufps4.GetChildByIndex(i).AsFile.DataStream.Duplicate(); } else if (cvi.IsSkit && i >= 4) { uint texId = NormalizePs3SkitTextureIdForWii(utexIds[i - 4]); try { pf.DataStream = skitTexCache.GetTextureStream(texId); } catch (Exception ex) { Console.WriteLine("ERROR: Failed to get skit texture with ID 0x" + texId.ToString("x4")); Console.WriteLine(" tex name: " + new SkitTexCache.SkitTex() { Stream = ufps4.GetChildByIndex(i).AsFile.DataStream.Duplicate() }.ToString()); throw ex; } } else { pf.DataStream = fps4.GetChildByIndex(i).AsFile.DataStream.Duplicate(); } pf.Length = pf.DataStream.Length; packFileInfos.Add(pf); } packFileInfos = HyoutaTools.Tales.Vesperia.FPS4.FPS4.DetectDuplicates(packFileInfos); HyoutaTools.Tales.Vesperia.FPS4.FPS4.Pack(packFileInfos, newfps4stream, fps4.ContentBitmask, EndianUtils.Endianness.BigEndian, fps4.Unknown2, cvi.IsSkit ? null : wstream.Duplicate(), fps4.ArchiveName, fps4.FirstFileStart, 0x20); } //using (var fs = new FileStream(Path.Combine(@"c:\__graces\______fps4repacktest\", name.Replace("/", "_") + "_old.fps4"), FileMode.Create)) { // using (var wcpy = wstream.Duplicate()) { // wcpy.Position = 0; // StreamUtils.CopyStream(wcpy, fs); // } //} //using (var fs = new FileStream(Path.Combine(@"c:\__graces\______fps4repacktest\", name.Replace("/", "_") + "_new.fps4"), FileMode.Create)) { // newfps4stream.Position = 0; // StreamUtils.CopyStream(newfps4stream, fs); //} newfps4stream.Position = 0; return(newfps4stream); }
public static List <MemChunk> FindFreeMemoryInFontTexture(MemoryStream fontStream) { DuplicatableStream textureWiiStream = new DuplicatableByteArrayStream(fontStream.CopyToByteArray()); HyoutaTools.Tales.Vesperia.FPS4.FPS4 textureWiiFps4 = new HyoutaTools.Tales.Vesperia.FPS4.FPS4(textureWiiStream); HyoutaTools.Tales.Vesperia.Texture.TXM textureWiiTxm = new HyoutaTools.Tales.Vesperia.Texture.TXM(textureWiiFps4.GetChildByIndex(0).AsFile.DataStream); HyoutaTools.Tales.Vesperia.Texture.TXV textureWiiTxv = new HyoutaTools.Tales.Vesperia.Texture.TXV(textureWiiTxm, textureWiiFps4.GetChildByIndex(1).AsFile.DataStream, false); Bitmap bitmapWii = textureWiiTxv.textures[2].GetBitmaps()[0]; { for (int y = 0; y < bitmapWii.Height; ++y) { for (int x = 0; x < bitmapWii.Width; ++x) { Color color; switch (IdentifyPixel(x, y)) { case TileIdentification.UsedTile: color = Color.FromArgb(0, 255, 0); break; case TileIdentification.UnusedTile: color = Color.FromArgb(0, 0, 255); break; default: throw new Exception("???"); } bitmapWii.SetPixel(x, y, color); } } } var pxit = new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(bitmapWii.Width, bitmapWii.Height, 8, 8); MemoryStream stream = new MemoryStream(); byte storage = 0; bool even = false; foreach (var px in pxit) { if (px.X < bitmapWii.Width && px.Y < bitmapWii.Height) { Color col = bitmapWii.GetPixel(px.X, px.Y); bool pixelUnused = col.B > 0; var colidx = pixelUnused ? 0xF : 0x0; if (!even) { storage = (byte)colidx; } else { storage = (byte)(storage << 4 | (byte)colidx); stream.WriteByte(storage == 0xFF ? (byte)1 : (byte)0); } even = !even; } } List <MemChunk> chunks = new List <MemChunk>(); uint offset = textureWiiFps4.Files[1].Location.Value + textureWiiTxv.textures[2].TXM.TxvLocation; long len = stream.Length; long startOfLastSafeBlock = -1; var fontMapper = new FontMapper(0xE0000000 - textureWiiFps4.Files[1].Location.Value); stream.Position = 0; for (long i = 0; i <= len; ++i) { bool safeToWriteTo = i == len ? false : stream.ReadUInt8() == 1; if (safeToWriteTo && startOfLastSafeBlock == -1) { // start of block startOfLastSafeBlock = i; } else if (!safeToWriteTo && startOfLastSafeBlock != -1) { // end of block long start = startOfLastSafeBlock; long length = i - startOfLastSafeBlock; MemChunk mc = new MemChunk(); mc.Address = (uint)(start + offset); mc.FreeBytes = (uint)length; mc.File = fontStream; mc.Mapper = fontMapper; mc.IsInternal = false; chunks.Add(mc); startOfLastSafeBlock = -1; } } return(chunks); }
public static void Setup(Config config, string targetpath) { Directory.CreateDirectory(targetpath); var _fc = new FileFetcher(config); var rootW = _fc.TryGetContainer("rootR.cpk", Version.W); var rootU = _fc.TryGetContainer("rootR.cpk", Version.U); StringBuilder sb = new StringBuilder(); var defstreamW = rootW.GetChildByName("snd/init/StrConfig.stp").AsFile.DataStream; var defstreamU = rootU.GetChildByName("snd/init/StrConfig.stp").AsFile.DataStream; var defW = new SPKD(defstreamW); var defU = new SPKD(defstreamU); List <SPKD.SpkdPackFileData> defWPack = defW.GetPackData(); SHBP hashVobtletcU = null; iPck lipVobtletcU = null; NUB nubVobtletcU = null; foreach (NubInfo nubInfo in Nubs) { var hashStreamW = defW.GetChildByName(nubInfo.Name + ".1")?.AsFile.DataStream; var hashStreamU = defU.GetChildByName(nubInfo.Name + ".1")?.AsFile.DataStream; var lipStreamU = defU.GetChildByName(nubInfo.Name + ".2")?.AsFile.DataStream; DuplicatableStream lipStreamUDec = null; if (lipStreamU != null) { MemoryStream ms = new MemoryStream(); compto.complib.DecodeStream(lipStreamU, ms, 0, 0, true); lipStreamUDec = ms.CopyToByteArrayStreamAndDispose(); lipStreamUDec.Position = 0; } var nubStreamU = rootU.GetChildByName("snd/strpck/" + nubInfo.Name + ".nub").AsFile.DataStream; var hashW = hashStreamW != null ? new SHBP(hashStreamW) : null; var hashU = hashStreamU != null ? new SHBP(hashStreamU) : null; var lipU = lipStreamUDec != null ? new iPck(lipStreamUDec) : null; var nubU = new NUB(nubStreamU, EndianUtils.Endianness.BigEndian); if (nubInfo.Name == "VOBTLETC") { // the Wii VOBTL was split into two files VOBTL and VOBTLETC in PS3, so we need to do some stuff to put them back together hashVobtletcU = hashU; lipVobtletcU = lipU; nubVobtletcU = nubU; continue; } Console.WriteLine("Extracting files for " + nubInfo.Name + "..."); List <NubFileRef> filesToExtract = new List <NubFileRef>(); if (hashW != null && hashU != null) { Dictionary <uint, NubFileRef> hashToNubfileMap = new Dictionary <uint, NubFileRef>(); for (int i = 0; i < hashU.Hashes.Count; ++i) { uint hash = hashU.Hashes[i]; NubFileRef nfr = new NubFileRef() { Nub = nubU, Index = i, Lipsync = lipU.Data[i] }; if (hashToNubfileMap.ContainsKey(hash)) { throw new Exception("duplicate hash key"); } hashToNubfileMap.Add(hash, nfr); } if (nubInfo.Name == "VOBTL") { for (int i = 0; i < hashVobtletcU.Hashes.Count; ++i) { uint hash = hashVobtletcU.Hashes[i]; NubFileRef nfr = new NubFileRef() { Nub = nubVobtletcU, Index = i, Lipsync = lipVobtletcU.Data[i] }; if (hashToNubfileMap.ContainsKey(hash)) { throw new Exception("duplicate hash key"); } hashToNubfileMap.Add(hash, nfr); } } for (int i = 0; i < hashW.Hashes.Count; ++i) { uint hash = hashW.Hashes[i]; filesToExtract.Add(hashToNubfileMap[hash]); } } else { for (int i = 0; i < nubU.EntryCount; ++i) { filesToExtract.Add(new NubFileRef() { Nub = nubU, Index = i }); } } List <byte[]> lipData = lipU != null ? new List <byte[]>() : null; string dir = Path.Combine(targetpath, nubInfo.Name); Directory.CreateDirectory(dir); for (int i = 0; i < filesToExtract.Count; ++i) { var nfr = filesToExtract[i]; if (lipData != null) { lipData.Add(nfr.Lipsync); } using (var audiofilestream = nfr.Nub.GetChildByIndex(nfr.Index).AsFile.DataStream.Duplicate()) { string path = Path.Combine(dir, string.Format("{0:D8}.{1}", i, nubInfo.EngType)); using (var fs = new FileStream(path, FileMode.Create)) { audiofilestream.Position = 0; StreamUtils.CopyStream(audiofilestream, fs); } } GenerateConversion(sb, nubInfo.Name, i.ToString("D8"), nubInfo.EngType, nubInfo.WiiType, nubInfo.WiiSampleRate); } if (lipData != null) { using (var newlipstream = new iPck(lipData).WriteToStream(EndianUtils.Endianness.BigEndian)) { newlipstream.Position = 0; using (MemoryStream ms = new MemoryStream()) { compto.complib.EncodeStream(newlipstream, ms, 0, 1, true); defWPack.First(x => x.Name == nubInfo.Name).File2 = ms.CopyToByteArrayStreamAndDispose(); } } } } using (var newspkd = SPKD.Pack(defWPack)) using (var fs = new FileStream(Path.Combine(targetpath, "StrConfig.stp"), FileMode.Create)) { newspkd.Position = 0; StreamUtils.CopyStream(newspkd, fs); } string otherdir = Path.Combine(targetpath, "other"); Directory.CreateDirectory(otherdir); foreach (var cvi in ContainedVoices) { for (int i = cvi.StartNumber; i <= cvi.EndNumber; ++i) { string path = string.Format(cvi.BaseName, i); Console.WriteLine("Extracting " + path + "..."); string fname = Path.GetFileNameWithoutExtension(path); var fps4stream = rootU.GetChildByName(path).AsFile.DataStream; var fps4 = new HyoutaTools.Tales.Vesperia.FPS4.FPS4(fps4stream); var se3stream = fps4.GetChildByIndex(cvi.SE3Index).AsFile.DataStream; var ms = new HyoutaTools.Tales.Vesperia.SE3.SE3(se3stream.Duplicate(), EndianUtils.Endianness.BigEndian, TextUtils.GameTextEncoding.ASCII).ExtractNubStream(); var nub = new NUB(ms.CopyToByteArrayStreamAndDispose(), EndianUtils.Endianness.BigEndian); using (var audiofilestream = nub.GetChildByIndex(0).AsFile.DataStream.Duplicate()) { string otherpath = Path.Combine(otherdir, string.Format("{0}.{1}", fname, cvi.EngType)); using (var fs = new FileStream(otherpath, FileMode.Create)) { audiofilestream.Position = 0; StreamUtils.CopyStream(audiofilestream, fs); } } GenerateConversion(sb, "other", fname, cvi.EngType, cvi.WiiType, cvi.WiiSampleRate); } } File.WriteAllText(Path.Combine(targetpath, "convert_voices.bat"), sb.ToString()); return; }