public void Access(string Path, Action Action, int RecompressVersion = -1) { if (Path.Contains('/')) { var Parts = Path.Split(new[] { '/' }, 2); Access(Parts[0], () => { Access(Parts[1], Action); }); return; } GetFile(Path, (CompressedStream) => { DecompressAndRecompressIfRequired(CompressedStream, (UncompressedStream) => { var Magic = UncompressedStream.Slice().ReadBytesUpTo(0x100); if (FPS4.IsValid(Magic)) { LanguageUtils.LocalSet(ref this.FileSystem, new FPS4FileSystem(UncompressedStream), Action); } else if (TO8SCEL.IsValid(Magic)) { LanguageUtils.LocalSet(ref this.FileSystem, new TO8SCELFileSystem(UncompressedStream), Action); } else { throw (new InvalidOperationException(String.Format("Can't access '{0}'", Path))); } }, RecompressVersion); }, RecompressVersion); }
public void RepackBtlPack() { //var OldFps4 = new FPS4(OldStream.Slice()); //var NewFps4 = new FPS4(OldStream.Slice()); // Intended OldStream Patcher.Action("Packing BTL_PACK_ES.DAT", () => { Patcher.TempFS.OpenFileReadScope("BTL_PACK_UK.DAT", (OldStream) => { Patcher.TempFS.OpenFileCreateScope("BTL_PACK_ES.DAT", (NewStream) => { var OldFps4 = new FPS4(OldStream.Slice()); var NewFps4 = new FPS4(OldStream.Slice()); // Intended OldStream NewFps4.ClearAllEntries(); for (int n = 0; n <= 19; n++) { NewFps4.CreateEntry(String.Format("{0}", n), Patcher.TempFS.OpenFileRead(String.Format("BTL_PACK/{0}", n))); } NewFps4.SaveTo(NewStream, DoAlign: false); }); }); }); }
protected void ExtractSvo(string SvoPath) { //try //{ using (var _SvoStream = File.OpenRead(SvoPath)) { Stream SvoStream = _SvoStream; int Compressed = TalesCompression.DetectVersion(SvoStream.Slice().ReadBytes(16), SvoStream.Length); if (Compressed >= 0) { SvoStream = TalesCompression.DecompressStream(SvoStream); } if (SvoStream.SliceWithLength().ReadString(7) == "TO8SCEL") { var TO8SCEL = new TO8SCEL(SvoStream); foreach (var Entry in TO8SCEL) { Console.WriteLine("{0} ... Start: {1}, End: {2}, Length: {3}", Entry.Index, Entry.EntryStruct.Offset, Entry.EntryStruct.Offset + Entry.EntryStruct.LengthCompressed, Entry.EntryStruct.LengthCompressed); } } else { var FPS4 = new FPS4(SvoStream); Console.WriteLine("{0}", FPS4); foreach (var Entry in FPS4) { Console.WriteLine("{0} ... Start: {1}, End: {2}, Length: {3}", Entry.Name, Entry.EntryStruct.Offset, Entry.EntryStruct.Offset + Entry.EntryStruct.LengthReal, Entry.EntryStruct.LengthReal); } } } }
private void Handle3() { Patcher.TempFS.OpenFileRWScope("BTL_PACK_ES.DAT", (BtlPackUkStream) => { Patcher.GameSetFileSystem(new FPS4FileSystem(BtlPackUkStream), () => { HandleBattlePackImages(); }); }); var OldBtlSvo = new FPS4(Patcher.GameFileSystem.OpenFileRead("btl.svo")); var NewBtlSvo = new FPS4(Patcher.GameFileSystem.OpenFileRead("btl.svo")); NewBtlSvo.ClearAllEntries(); NewBtlSvo.CreateEntry("BTL_EFFECT.DAT", OldBtlSvo["BTL_EFFECT.DAT"].Open()); var PackEsEntry = NewBtlSvo.CreateEntry("BTL_PACK_ES.DAT", Patcher.TempFS.OpenFileRead("BTL_PACK_ES.DAT")); NewBtlSvo.CreateEntry("BTL_PACK_DE.DAT", PackEsEntry); NewBtlSvo.CreateEntry("BTL_PACK_FR.DAT", PackEsEntry); NewBtlSvo.CreateEntry("BTL_PACK_UK.DAT", PackEsEntry); NewBtlSvo.CreateEntry("BTL_PACK_US.DAT", PackEsEntry); Patcher.TempFS.OpenFileCreateScope("btl.svo", (NewBtlSvoStream) => { NewBtlSvo.SaveTo(NewBtlSvoStream); }); Patcher.GameReplaceFile("btl.svo", Patcher.TempFS.OpenFileRead("btl.svo")); }
protected void Init(Stream StreamChatSvoOriginal, Stream StreamChatSvoTranslate, Stream StreamAcmeSkits) { //TalesCompression = new TalesCompression1_3(3); TalesCompression = new TalesCompression15_Lzx(); PAK = new FPS4(StreamChatSvoOriginal); PAKOutput = StreamChatSvoTranslate; ACME1 = new ACME1(StreamAcmeSkits, Encoding.GetEncoding("ISO-8859-1")); }
public override string ToString() { using (FPS4 fps4 = new FPS4(Stream.Duplicate())) using (DuplicatableStream txmvStream = fps4.GetChildByIndex(1).AsFile.DataStream.Duplicate()) using (FPS4 txmv = new FPS4(txmvStream.Duplicate())) using (DuplicatableStream txmStream = txmv.GetChildByIndex(0).AsFile.DataStream.Duplicate()) { TXM txm = new TXM(txmStream.Duplicate()); return(txm.TXMRegulars[0].Name); } }
/// <summary> /// /// </summary> /// <param name="DatPath"></param> /// <param name="DavPath"></param> /// <param name="OutputDirectory"></param> protected void ExtractSvo2(string DatPath, string DavPath, string OutputDirectory = null) { if (DavPath == null) { DavPath = DatPath; } if (OutputDirectory == null) { OutputDirectory = DatPath + ".d"; } Console.WriteLine("Loading {0}...", DatPath); //try //{ using (var _Stream1 = File.OpenRead(DatPath)) using (var Stream2 = File.OpenRead(DavPath)) { var Stream1 = (Stream)_Stream1; try { Directory.CreateDirectory(OutputDirectory); } catch { } int Compressed = TalesCompression.DetectVersion(Stream1.Slice().ReadBytes(16), Stream1.Length); if (Compressed >= 0) { Stream1 = TalesCompression.DecompressStream(Stream1); } if (Stream1.SliceWithLength().ReadString(7) == "TO8SCEL") { var TO8SCEL = new TO8SCEL(Stream1); foreach (var Entry in TO8SCEL) { _ExtractFile(OutputDirectory + "/" + Entry.Index, () => Entry.UncompressedStream, (int)(uint)Entry.EntryStruct.Offset, (int)(uint)Entry.EntryStruct.LengthCompressed); } } else { var FPS4 = new FPS4(Stream1, Stream2); Console.WriteLine("{0}", FPS4); foreach (var Entry in FPS4) { _ExtractFile(OutputDirectory + "/" + Entry.Name, () => Entry.Open(), (int)(uint)Entry.EntryStruct.Offset, (int)(uint)Entry.EntryStruct.LengthReal); } } } //} //catch (Exception Exception) //{ // Console.Error.WriteLine("{0}", Exception); //} }
public void Handle() { Patcher.Action("chat.svo", () => { TranslatedChatSvo = new FPS4(Patcher.GameFileSystem.OpenFileRead("chat.svo")).ClearAllEntries(); OriginalChatSvo = new FPS4(Patcher.GameFileSystem.OpenFileRead("chat.svo")); Patcher.ProgressHandler.ExecuteActionsWithProgressTracking("chat.svo", Handle1, Handle2, Handle3 ); }); }
static string svoExtractToTempDir(string infile, bool nometa = false) { string extractPath = TempUtil.GetTempFileName(); if (Directory.Exists(extractPath)) { Util.DeleteDirectoryAggressive(extractPath, true); } Directory.CreateDirectory(extractPath); using (var fps4 = new FPS4(infile)) { fps4.Extract(extractPath, nometa); } Logger.LogDirData(extractPath, "FPS4 extract of " + infile); return(extractPath); }
private static void OperationExtractFPS4() { string filename = ConsolePath("Full path to FPS4 archive..?"); if (filename.IsEmpty()) { return; } Stream stream = new CachedReadStream(new FileStream(filename, FileMode.Open, FileAccess.Read)); FPS4 fps = new FPS4(stream); string path = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".ext"); fps.Root.Extract(path); stream.Close(); File.WriteAllText(Path.Combine(path, "fps4.type"), fps.Type); }
public static Stream ProcessAreaNameTexture(FileFetcher _fc, string name, DuplicatableStream jstream, DuplicatableStream ustream) { DuplicatableStream wstream = _fc.GetFile(name, Version.W); FPS4 wani = new FPS4(wstream.Duplicate()); FPS4 uani = new FPS4(new HyoutaTools.Tales.tlzc.TlzcDecompressor().Decompress(ustream.Duplicate())); var clgfileinfo = wani.Files.Where(x => x.FileName.EndsWith(".CLG")).First(); string clgname = clgfileinfo.FileName; FPS4 waniclg = new FPS4(wani.GetChildByName(clgname).AsFile.DataStream); FPS4 uaniclg = new FPS4(uani.GetChildByName(clgname).AsFile.DataStream); DuplicatableStream wtexstream = waniclg.GetChildByIndex(1).AsFile.DataStream; DuplicatableStream utexstream = uaniclg.GetChildByIndex(1).AsFile.DataStream; Stream wtexstreammod = ProcessTexture(name + "/" + clgname, utexstream, wtexstream); long injectOffset = clgfileinfo.Location.Value + waniclg.Files[1].Location.Value; Stream wstreammod = wstream.CopyToMemory(); wstreammod.Position = injectOffset; wtexstreammod.Position = 0; StreamUtils.CopyStream(wtexstreammod, wstreammod, wtexstreammod.Length); wstreammod.Position = 0; return(wstreammod); }
protected void CsvHandle(string CsvPath) { var ListLastPair = new HashSet <string>(); var ProcessedNormalFile = new HashSet <string>(); var FPS4List = new Dictionary <string, FPS4>(); var Parse = new Regex(@"ReadFile"",""([^""]+)"",""SUCCESS"",""Offset: ([\d\.]+), Length: ([\d\.]+)", RegexOptions.Compiled); foreach (var Line in File.ReadAllLines(CsvPath)) { if (Line.Contains(@"ReadFile")) { var Match = Parse.Match(Line); if (Match.Groups[1].Value == "") { //Console.WriteLine(Line); Console.Error.WriteLine("Invalid Line! : {0}", Line); } else { var FilePath = Match.Groups[1].Value; var Offset = int.Parse(Match.Groups[2].Value.Replace(".", "").Trim()); var Length = int.Parse(Match.Groups[3].Value.Replace(".", "").Trim()); if (!FPS4List.ContainsKey(FilePath)) { try { FPS4List[FilePath] = new FPS4(File.OpenRead(FilePath)); } catch { } } if (FPS4List.ContainsKey(FilePath)) { var FPS4 = FPS4List[FilePath]; foreach (var Item in FPS4) { if (Offset >= Item.EntryStruct.Offset && Offset < Item.EntryStruct.Offset + Item.EntryStruct.LengthReal) { var CurrentPair = FilePath + Item.Name; if (!ListLastPair.Contains(CurrentPair)) { ListLastPair.Add(CurrentPair); Console.WriteLine("{0}: {1}, {2} : {3}", FilePath, Offset, Length, Item.Name); } } } } else { if (!ProcessedNormalFile.Contains(FilePath)) { ProcessedNormalFile.Add(FilePath); Console.WriteLine("{0}: {1}, {2}", FilePath, Offset, Length); } } } //var Parts = Line.Split(','); //Console.WriteLine(Parts[5]); //Console.WriteLine(Parts[7]); //Console.WriteLine(Parts[8]); //Console.WriteLine(String.Join("||", Parts)); } } }
private static void OperationPackFPS4() { string dirname = ConsolePath("Full path to FPS4 file contents..?"); string filename; if (dirname.EndsWith(".ext")) { filename = dirname.Substring(0, dirname.Length - 4); } else { filename = ConsolePath("Full path to FPS4 archive..?"); } if (!File.Exists(filename)) { Console.WriteLine("FPS4 file does not exist."); return; } Stream stream = new CachedReadStream(new FileStream(filename, FileMode.Open, FileAccess.Read)); FPS4 fps = new FPS4(stream); DelayedStreamCache cache = new DelayedStreamCache(); string[] files = Directory.GetFiles(dirname, "*", SearchOption.TopDirectoryOnly); foreach (string file in files) { string fname = Path.GetFileName(file); FPS4Base.Node node = fps.Base.Nodes.FirstOrDefault(n => n.Filename == fname); Stream data = new FileStream(file, FileMode.Open, FileAccess.Read); cache.AddStream(data); if (node == null) { continue; /* TODO: Only add when we want to * node = new FPS4Base.Node(0, (uint)data.Length, (uint)data.Length, fname, 0, 0, data); * fps.Base.Nodes.Insert((int)fps.Base.Files - 1, node); * fps.Base.Files++; */ } else { node.Data = data; } } fps.Base.Reorder(); Stream ostream = new FileStream(filename + ".new", FileMode.Create, FileAccess.Write); fps.Base.Save(ostream); ostream.Close(); stream.Close(); cache.Dispose(); }
public static void PatchChara(string charaPath, string patchDir, string outDir, string outMd5 = null, BackgroundWorker worker = null) { if (!File.Exists(charaPath)) { throw new PatchingException("File not found: " + charaPath); } if (worker != null) { worker.ReportProgress(0, "Confirming source file..."); } // if patched file exists and matches, exit early string outPath = Path.Combine(outDir, "chara.svo"); try { CompareMd5Output(outPath, outMd5); return; } catch (PatchingException) { } catch (FileNotFoundException) { } CompareMd5(charaPath, "38984a5656b7a2faac3a7e24c962607e"); Logger.LogFileData(charaPath, "chara.svo"); Logger.LogDirData(patchDir, "chara patches"); if (worker != null) { worker.ReportProgress(0, "Extracting source file..."); } string extractPath = svoExtractToTempDir(charaPath); if (worker != null) { worker.ReportProgress(0, "Patching files..."); } foreach (var patchDirG in Directory.GetDirectories(patchDir)) { string charaFilePath = Path.Combine(extractPath, Path.GetFileName(patchDirG) + ".DAT"); string decompPath = TempUtil.GetTempFileName(); tlzcDecompress(charaFilePath, decompPath); string subDir = svoExtractToTempDir(decompPath); foreach (var patchDirH in Directory.GetDirectories(patchDirG)) { string subPath = Path.Combine(subDir, Path.GetFileName(patchDirH)); string subSubDir = svoExtractToTempDir(subPath, true); foreach (var patch in Util.DirectoryGetFilesWorkaround(patchDirH)) { string toPatchCompressed = Path.Combine(subSubDir, Path.GetFileNameWithoutExtension(patch)); string toPatch = TempUtil.GetTempFileName(); tlzcDecompress(toPatchCompressed, toPatch); string patched = TempUtil.GetTempFileName(); XdeltaApply(toPatch, patched, patch); File.Delete(toPatch); tlzcCompress(patched, toPatchCompressed); File.Delete(patched); } string newSubPath = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(subPath)) { fps4.Alignment = 0x80; fps4.Pack(subSubDir, newSubPath); } File.Delete(subPath); File.Move(newSubPath, subPath); Util.DeleteDirectoryAggressive(subSubDir, true); } string newPath = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(decompPath)) { fps4.Alignment = 0x80; fps4.Pack(subDir, newPath); } tlzcCompress(newPath, charaFilePath); File.Delete(newPath); File.Delete(decompPath); Util.DeleteDirectoryAggressive(subDir, true); } // dice minigame textures { string EP_0670_010 = Path.Combine(extractPath, "EP_0670_010.DAT"); string EP_0670_010decomp = tlzcDecompressToTempFile(EP_0670_010); string EP_0670_010extract = svoExtractToTempDir(EP_0670_010decomp); { string EP_0670_010e_0002 = Path.Combine(EP_0670_010extract, "0002"); string EP_0670_010e_0002extract = svoExtractToTempDir(EP_0670_010e_0002, true); { string EP_0670_010e_0002e_0005 = Path.Combine(EP_0670_010e_0002extract, "0005"); string EP_0670_010e_0002e_0005decomp = tlzcDecompressToTempFile(EP_0670_010e_0002e_0005); BlockCopy(EP_0670_010e_0002e_0005decomp, 0x100, EP_0670_010e_0002e_0005decomp, 0x100100, 0x100000); tlzcCompress(EP_0670_010e_0002e_0005decomp, EP_0670_010e_0002e_0005); File.Delete(EP_0670_010e_0002e_0005decomp); string EP_0670_010e_0002e_0006 = Path.Combine(EP_0670_010e_0002extract, "0006"); string EP_0670_010e_0002e_0006decomp = tlzcDecompressToTempFile(EP_0670_010e_0002e_0006); BlockCopy(EP_0670_010e_0002e_0006decomp, 0x100, EP_0670_010e_0002e_0006decomp, 0x100100, 0x100000); tlzcCompress(EP_0670_010e_0002e_0006decomp, EP_0670_010e_0002e_0006); File.Delete(EP_0670_010e_0002e_0006decomp); } string EP_0670_010e_0002new = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(EP_0670_010e_0002)) { fps4.Alignment = 0x80; fps4.Pack(EP_0670_010e_0002extract, EP_0670_010e_0002new); } File.Delete(EP_0670_010e_0002); File.Move(EP_0670_010e_0002new, EP_0670_010e_0002); Util.DeleteDirectoryAggressive(EP_0670_010e_0002extract, true); } string EP_0670_010new = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(EP_0670_010decomp)) { fps4.Alignment = 0x80; fps4.Pack(EP_0670_010extract, EP_0670_010new); } tlzcCompress(EP_0670_010new, EP_0670_010); File.Delete(EP_0670_010decomp); File.Delete(EP_0670_010new); Util.DeleteDirectoryAggressive(EP_0670_010extract, true); } // "and they were never heard from again" textures { string GAMEOVER = Path.Combine(extractPath, "GAMEOVER.DAT"); string GAMEOVERdecomp = tlzcDecompressToTempFile(GAMEOVER); string GAMEOVERextract = svoExtractToTempDir(GAMEOVERdecomp); { string GAMEOVERe_0002 = Path.Combine(GAMEOVERextract, "0002"); string GAMEOVERe_0002extract = svoExtractToTempDir(GAMEOVERe_0002, true); { string GAMEOVERe_0002e_0001 = Path.Combine(GAMEOVERe_0002extract, "0001"); string GAMEOVERe_0002e_0001decomp = tlzcDecompressToTempFile(GAMEOVERe_0002e_0001); BlockCopy(GAMEOVERe_0002e_0001decomp, 0x55D80, GAMEOVERe_0002e_0001decomp, 0xD80, 0x55000); BlockCopy(GAMEOVERe_0002e_0001decomp, 0x55D80, GAMEOVERe_0002e_0001decomp, 0xAAD80, 0x55000); tlzcCompress(GAMEOVERe_0002e_0001decomp, GAMEOVERe_0002e_0001); File.Delete(GAMEOVERe_0002e_0001decomp); } string GAMEOVERe_0002new = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(GAMEOVERe_0002)) { fps4.Alignment = 0x80; fps4.Pack(GAMEOVERe_0002extract, GAMEOVERe_0002new); } File.Delete(GAMEOVERe_0002); File.Move(GAMEOVERe_0002new, GAMEOVERe_0002); Util.DeleteDirectoryAggressive(GAMEOVERe_0002extract, true); } string GAMEOVERnew = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(GAMEOVERdecomp)) { fps4.Alignment = 0x80; fps4.Pack(GAMEOVERextract, GAMEOVERnew); } tlzcCompress(GAMEOVERnew, GAMEOVER); File.Delete(GAMEOVERdecomp); File.Delete(GAMEOVERnew); Util.DeleteDirectoryAggressive(GAMEOVERextract, true); } // more dice minigame textures why are there so many copies of those { string POR_C = Path.Combine(extractPath, "POR_C.DAT"); string POR_Cdecomp = tlzcDecompressToTempFile(POR_C); string POR_Cextract = svoExtractToTempDir(POR_Cdecomp, true); { string POR_Ce_0002 = Path.Combine(POR_Cextract, "0002"); string POR_Ce_0002extract = svoExtractToTempDir(POR_Ce_0002, true); { string POR_Ce_0002e_0026 = Path.Combine(POR_Ce_0002extract, "0026"); string POR_Ce_0002e_0026decomp = tlzcDecompressToTempFile(POR_Ce_0002e_0026); BlockCopy(POR_Ce_0002e_0026decomp, 0x100, POR_Ce_0002e_0026decomp, 0x100100, 0x100000); tlzcCompress(POR_Ce_0002e_0026decomp, POR_Ce_0002e_0026); File.Delete(POR_Ce_0002e_0026decomp); string POR_Ce_0002e_0027 = Path.Combine(POR_Ce_0002extract, "0027"); string POR_Ce_0002e_0027decomp = tlzcDecompressToTempFile(POR_Ce_0002e_0027); BlockCopy(POR_Ce_0002e_0027decomp, 0x100, POR_Ce_0002e_0027decomp, 0x100100, 0x100000); tlzcCompress(POR_Ce_0002e_0027decomp, POR_Ce_0002e_0027); File.Delete(POR_Ce_0002e_0027decomp); } string POR_Ce_0002new = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(POR_Ce_0002)) { fps4.Alignment = 0x80; fps4.Pack(POR_Ce_0002extract, POR_Ce_0002new); } File.Delete(POR_Ce_0002); File.Move(POR_Ce_0002new, POR_Ce_0002); Util.DeleteDirectoryAggressive(POR_Ce_0002extract, true); } string POR_Cnew = TempUtil.GetTempFileName(); using (var fps4 = new FPS4(POR_Cdecomp)) { fps4.Alignment = 0x80; fps4.Pack(POR_Cextract, POR_Cnew); } tlzcCompress(POR_Cnew, POR_C); File.Delete(POR_Cdecomp); File.Delete(POR_Cnew); Util.DeleteDirectoryAggressive(POR_Cextract, true); } // extract yuri towel costume into its own archive { string EP_1320_060 = Path.Combine(extractPath, "EP_1320_060.DAT"); string EP_1320_060decomp = tlzcDecompressToTempFile(EP_1320_060); string EP_1320_060extract = svoExtractToTempDir(EP_1320_060decomp); { string EP_1320_060e_0002 = Path.Combine(EP_1320_060extract, "0002"); string EP_1320_060e_0002extract = svoExtractToTempDir(EP_1320_060e_0002); { foreach (string file in Util.DirectoryGetFilesWorkaround(EP_1320_060e_0002extract)) { if (!file.EndsWith("4")) { File.Delete(file); } } string EP_1320_060e_0002new = Path.Combine(EP_1320_060extract, "0002.new"); using (var fps4 = new FPS4()) { fps4.Alignment = 0x80; fps4.ContentBitmask = 0x0047; fps4.Pack(Util.DirectoryGetFilesWorkaround(EP_1320_060e_0002extract), EP_1320_060e_0002new, "n"); } File.Delete(EP_1320_060e_0002); File.Move(EP_1320_060e_0002new, EP_1320_060e_0002); Util.DeleteDirectoryAggressive(EP_1320_060e_0002extract, true); } File.Delete(Path.Combine(EP_1320_060extract, "0001")); File.Copy(Path.Combine(EP_1320_060extract, "0003"), Path.Combine(EP_1320_060extract, "0001")); string EP_1320_060e_0000 = Path.Combine(EP_1320_060extract, "0000"); string EP_1320_060e_0000extract = Path.Combine(EP_1320_060extract, "0000.ext"); if (Directory.Exists(EP_1320_060e_0000extract)) { Util.DeleteDirectoryAggressive(EP_1320_060e_0000extract, true); } Directory.CreateDirectory(EP_1320_060e_0000extract); using (var fps4 = new FPS4(EP_1320_060e_0000)) { fps4.Extract(EP_1320_060e_0000extract); } { foreach (string dir in Directory.GetDirectories(EP_1320_060e_0000extract)) { if (!Path.GetFileName(dir).StartsWith("P")) { Util.DeleteDirectoryAggressive(dir, true); } } foreach (string dir in Directory.GetDirectories(Directory.GetDirectories(EP_1320_060e_0000extract).First())) { string dirname = Path.GetFileName(dir); if (!(dirname.StartsWith("Y") || dirname.EndsWith("2"))) { Util.DeleteDirectoryAggressive(dir, true); } } foreach (string dir in Directory.GetDirectories(Directory.GetDirectories(Directory.GetDirectories(EP_1320_060e_0000extract).First()).First())) { string dirname = Path.GetFileName(dir); if (!dir.EndsWith("M")) { Util.DeleteDirectoryAggressive(dir, true); } } string EP_1320_060e_0000new = Path.Combine(EP_1320_060extract, "0000.new"); using (var fps4 = new FPS4()) { fps4.Alignment = 0x80; fps4.ContentBitmask = 0x0047; var files = Util.DirectoryGetFilesWorkaround(EP_1320_060e_0000extract, "*", System.IO.SearchOption.AllDirectories).OrderBy(x => x.Split('.').Last()).ToArray(); fps4.Pack(files, EP_1320_060e_0000new, "p"); } File.Delete(EP_1320_060e_0000); File.Move(EP_1320_060e_0000new, EP_1320_060e_0000); Util.DeleteDirectoryAggressive(EP_1320_060e_0000extract, true); } } string YUR_C201new = Path.Combine(extractPath, "YUR_C201.DAT.dec.new"); using (var fps4 = new FPS4()) { fps4.Alignment = 0x80; fps4.ContentBitmask = 0x0007; fps4.ArchiveName = "YUR_C201"; fps4.Pack(Util.DirectoryGetFilesWorkaround(EP_1320_060extract), YUR_C201new); } Util.DeleteDirectoryAggressive(EP_1320_060extract, true); tlzcCompress(YUR_C201new, Path.Combine(extractPath, "YUR_C201.DAT")); File.Delete(EP_1320_060decomp); File.Delete(YUR_C201new); } if (worker != null) { worker.ReportProgress(100, "Packing modified file..."); } Logger.LogDirData(extractPath, "chara dir patched"); using (var fps4 = new FPS4()) { using (var oldfps4 = new FPS4(charaPath)) { fps4.Unknown2 = oldfps4.Unknown2; fps4.ArchiveName = oldfps4.ArchiveName; } fps4.Alignment = 0x800; fps4.Pack(extractPath, outPath); } Logger.LogFileData(outPath, "chara.svo patched"); Util.DeleteDirectoryAggressive(extractPath, true); if (outMd5 != null) { CompareMd5Output(outPath, outMd5); } }
protected void HandleEntry(Regex SelectAll, Func <String, String, String> ReplaceSuffixName, FPS4.Entry EnglishEntry) { //Console.WriteLine(Thread.CurrentThread.ManagedThreadId); using (EnglishEntry) { //Console.WriteLine("[1]"); var BaseName = SelectAll.Match(EnglishEntry.Name).Groups[1].Value; var SpanishName = ReplaceSuffixName(EnglishEntry.Name, "ES"); Console.WriteLine("{0} : {1}", SpanishName, Thread.CurrentThread.ManagedThreadId); var ACMEFiles = ACME1.FilesByIndex.Where(Item => Item.Name.Contains(BaseName)); if (ACMEFiles.Count() == 1) { //Console.WriteLine("[2]"); var EsTempFile = TestOutputFolder + @"\" + SpanishName; #if REUSE_PAK if (!File.Exists(EsTempFile)) #endif { using (var CompressedSkitPAKStream = File.Open(EsTempFile, FileMode.Create)) { //Console.WriteLine("[3]"); var ACMEFile = ACMEFiles.ElementAt(0); //Console.WriteLine(SpanishName); using (var SkitPAK = new FPS4(TalesCompression.DecompressStream(EnglishEntry.Open()))) using (var chtx = new TO8CHTX(SkitPAK[3].Open())) { //Console.WriteLine("[4]"); try { chtx.TranslateWithAcmeFile(ACMEFile); } catch (Exception Exception) { Console.Error.WriteLine(Exception); Console.ReadKey(); } //Console.WriteLine("[5]"); using (var NewChtxStream = new MemoryStream()) using (var SkitPAKStream = new MemoryStream()) { chtx.Save(NewChtxStream); SkitPAK[3].SetStream(NewChtxStream); //Console.WriteLine("[6]"); SkitPAK.Save(SkitPAKStream); TalesCompression.EncodeFile(SkitPAKStream, CompressedSkitPAKStream); } } } } var SpanishEntry = PAK.CreateEntry(SpanishName, File.Open(EsTempFile, FileMode.Open)); } else { Console.WriteLine("WARNING. Untranslated Skit: ACMEFiles.Count() : {0} : {1}", ACMEFiles.Count(), BaseName); var SpanishEntry = PAK.CreateEntry(SpanishName, EnglishEntry.Open()); } } }
public static Stream ProcessTexture(string name, DuplicatableStream ustream, DuplicatableStream wstream) { FPS4 w = new FPS4(wstream.Duplicate()); TXM wtxm = new TXM(w.GetChildByIndex(0).AsFile.DataStream.Duplicate()); TXV wtxv = new TXV(wtxm, w.GetChildByIndex(1).AsFile.DataStream.Duplicate(), false); FPS4 u = new FPS4(ustream.Duplicate()); TXM utxm = new TXM(u.GetChildByIndex(0).AsFile.DataStream.Duplicate()); TXV utxv = new TXV(utxm, u.GetChildByIndex(1).AsFile.DataStream.Duplicate(), false); List <TexConvRules> convs = new List <TexConvRules>(); if (name == "rootR.cpk/mg/tex/karuta.tex") { convs.Add(new TexConvRules() { WTexId = 2, UTexId = 1, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKarutaHalfAndHalf(wtex, utex, 82, 134, 294) }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 3, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKarutaHalfAndHalf(wtex, utex, 86, 134, 294) }); convs.Add(new TexConvRules() { WTexId = 7, UTexId = 7, Method = TexConvMethod.DownscaleTwoThirds }); convs.Add(new TexConvRules() { WTexId = 13, UTexId = 13, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKaruta13(wtex, utex) }); convs.Add(new TexConvRules() { WTexId = 17, UTexId = 17, Method = TexConvMethod.DownscaleTwoThirds }); convs.Add(new TexConvRules() { WTexId = 22, UTexId = 23, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DownscaleTwoThirds(CropExpandCanvas(utex, 2, -2, (uint)(utex.Width + 3), (uint)(utex.Height - 3))) }); } else if (name == "rootR.cpk/mnu/tex/main.tex") { convs.Add(new TexConvRules() { WTexId = 110, UTexId = 61, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 111, UTexId = 62, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 112, UTexId = 63, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 113, UTexId = 64, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 114, UTexId = 65, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 115, UTexId = 66, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 116, UTexId = 67, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 117, UTexId = 68, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 118, UTexId = 69, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 119, UTexId = 70, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 124, UTexId = 75, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/mnu/tex/shop.tex") { convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 2, UTexId = 2, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 3, UTexId = 3, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 4, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 5, UTexId = 5, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 6, UTexId = 6, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 7, UTexId = 7, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/mnu/tex/skill.tex") { convs.Add(new TexConvRules() { WTexId = 0, UTexId = 0, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 2, UTexId = 2, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 3, UTexId = 3, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 4, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 5, UTexId = 5, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/mnu/tex/snd_test.tex") { convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/SysSub/JA/TitleTexture.tex") { convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 2, UTexId = 4, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 3, UTexId = 6, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 8, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 6, UTexId = 12, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 7, UTexId = 14, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 8, UTexId = 16, Method = TexConvMethod.CropExpandCanvas }); } else if (name.EndsWith(".CLG")) { convs.Add(new TexConvRules() { WTexId = 0, UTexId = 0, Method = TexConvMethod.DownscaleTwoThirds }); convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Clear }); } MemoryStream s = wstream.Duplicate().CopyToMemory(); s.Position = 0; foreach (TexConvRules c in convs) { var wm = wtxm.TXMRegulars[c.WTexId]; var um = utxm.TXMRegulars[c.UTexId]; var wv = wtxv.textures.Where(x => x.TXM == wm).First(); var uv = utxv.textures.Where(x => x.TXM == um).First(); System.Drawing.Bitmap newImage = null; switch (c.Method) { case TexConvMethod.Downscale2x: { newImage = FontProcessing.DownscaleInteger(uv.GetBitmaps()[0], 2); } break; case TexConvMethod.DownscaleTwoThirds: { newImage = DownscaleTwoThirds(uv.GetBitmaps()[0]); } break; case TexConvMethod.CropExpandCanvas: { newImage = DoCropExpandCanvas(uv.GetBitmaps()[0], wm.Width, wm.Height); } break; case TexConvMethod.Clear: { newImage = new Bitmap(wv.GetBitmaps()[0]); for (int y = 0; y < newImage.Height; ++y) { for (int x = 0; x < newImage.Width; ++x) { newImage.SetPixel(x, y, Color.FromArgb(0, 0, 0, 0)); } } } break; case TexConvMethod.Delegate: { newImage = c.Delegate(wv.GetBitmaps()[0], uv.GetBitmaps()[0]); } break; default: { throw new Exception("don't know how to convert " + uv.TXM.Name); } } if (newImage != null) { HyoutaTools.Util.Assert(newImage.Width == wm.Width); HyoutaTools.Util.Assert(newImage.Height == wm.Height); if (wm.Format == HyoutaTools.Tales.Vesperia.Texture.TextureFormat.Indexed8Bits_RGB5A3) { ChopBitsRGB5A3(newImage); var palette = GeneratePalette256(newImage); s.Position = w.Files[1].Location.Value + wm.TxvLocation; foreach (var loc in new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(newImage.Width, newImage.Height, 8, 4)) { int cval = 0; if (loc.X < newImage.Width && loc.Y < newImage.Height) { cval = palette.lookup[newImage.GetPixel(loc.X, loc.Y)]; } s.WriteByte((byte)cval); } for (int ci = 0; ci < 256; ++ci) { ushort cval = 0; if (ci < palette.colors.Count) { cval = HyoutaTools.Textures.ColorFetchingIterators.ColorFetcherRGB5A3.ColorToRGB5A3(palette.colors[ci]); } s.WriteUInt16(cval.ToEndian(EndianUtils.Endianness.BigEndian)); } } else if (wm.Format == HyoutaTools.Tales.Vesperia.Texture.TextureFormat.GamecubeRGBA8) { s.Position = w.Files[1].Location.Value + wm.TxvLocation; byte[] tmpb = new byte[0x40]; int tmpp = 0; foreach (var loc in new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(newImage.Width, newImage.Height, 4, 4)) { Color col = newImage.GetPixel(loc.X, loc.Y); tmpb[tmpp * 2 + 0] = col.A; tmpb[tmpp * 2 + 1] = col.R; tmpb[tmpp * 2 + 0 + 0x20] = col.G; tmpb[tmpp * 2 + 1 + 0x20] = col.B; ++tmpp; if (tmpp == 16) { tmpp = 0; s.Write(tmpb); } } if (tmpp != 0) { throw new Exception("Unexpected tile size for " + wm.Name); } } else { Console.WriteLine("don't know how to encode into " + wm.Format); } } } s.Position = 0; return(s); }
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); }
public static void PatchBtl(string btlPath, string patchDir, string outDir, string outMd5 = null, BackgroundWorker worker = null) { if (!File.Exists(btlPath)) { throw new PatchingException("File not found: " + btlPath); } if (worker != null) { worker.ReportProgress(0, "Confirming source file..."); } // if patched file exists and matches, exit early string outPath = Path.Combine(outDir, "btl.svo"); try { CompareMd5Output(outPath, outMd5); return; } catch (PatchingException) { } catch (FileNotFoundException) { } CompareMd5(btlPath, "37bed259717dd27e5145d8899e7c36d9"); Logger.LogFileData(btlPath, "btl.svo"); Logger.LogDirData(patchDir, "btl patches"); // extract if (worker != null) { worker.ReportProgress(0, "Extracting source file..."); } string extractPath = svoExtractToTempDir(btlPath); string btlPackPath = svoExtractToTempDir(Path.Combine(extractPath, "BTL_PACK.DAT")); string file3Path = svoExtractToTempDir(Path.Combine(btlPackPath, "0003"), nometa: true); // patch int i = 0; var files = Util.DirectoryGetFilesWorkaround(patchDir); foreach (string patch in files) { if (worker != null) { worker.ReportProgress((i / files.Length) * 100, "Patching file " + (i + 1) + " of " + files.Length + "..."); } string fileName = Path.GetFileNameWithoutExtension(patch); string sourcePath = Path.Combine(file3Path, "0" + fileName); string decompressedPath = tlzcDecompressToTempFile(sourcePath); string patchedPath = TempUtil.GetTempFileName(); XdeltaApply(decompressedPath, patchedPath, patch); tlzcCompress(patchedPath, sourcePath); System.IO.File.Delete(decompressedPath); System.IO.File.Delete(patchedPath); ++i; } // pack if (worker != null) { worker.ReportProgress(100, "Packing modified file..."); } Logger.LogDirData(file3Path, "btl/btl_pack/3 dir patched"); using (var fps4file3 = new FPS4(Path.Combine(btlPackPath, "0003"))) { fps4file3.Alignment = 0x80; fps4file3.Pack(file3Path, Path.Combine(btlPackPath, "0003.new")); } File.Delete(Path.Combine(btlPackPath, "0003")); File.Move(Path.Combine(btlPackPath, "0003.new"), Path.Combine(btlPackPath, "0003")); Util.DeleteDirectoryAggressive(file3Path, true); using (var fps4btlPack = new FPS4(Path.Combine(extractPath, "BTL_PACK.DAT"))) { fps4btlPack.Alignment = 0x80; fps4btlPack.Pack(btlPackPath, Path.Combine(extractPath, "BTL_PACK.DAT.new")); } File.Delete(Path.Combine(extractPath, "BTL_PACK.DAT")); File.Move(Path.Combine(extractPath, "BTL_PACK.DAT.new"), Path.Combine(extractPath, "BTL_PACK.DAT")); Util.DeleteDirectoryAggressive(btlPackPath, true); Logger.LogDirData(extractPath, "btl dir patched"); using (var fps4btl = new FPS4(btlPath)) { fps4btl.Alignment = 0x800; fps4btl.Pack(extractPath, outPath); } Logger.LogFileData(outPath, "btl.svo patched"); Util.DeleteDirectoryAggressive(extractPath, true); if (outMd5 != null) { CompareMd5Output(outPath, outMd5); } }
private void Handle1() { Patcher.TempFS.CreateDirectory("CHAT_ES", 0777, false); Patcher.Action("Translating Skits...", () => { Patcher.ProgressHandler.AddProgressLevel("Traduciendo skits", OriginalChatSvo.Count(), () => { Patcher.ParallelForeach("Translating", OriginalChatSvo, (ChatSvoEntry) => ChatSvoEntry.Name, (ChatSvoEntry) => { var Match = ChatSvoEntry.Name.RegexMatch(@"^(VC\d+B?)(UK)\.DAT$"); if (Match != null) { var CompleteFile = Match[0].Value; var ChatId = Match[1].Value; var EsFile = PreppendTempFile + ChatId + "ES.DAT"; Console.WriteLine("{0}...", ChatId); if (!Patcher.TempFS.Exists(EsFile)) { var Fps4 = new FPS4(TalesCompression.DecompressStream(OriginalChatSvo[CompleteFile].Open())); { var Chtx = new TO8CHTX(); Chtx.Load(Fps4["3"].Open()); // Translate { foreach (var Entry in Patcher.EntriesByRoom["skits/" + ChatId].Values) { int TextId = int.Parse(Entry.text_id) - 1; if (TextId >= 0) { //Chtx[TextId].Title = ""; //Chtx[TextId].Title = TextProcessor.Instance.ProcessAndDetectPitfalls(Chtx[TextId].Title, Entry.texts.es[0].TrimEnd(' ', '\t', '\n', '\r', '.')); //Chtx[TextId].Title = TextProcessor.Instance.ProcessAndDetectPitfalls(Chtx[TextId].Title, Entry.texts.es[0]); Chtx[TextId].Title = ""; Chtx[TextId].TextOriginal = ""; Chtx[TextId].TextTranslated = TextProcessor.Instance.ProcessAndDetectPitfalls(Chtx[TextId].TextTranslated, Entry.texts.es[1]); } } } //ChtxStream.SetLength(0); var ChtxStream = new MemoryStream(); Chtx.SaveTo(ChtxStream); ChtxStream.Position = 0; Fps4["3"].SetStream(ChtxStream); } Patcher.TempFS.WriteAllBytes(EsFile, TalesCompression.CreateFromVersion(Patcher.CompressionVersion, Patcher.CompressionFallback).EncodeBytes(Fps4.Save(false).ToArray())); Console.WriteLine("{0}...Ok", ChatId); } else { Console.WriteLine("{0}...Exists", ChatId); } } Patcher.ProgressHandler.IncrementLevelProgress(); }); }); }); }
public void Initialize() { fps4 = new FPS4(); }
public static int Execute(List <string> args) { bool gamedirmode = args.Count == 3 || args.Count == 4; bool manualmode = args.Count == 9; if (!gamedirmode && !manualmode) { System.Windows.Forms.MessageBox.Show( "Requires arguments:\n\n" + " For automatically fetching files from game directory (point at folder containing item.svo):\n" + " Version Locale GameDirectory [STRING_DIC.SO]\n" + " STRING_DIC.SO can be overridden to select a different language file.\n" + "\n" + " For manually providing files:\n" + " Version Locale ITEM.DAT STRING_DIC.SO T8BTSK T8BTEMST COOKDAT WRLDDAT ITEMSORT.DAT\n" + "\n" + "'Version' should be one of: 360, 360EU, PS3, PC\n" + "'Locale' should be 1 for the 1st language in the given STRING_DIC, or 2 for the second" ); return(-1); } GameVersion?version = null; EndianUtils.Endianness endian = EndianUtils.Endianness.BigEndian; BitUtils.Bitness bits = BitUtils.Bitness.B32; TextUtils.GameTextEncoding encoding = TextUtils.GameTextEncoding.ShiftJIS; switch (args[0].ToUpperInvariant()) { case "360": version = GameVersion.X360_US; break; case "360EU": version = GameVersion.X360_EU; encoding = TextUtils.GameTextEncoding.UTF8; break; case "PS3": version = GameVersion.PS3; break; case "PC": version = GameVersion.PC; endian = EndianUtils.Endianness.LittleEndian; bits = BitUtils.Bitness.B64; encoding = TextUtils.GameTextEncoding.UTF8; break; } int locale = 0; if (args[1] == "1") { locale = 1; } else if (args[1] == "2") { locale = 2; } if (version == null || locale == 0) { Console.WriteLine("First parameter must indicate game version, second parameter must indicate locale!"); return(-1); } DuplicatableStream itemDatStream; DuplicatableStream itemSortStream; DuplicatableStream stringDicStream; DuplicatableStream skillsStream; DuplicatableStream enemiesStream; DuplicatableStream cookdatStream; DuplicatableStream locationsStream; if (manualmode) { itemDatStream = new DuplicatableFileStream(args[2]).CopyToByteArrayStreamAndDispose(); itemSortStream = new DuplicatableFileStream(args[8]).CopyToByteArrayStreamAndDispose(); stringDicStream = new DuplicatableFileStream(args[3]).CopyToByteArrayStreamAndDispose(); skillsStream = new DuplicatableFileStream(args[4]).CopyToByteArrayStreamAndDispose(); enemiesStream = new DuplicatableFileStream(args[5]).CopyToByteArrayStreamAndDispose(); cookdatStream = new DuplicatableFileStream(args[6]).CopyToByteArrayStreamAndDispose(); locationsStream = new DuplicatableFileStream(args[7]).CopyToByteArrayStreamAndDispose(); } else { bool hasCooksvo = VesperiaUtil.Is360(version.Value); using (var itemsvo = new FPS4(Path.Combine(args[2], "item.svo"))) { itemDatStream = itemsvo.GetChildByName("ITEM.DAT").AsFile.DataStream.CopyToByteArrayStreamAndDispose(); itemSortStream = itemsvo.GetChildByName("ITEMSORT.DAT").AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } using (var menusvo = new FPS4(Path.Combine(args[2], "menu.svo"))) { if (!hasCooksvo) { cookdatStream = menusvo.GetChildByName("COOKDATA.BIN").AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } else { using (var cooksvo = new FPS4(Path.Combine(args[2], "cook.svo"))) { cookdatStream = cooksvo.GetChildByName("COOKDATA.BIN").AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } } locationsStream = menusvo.GetChildByName("WORLDDATA.BIN").AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } if (args.Count == 3) { if (version == GameVersion.X360_EU) { stringDicStream = new DuplicatableFileStream(Path.Combine(args[2], "language", "string_dic_uk.so")).CopyToByteArrayStreamAndDispose(); } else if (version == GameVersion.PC) { stringDicStream = new DuplicatableFileStream(Path.Combine(args[2], "language", "string_dic_ENG.so")).CopyToByteArrayStreamAndDispose(); } else { using (var stringsvo = new FPS4(Path.Combine(args[2], "string.svo"))) { stringDicStream = stringsvo.GetChildByName("STRING_DIC.SO").AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } } } else { stringDicStream = new DuplicatableFileStream(args[3]).CopyToByteArrayStreamAndDispose(); } using (var btlsvo = new FPS4(Path.Combine(args[2], "btl.svo"))) { using (var btlpack = new FPS4(btlsvo.GetChildByName(version == GameVersion.X360_EU ? "BTL_PACK_UK.DAT" : "BTL_PACK.DAT").AsFile.DataStream)) { using (var all = new FPS4(btlpack.GetChildByIndex(10).AsFile.DataStream)) { skillsStream = all.GetChildByIndex(0).AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } using (var all = new FPS4(btlpack.GetChildByIndex(5).AsFile.DataStream)) { enemiesStream = all.GetChildByIndex(0).AsFile.DataStream.CopyToByteArrayStreamAndDispose(); } } } } HyoutaTools.Tales.Vesperia.ItemDat.ItemDat items = new HyoutaTools.Tales.Vesperia.ItemDat.ItemDat(itemDatStream, itemSortStream, EndianUtils.Endianness.BigEndian); TSSFile TSS; try { TSS = new TSSFile(stringDicStream, encoding, endian); } catch (System.IO.FileNotFoundException) { Console.WriteLine("Could not open STRING_DIC.SO, exiting."); return(-1); } HyoutaTools.Tales.Vesperia.T8BTSK.T8BTSK skills = new HyoutaTools.Tales.Vesperia.T8BTSK.T8BTSK(skillsStream, endian, bits); HyoutaTools.Tales.Vesperia.T8BTEMST.T8BTEMST enemies = new HyoutaTools.Tales.Vesperia.T8BTEMST.T8BTEMST(enemiesStream, endian, bits); HyoutaTools.Tales.Vesperia.COOKDAT.COOKDAT cookdat = new HyoutaTools.Tales.Vesperia.COOKDAT.COOKDAT(cookdatStream, endian); HyoutaTools.Tales.Vesperia.WRLDDAT.WRLDDAT locations = new HyoutaTools.Tales.Vesperia.WRLDDAT.WRLDDAT(locationsStream, endian); Console.WriteLine("Initializing GUI..."); ItemForm itemForm = new ItemForm(version.Value, locale - 1, items, TSS, skills, enemies, cookdat, locations); itemForm.Show(); return(0); }
static void Main(string[] args) { //var basename = @"C:\Juegos\fez\Content\Essentials.pak.d\fonts\zuish"; //var basename = @"C:\Juegos\fez\Content\Essentials.pak.d\effects\basicposteffect"; //var basename = @"C:\Juegos\fez\Content\Other.pak.d\background planes\qr_crypt"; //DecodeImage(@"C:\Juegos\fez\Content\Other.pak.d\art objects\menu_cube"); //Environment.Exit(0); //var Path = @"C:\Juegos\fez\Content\"; var Path = @"C:\Juegos\fez\Content\Other.pak.d\art objects"; foreach (var filename in Directory.EnumerateFiles(Path, "*", SearchOption.AllDirectories)) { Console.WriteLine("{0}...", filename); try { DecodeImage(filename); } catch (Exception Exception) { //Console.WriteLine(Exception); } } //BE 5A 00 00 //93 AA 04 00 // 0x5ABE // 0xAA93 /* * var Out = new MemoryStream(); * Lzx.Decompress(Stream, 0x5ABE, Out, 0xAA93); * Console.WriteLine(Out.Length); */ Console.ReadKey(); #if false //var FilePath = @"I:\isos\360\Tales of Vesperia [PAL] [Multi3] [English] [Xbox360].iso"; var FilePath = @"C:\tov\tov_spa.iso"; var Dvd9Xbox360 = new Dvd9Xbox360(); using (var IsoStream = File.Open(FilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { Dvd9Xbox360.Load(IsoStream); using (var map_svo_stream = Dvd9Xbox360.RootEntry["/map.svo"].Open()) { var map_svo = new FPS4(map_svo_stream); map_svo["SCENARIO.DAT"].ReplaceWithFile(@"c:\tov\language\scenario_uk.dat"); } Dvd9Xbox360.RootEntry["/language/scenario_us.dat"].ReplaceWithFile(@"c:\tov\language\scenario_uk.dat"); Dvd9Xbox360.RootEntry["/language/scenario_uk.dat"].ReplaceWithFile(@"c:\tov\language\scenario_uk.dat"); Dvd9Xbox360.RootEntry["/language/string_dic_uk.so"].ReplaceWithFile(@"c:\tov\language\string_dic_uk.so"); Dvd9Xbox360.RootEntry["/UI.svo"].ReplaceWithFile(@"c:\tov\ui.svo"); Dvd9Xbox360.RootEntry["/chat.svo"].ReplaceWithFile(@"c:\tov\chat.svo"); } Console.WriteLine("Done. Press any key to continue."); Console.ReadKey(); return; #if true var TranslateSkits = new TranslateSkits(@"c:\tov\chat.svo.bak", @"c:\tov\chat.svo", @"tov_skits.zip"); //var TranslateSkits = new TranslateSkits(); //TranslateSkits.Backup(); TranslateSkits.Process(); new UpdateFont().Process(@"c:\tov\UI.svo", "FONTTEX10.TXV.mod.png"); /* * Console.WriteLine("Decoding..."); * //var Fps4 = new FPS4(File.Open(@"F:\Isos\360\games\vesperia\UI.svo", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)); * var Fps4 = new FPS4(File.Open(@"J:\games\vesperia\UI.svo", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)); * using (var Out = Fps4["FONTTEX10.TXV"].Open()) * { * DXT5.SaveSwizzled(new Bitmap(Image.FromFile("../../../TestInput/FONTTEX10.TXV.mod.png")), Out); * } * Console.WriteLine("Ok"); */ /* * //var Bitmap = DXT5.LoadSwizzled(File.OpenRead("../../../TestInput/FONTTEX05.TXV.mod.TXV"), 2048, 2048); * using (var Out = File.OpenWrite("../../../Lol.txv")) * { * DXT5.SaveSwizzled(new Bitmap(Image.FromFile("../../../TestInput/FONTTEX10.TXV.mod.png")), Out); * } */ //Bitmap.Save("../../../Lol.png"); #else var TranslateSkits = new TranslateSkits(); TranslateSkits.Backup(); TranslateSkits.Process(); /* * var FPS4 = new FPS4(); * FPS4.Load(File.OpenRead(@"J:\games\vesperia\chat.svo")); * * Console.WriteLine(FPS4.Entries["VC980US.DAT"].CompressedStream.Length); * * FPS4.Entries["VC980US.DAT"].CompressedStream.CopyTo( * File.OpenWrite(@"C:\projects\svn.tales-tra.com\csharp\TalesOfVesperiaUtils\TestInput\VC980US.DAT"), * 8 * 1024 * 1024 * ); */ #endif #endif Console.WriteLine("Done. Press any key to continue."); Console.ReadKey(); }
public FPS4FileSystem(Stream Stream) { this.FPS4 = new FPS4(Stream); }
protected void Expand(string FilePath) { if (FilePath.Contains('*') || FilePath.Contains('?')) { var BasePath = Path.GetDirectoryName(FilePath); var Recursive = false; if (BasePath == "") { BasePath = "."; } foreach (var FileName in Directory.EnumerateFiles(BasePath, Path.GetFileName(FilePath), Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)) { Expand(FileName); } return; } var ListToExpand = new List <string>(); //Console.WriteLine("Expanding '{0}'...", FilePath); using (var _FileStream = File.OpenRead(FilePath)) { if (_FileStream.Length == 0) { //Console.WriteLine("EMPTY: {0}", FilePath); return; } var FileStream = DecompressIfCompressedStream(_FileStream); var MagicData = FileStream.Slice().ReadBytesUpTo(0x100); if (false) { } else if (TO8SCEL.IsValid(MagicData)) { try { var To8Scel = new TO8SCEL(FileStream); foreach (var Entry in To8Scel) { var EntryFilePath = FilePath + ".d/" + Entry.Index; if (Overwrite || !File.Exists(EntryFilePath)) { Console.WriteLine("{0}", EntryFilePath); try { var EntryStream = DecompressIfCompressedStream(Entry.CompressedStream); if (EntryStream.Length > 0) { EntryStream.CopyToFile(EntryFilePath); } } catch (Exception Exception) { ShowException(Exception); } } if (File.Exists(EntryFilePath)) { ListToExpand.Add(EntryFilePath); } } } catch (Exception Exception) { ShowException(Exception); } } else if (FPS4.IsValid(MagicData)) { //Console.WriteLine("FPS4"); try { var Fps4 = new FPS4(FileStream); foreach (var Entry in Fps4) { var EntryFilePath = FilePath + ".d/" + Entry.Name; if (Overwrite || !File.Exists(EntryFilePath)) { Console.WriteLine("{0}", EntryFilePath); try { var EntryStream = DecompressIfCompressedStream(Entry.Open()); if (EntryStream.Length > 0) { EntryStream.CopyToFile(EntryFilePath); } } catch (Exception Exception) { ShowException(Exception); } } if (File.Exists(EntryFilePath)) { ListToExpand.Add(EntryFilePath); } } } catch (Exception Exception) { ShowException(Exception); } } else if (TSS.IsValid(MagicData)) { int RoomId = 0; try { RoomId = int.Parse(Path.GetFileNameWithoutExtension(FilePath)); } catch { } var TxtFile = FilePath + ".txt"; Console.WriteLine("{0}", TxtFile); if (Overwrite || !File.Exists(TxtFile)) { var Tss = new TSS().Load(FileStream.Slice()); using (var TxtStream = File.Open(TxtFile, FileMode.Create, FileAccess.Write)) using (var TextWriter = new StreamWriter(TxtStream)) { try { Tss.DumpTexts(TextWriter); } catch (Exception Exception) { ShowException(Exception); } } } var ScrFile = FilePath + ".scr"; Console.WriteLine("{0}", ScrFile); if (Overwrite || !File.Exists(ScrFile)) { var Tss = new TSS().Load(FileStream.Slice()); using (var TxtStream = File.Open(ScrFile, FileMode.Create, FileAccess.Write)) using (var TextWriter = new StreamWriter(TxtStream)) { try { var ErrorString = ConsoleUtils.CaptureError(() => { Tss.DumpScript(TextWriter); }); } catch (Exception Exception) { ShowException(Exception); } } } } else if (TO8CHTX.IsValid(MagicData)) { var Chtx = new TO8CHTX(FileStream); var TxtFile = FilePath + ".txt"; Console.WriteLine("{0}", TxtFile); if (Overwrite || !File.Exists(TxtFile)) { using (var TxtStream = File.Open(TxtFile, FileMode.Create, FileAccess.Write)) using (var TextWriter = new StreamWriter(TxtStream)) { foreach (var Entry in Chtx.Entries) { TextWriter.WriteLine("{0}", Entry.Title); TextWriter.WriteLine("{0}", Entry.TextOriginal); TextWriter.WriteLine("{0}", Entry.TextTranslated); TextWriter.WriteLine(""); } } //Chtx.Entries[0].Title //Console.WriteLine("CHAT!"); } } else if (SE3.IsValid(MagicData)) { var Se3 = new SE3().Load(FileStream); foreach (var Entry in Se3.Entries) { var EntryFullNameXma = FilePath + "." + Entry.Name + ".xma"; var EntryFullNameWav = FilePath + "." + Entry.Name + ".wav"; Console.WriteLine("{0}", EntryFullNameXma); if (Overwrite || !File.Exists(EntryFullNameXma)) { Entry.ToXmaWav().CopyToFile(EntryFullNameXma); } if (Overwrite || !File.Exists(EntryFullNameWav)) { using (var WavOut = File.Open(EntryFullNameWav, FileMode.Create, FileAccess.Write)) { Entry.ToWav(WavOut); } } } } else if (TXM.IsValid(MagicData)) { string BasePath; string TxmPath; string TxvPath; if (Path.GetExtension(FilePath).ToLower() == ".txm") { BasePath = Path.GetDirectoryName(FilePath) + "/" + Path.GetFileNameWithoutExtension(FilePath); TxmPath = BasePath + ".txm"; TxvPath = BasePath + ".txv"; } else { var DirectoryPath = Path.GetDirectoryName(FilePath); TxmPath = DirectoryPath + "/" + Path.GetFileName(FilePath); TxvPath = DirectoryPath + "/" + (int.Parse(Path.GetFileName(TxmPath)) + 1); BasePath = TxmPath; } var Txm = TXM.FromTxmTxv(File.OpenRead(TxmPath), File.OpenRead(TxvPath)); /* * if (Txm.Surface2DEntries.Length > 0 && Txm.Surface3DEntries.Length > 0) * { * // 3D and 2D surfaces * //Console.WriteLine("ERROR 3D and 2D SURFACES! (2D: {0}, 3D: {1})", Txm.Surface2DEntries.Length, Txm.Surface3DEntries.Length); * } * else if (Txm.Surface2DEntries.Length > 0) * { * // 2D Surfaces * //Console.WriteLine("2D SURFACES! {0}", Txm.Surface2DEntries.Length); * } * else if (Txm.Surface3DEntries.Length > 0) * { * // 3D Surfaces * //Console.WriteLine("3D SURFACES! {0}", Txm.Surface3DEntries.Length); * } */ foreach (var Entry in Txm.Surface2DEntries) { var ImagePath = BasePath + "." + Entry.Name + ".png"; if (Overwrite || !File.Exists(ImagePath)) { try { Entry.Bitmap.Save(ImagePath); } catch (Exception Exception) { ShowException(Exception); } } } foreach (var Entry in Txm.Surface3DEntries) { var ImagePath0 = BasePath + "." + Entry.Name + "." + 0 + ".png"; if (Overwrite || !File.Exists(ImagePath0)) { try { var n = 0; foreach (var Bitmap in Entry.Bitmaps.Bitmaps) { var ImagePath = BasePath + "." + Entry.Name + "." + n + ".png"; Console.WriteLine("{0}", ImagePath); if (Overwrite || !File.Exists(ImagePath)) { Bitmap.Save(ImagePath); } n++; } } catch (Exception Exception) { ShowException(Exception); } } } } else { } } // Expand all the queued stuff foreach (var Item in ListToExpand) { try { Expand(Item); } catch (Exception Exception) { Console.WriteLine(" ERROR: {0}", Verbose ? Exception.ToString() : Exception.Message.ToString()); } } }
public void HandleBattlePackDialogs(Stream OldStream, Stream NewStream) { FPS4 OldFps4; FPS4 NewFps4; OldFps4 = new FPS4(OldStream.Slice()); NewFps4 = new FPS4(OldStream.Slice()); // Intended OldStream var TranslatedFiles = new ConcurrentDictionary <string, MemoryStream>(); var Names = new[] { "BTL_EP_0070_010", "BTL_EP_030_040", "BTL_EP_030_080", "BTL_EP_0950_010", "BTL_EP_0960_020", "BTL_EP_1040_020", "BTL_EP_150_170", "BTL_EP_170_050", "BTL_EP_210_090", "BTL_EP_270_110", "BTL_EP_270_110_1", "BTL_EP_340_070", "BTL_EP_370_050", "BTL_EP_420_080", "BTL_EP_440_040", "BTL_EP_470_030", "BTL_EP_490_060_0", "BTL_EP_490_060_1", "BTL_EP_510_050", "BTL_EP_510_080", "BTL_EP_640_050", "BTL_EP_650_030", "BTL_EP_650_050", "BTL_LL_MONSTER", "MA_VAL_A_05", }; Patcher.Action("Translating Battle Scripts", () => { Patcher.ProgressHandler.AddProgressLevel("Traduciendo scripts de batalla...", Names.Length, () => { Patcher.ParallelForeach("Translating", Names, (Name) => Name, (Name) => { using (var CompressedTssStream = OldFps4[Name].Open()) { using (var TssStream = TalesCompression.DecompressStream(CompressedTssStream)) { var TssName = Name; var Tss = new TSS().Load(TssStream); Tss.TranslateTexts((Entry) => { //if (Entry == null) return; var TranslationEntry = Patcher.EntriesByRoom["battle/" + TssName][String.Format("{0:X8}", Entry.Id2)]; int TextCount = Entry.Original.Length; Entry.TranslateWithTranslationEntry(TranslationEntry); //Console.WriteLine("{0} : {1}", Entry.Translated[1], TranslationEntry.texts.es[1]); }, (String) => { return(null); }); var TranslatedCompressedStream = TalesCompression.CreateFromVersion(Patcher.CompressionVersion, Patcher.CompressionFallback).EncodeFile(Tss.Save()); TranslatedFiles[Name] = TranslatedCompressedStream; } } Patcher.ProgressHandler.IncrementLevelProgress(); }); }); }); Patcher.Action("Reconstructing Battle Scripts Package", () => { NewFps4.ClearAllEntries(); foreach (var Entry in OldFps4.Entries.Values) { var EntryName = Entry.Name; if (TranslatedFiles.ContainsKey(EntryName)) { NewFps4.CreateEntry(EntryName, TranslatedFiles[EntryName]); } else { NewFps4.CreateEntry(EntryName, Entry.Open()); } } NewFps4.SaveTo(NewStream, DoAlign: false); }); }
public static void PatchChat(string chatPath, string patchDir, string outDir, string outMd5 = null, BackgroundWorker worker = null) { if (!File.Exists(chatPath)) { throw new PatchingException("File not found: " + chatPath); } if (worker != null) { worker.ReportProgress(0, "Confirming source file..."); } // if patched file exists and matches, exit early string outPath = Path.Combine(outDir, "chat.svo"); try { CompareMd5Output(outPath, outMd5); return; } catch (PatchingException) { } catch (FileNotFoundException) { } CompareMd5(chatPath, "7f0992514818e791ba64a987b6accf88"); Logger.LogFileData(chatPath, "chat.svo"); Logger.LogDirData(patchDir, "chat patches"); if (worker != null) { worker.ReportProgress(0, "Extracting source file..."); } string extractPath = svoExtractToTempDir(chatPath); var files = Util.DirectoryGetFilesWorkaround(extractPath); int i = 0; int filecount = files.Count(x => Path.GetFileName(x).StartsWith("VC") && Path.GetFileName(x).EndsWith(".DAT")); foreach (string file in files) { string filename = Path.GetFileName(file); if (filename.StartsWith("VC") && filename.EndsWith(".DAT")) { if (worker != null) { worker.ReportProgress((i / filecount) * 100, "Patching file " + (i + 1) + " of " + filecount + "..."); } string decompPath = tlzcDecompressToTempFile(file); string skitExtractPath = svoExtractToTempDir(decompPath); XdeltaApply( Path.Combine(skitExtractPath, "0003"), Path.Combine(skitExtractPath, "0003.new"), Path.Combine(patchDir, filename + ".xdelta3") ); File.Delete(Path.Combine(skitExtractPath, "0003")); File.Move(Path.Combine(skitExtractPath, "0003.new"), Path.Combine(skitExtractPath, "0003")); using (var fps4Skit = new FPS4(decompPath)) { fps4Skit.Alignment = 0x80; fps4Skit.Pack(skitExtractPath, Path.Combine(extractPath, filename + ".new")); } tlzcCompress(Path.Combine(extractPath, filename + ".new"), file); File.Delete(decompPath); File.Delete(Path.Combine(extractPath, filename + ".new")); Util.DeleteDirectoryAggressive(skitExtractPath, true); ++i; } } if (worker != null) { worker.ReportProgress(100, "Packing modified file..."); } Logger.LogDirData(extractPath, "chat dir patched"); using (var fps4 = new FPS4(chatPath)) { fps4.Alignment = 0x800; fps4.Pack(extractPath, outPath); } Logger.LogFileData(outPath, "chat.svo patched"); Util.DeleteDirectoryAggressive(extractPath, true); if (outMd5 != null) { CompareMd5Output(outPath, outMd5); } }
public static (DuplicatableStream metrics, DuplicatableStream texture, Dictionary <char, (int w1, int w2)> charToWidthMap) Run(FileFetcher _fc, Config config) { bool debug = config.DebugFontOutputPath != null; bool adjustMetrics = debug; DuplicatableStream metricsWiiStream = _fc.GetFile("rootR.cpk/sys/FontBinary2.bin", Version.W); DuplicatableStream textureWiiStream = _fc.GetFile("rootR.cpk/sys/FontTexture2.tex", Version.W); DuplicatableStream texturePs3Stream = _fc.GetFile("rootR.cpk/sys/FontTexture2.tex", Version.U); FPS4 metricsWiiFps4 = new FPS4(metricsWiiStream); DuplicatableStream metricsWiiData = metricsWiiFps4.GetChildByIndex(1).AsFile.DataStream; FPS4 textureWiiFps4 = new FPS4(textureWiiStream); FPS4 texturePs3Fps4 = new FPS4(texturePs3Stream); TXM textureWiiTxm = new TXM(textureWiiFps4.GetChildByIndex(0).AsFile.DataStream); TXV textureWiiTxv = new TXV(textureWiiTxm, textureWiiFps4.GetChildByIndex(1).AsFile.DataStream, false); TXM texturePs3Txm = new TXM(texturePs3Fps4.GetChildByIndex(0).AsFile.DataStream); TXV texturePs3Txv = new TXV(texturePs3Txm, texturePs3Fps4.GetChildByIndex(1).AsFile.DataStream, false); Bitmap bitmapWii = textureWiiTxv.textures[0].GetBitmaps()[0]; Bitmap bitmapPs3 = texturePs3Txv.textures[0].GetBitmaps()[0]; if (debug) { Directory.CreateDirectory(config.DebugFontOutputPath); bitmapWii.Save(Path.Combine(config.DebugFontOutputPath, "wii.png")); bitmapPs3.Save(Path.Combine(config.DebugFontOutputPath, "ps3.png")); } var img_wii = bitmapWii; var img_ps3 = bitmapPs3; const int tile_extent_in_image = 25; const int tile_extent_actual = 24; int tiles_x = (img_wii.Width + 1) / tile_extent_in_image; int tiles_y = (img_wii.Height + 1) / tile_extent_in_image; const int ps3_tile_extent_in_image = 37; const int ps3_tile_extent_actual = 36; int ps3_tiles_x = (img_ps3.Width + 1) / ps3_tile_extent_in_image; int ps3_tiles_y = (img_ps3.Height + 1) / ps3_tile_extent_in_image; // split into individual tiles and extract source colors HashSet <Color> colors = new HashSet <Color>(); List <Bitmap> tiles_wii = new List <Bitmap>(); List <Bitmap> tiles_ps3 = new List <Bitmap>(); for (int ty = 0; ty < tiles_y; ++ty) { for (int tx = 0; tx < tiles_x; ++tx) { var bmp = new Bitmap(tile_extent_actual, tile_extent_actual); for (int y = 0; y < tile_extent_actual; ++y) { for (int x = 0; x < tile_extent_actual; ++x) { var px = img_wii.GetPixel(tx * tile_extent_in_image + x, ty * tile_extent_in_image + y); colors.Add(px); bmp.SetPixel(x, y, px); } } tiles_wii.Add(bmp); } } for (int ty = 0; ty < ps3_tiles_y; ++ty) { for (int tx = 0; tx < ps3_tiles_x; ++tx) { var bmp = new Bitmap(ps3_tile_extent_actual, ps3_tile_extent_actual); for (int y = 0; y < ps3_tile_extent_actual; ++y) { for (int x = 0; x < ps3_tile_extent_actual; ++x) { var px = img_ps3.GetPixel(tx * ps3_tile_extent_in_image + x, ty * ps3_tile_extent_in_image + y); bmp.SetPixel(x, y, px); } } tiles_ps3.Add(bmp); } } // inject ps3 tiles over wii tiles List <(int where, int ps3where, string chars)> charsets = new List <(int where, int ps3where, string chars)>(); charsets.Add((0, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")); charsets.Add((243, 74, ",.")); charsets.Add((246, 77, ":;?!_")); charsets.Add((254, 83, "/\\~|…")); charsets.Add((260, 118, "‘")); charsets.Add((261, 118, "’")); charsets.Add((262, 119, "“")); charsets.Add((263, 119, "”")); charsets.Add((264, 93, "()[]{}")); charsets.Add((276, 105, "+")); charsets.Add((277, 82, "-")); // copy the dash minus instead of the math minus, looks better in text flow charsets.Add((278, 107, "±×÷=≠<>≤≥")); charsets.Add((289, 118, "'\"")); charsets.Add((293, 122, "$%#&*@")); Dictionary <char, (int w1, int w2)> charToWidthMap = new Dictionary <char, (int w1, int w2)>(); byte[] metrics = new byte[metricsWiiData.Length]; metricsWiiData.Read(metrics, 0, metrics.Length); foreach (var charset in charsets) { int where = charset.where; int ps3where = charset.ps3where; foreach (char ch in charset.chars) { var wiitile = tiles_wii[where]; var averagescaled = DownscaleTileFromPs3ToWiiWithUnweightedAverageScaling(tiles_ps3[ps3where]); //var downscaled = DownscaleTileFromPs3ToWiiWithWeightedScaling(tiles_ps3[ps3where]); var downscaled = averagescaled; PosterizeImage(wiitile, downscaled, colors, tile_extent_actual); PosterizeImage(averagescaled, averagescaled, colors, tile_extent_actual); if (debug) { wiitile.Save(Path.Combine(config.DebugFontOutputPath, string.Format("wii_new_{0:D4}.png", where))); } int cutoff_1 = 180; int cutoff_2 = 220; int leftwhere = where * 8 + 0; int rightwhere = where * 8 + 1; int leftwhere2 = where * 8 + 4; int rightwhere2 = where * 8 + 5; // forcing vertical extents to be the same for all, because text looks *really weird* in english if lines have different heights // for digits, forcing horizontal extents to be the same as well so they look nice in vertical lists bool isDigit = ch == '0' || ch == '1' || ch == '2' || ch == '3' || ch == '4' || ch == '5' || ch == '6' || ch == '7' || ch == '8' || ch == '9'; if (isDigit) { metrics[leftwhere] = ch == '1' ? (byte)(6) : ch == '2' ? (byte)(6) : (byte)(7); metrics[rightwhere] = ch == '1' ? (byte)(8) : ch == '2' ? (byte)(8) : (byte)(7); //metrics[leftwhere2] = ch == '1' ? (byte)(7) : ch == '2' ? (byte)(7) : (byte)(8); //metrics[rightwhere2] = ch == '1' ? (byte)(9) : ch == '2' ? (byte)(9) : (byte)(8); } else { metrics[leftwhere] = (byte)MeasureAlphaFromLeft(averagescaled, cutoff_1); metrics[rightwhere] = (byte)MeasureAlphaFromRight(averagescaled, cutoff_1); //metrics[leftwhere2] = (byte)MeasureAlphaFromLeft(averagescaled, cutoff_2); //metrics[rightwhere2] = (byte)MeasureAlphaFromRight(averagescaled, cutoff_2); } switch (ch) { case 'j': case ';': metrics[leftwhere] += 1; break; case 'A': case 'P': case 'Q': case 'T': case 'Y': case 'W': case 'f': case 's': case 'w': case 'y': case '[': metrics[rightwhere] += 1; break; case 't': metrics[leftwhere] += 1; metrics[rightwhere] += 1; break; default: break; } metrics[leftwhere2] = metrics[leftwhere]; metrics[rightwhere2] = metrics[rightwhere]; switch (ch) { case '.': case ',': metrics[leftwhere2] += 1; metrics[rightwhere] += 1; break; default: break; } metrics[where * 8 + 2] = 0; //(byte)MeasureAlphaFromTop(test, cutoff_1); metrics[where * 8 + 3] = 4; //(byte)MeasureAlphaFromBottom(test, cutoff_1); metrics[where * 8 + 6] = 0; //(byte)MeasureAlphaFromTop(test, cutoff_2); metrics[where * 8 + 7] = 4; //(byte)MeasureAlphaFromBottom(test, cutoff_2); int width1 = tile_extent_actual - (metrics[leftwhere] + metrics[rightwhere]); int width2 = tile_extent_actual - (metrics[leftwhere2] + metrics[rightwhere2]); charToWidthMap.Add(ch, (width1, width2)); ++where; ++ps3where; } } // manually generate good metrics for space; see also code patches in main.dol metrics[0x6F70] = 10; metrics[0x6F71] = 10; metrics[0x6F72] = 0; metrics[0x6F73] = 4; metrics[0x6F74] = 10; metrics[0x6F75] = 10; metrics[0x6F76] = 0; metrics[0x6F77] = 4; charToWidthMap.Add(' ', (tile_extent_actual - 20, tile_extent_actual - 20)); // write out visual representation of font metrics for adjustments if (adjustMetrics) { foreach (var charset in charsets) { int where = charset.where; foreach (char ch in charset.chars) { int factor = 10; var test = PointScale(tiles_wii[where], factor); for (int metricsset = 0; metricsset < 2; ++metricsset) { Color col = metricsset == 0 ? Color.Red : Color.Yellow; int xl = (metrics[where * 8 + metricsset * 4] - 1) * factor + factor - 1; int xr = (tiles_wii[where].Width - metrics[where * 8 + metricsset * 4 + 1]) * factor; int yt = (metrics[where * 8 + metricsset * 4 + 2] - 1) * factor + factor - 1; int yb = (tiles_wii[where].Width - metrics[where * 8 + metricsset * 4 + 3]) * factor; for (int y = 0; y < test.Height; ++y) { if (xl >= 0 && xl < test.Width) { test.SetPixel(xl, y, col); } if (xr >= 0 && xr < test.Width) { test.SetPixel(xr, y, col); } } for (int x = 0; x < test.Width; ++x) { if (yt >= 0 && yt < test.Height) { test.SetPixel(x, yt, col); } if (yb >= 0 && yb < test.Height) { test.SetPixel(x, yb, col); } } } PointScale(test, 3).Save(Path.Combine(config.DebugFontOutputPath, string.Format("metrics_view_{0:D4}.png", where))); ++where; } } } // join indvidiual tiles back into full texture int idx = 0; for (int ty = 0; ty < tiles_y; ++ty) { for (int tx = 0; tx < tiles_x; ++tx) { var bmp = tiles_wii[idx]; for (int y = 0; y < tile_extent_actual; ++y) { for (int x = 0; x < tile_extent_actual; ++x) { var px = bmp.GetPixel(x, y); img_wii.SetPixel(tx * tile_extent_in_image + x, ty * tile_extent_in_image + y, px); } } ++idx; } } if (debug) { img_wii.Save(Path.Combine(config.DebugFontOutputPath, "wii_new.png")); } // inject metrics DuplicatableStream outputMetricsStream; { Stream stream = metricsWiiStream.Duplicate().CopyToMemory(); stream.Position = 0x43E0; stream.Write(metrics); stream.Position = 0; byte[] data = new byte[stream.Length]; stream.Read(data, 0, data.Length); outputMetricsStream = new HyoutaUtils.Streams.DuplicatableByteArrayStream(data); } // encode texture DuplicatableStream outputTextureStream; { Stream stream = textureWiiStream.Duplicate().CopyToMemory(); stream.Position = 0x80100; List <(int idx, ushort v)> stuff = new List <(int idx, ushort v)>(); for (int i = 0; i < 16; ++i) { stuff.Add((i, stream.ReadUInt16().FromEndian(EndianUtils.Endianness.BigEndian))); } stream.Position = 0x100; var pxit = new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(img_wii.Width, img_wii.Height, 8, 8); byte storage = 0; bool even = false; foreach (var px in pxit) { if (px.X < img_wii.Width && px.Y < img_wii.Height) { Color col = img_wii.GetPixel(px.X, px.Y); ushort value = HyoutaTools.Textures.ColorFetchingIterators.ColorFetcherGrey8Alpha8.ColorToGrey8Alpha8(col); var colidx = stuff.First(x => x.v == value).idx; if (!even) { storage = (byte)colidx; } else { storage = (byte)(storage << 4 | (byte)colidx); stream.WriteByte(storage); } even = !even; } } stream.Position = 0; byte[] data = new byte[stream.Length]; stream.Read(data, 0, data.Length); outputTextureStream = new HyoutaUtils.Streams.DuplicatableByteArrayStream(data); } return(outputMetricsStream, outputTextureStream, charToWidthMap); }
public static void PatchUI(string uiPath, string patchDir, string outDir, string outMd5 = null, BackgroundWorker worker = null) { if (!File.Exists(uiPath)) { throw new PatchingException("File not found: " + uiPath); } if (worker != null) { worker.ReportProgress(0, "Confirming source file..."); } // if patched file exists and matches, exit early string outPath = Path.Combine(outDir, "UI.svo"); try { CompareMd5Output(outPath, outMd5); return; } catch (PatchingException) { } catch (FileNotFoundException) { } CompareMd5(uiPath, "9d0a479c838c4811e5df5f6a6815071d"); Logger.LogFileData(uiPath, "UI.svo"); Logger.LogDirData(patchDir, "UI patches"); // extract if (worker != null) { worker.ReportProgress(0, "Extracting source file..."); } string extractPath = svoExtractToTempDir(uiPath); // patch int i = 0; var files = Util.DirectoryGetFilesWorkaround(patchDir); foreach (string patch in files) { if (worker != null) { worker.ReportProgress((i / files.Length) * 100, "Patching file " + (i + 1) + " of " + files.Length + "..."); } string fileName = Path.GetFileNameWithoutExtension(patch); string sourcePath = Path.Combine(extractPath, fileName); string patchedPath = TempUtil.GetTempFileName(); XdeltaApply(sourcePath, patchedPath, patch); File.Delete(sourcePath); File.Move(patchedPath, sourcePath); ++i; } // copy unchanged 360 english files over japanese ones File.Copy(Path.Combine(extractPath, "MINIGAMEISHI_E.TXV"), Path.Combine(extractPath, "MINIGAMEISHI.TXV"), true); File.Copy(Path.Combine(extractPath, "EVENTMAP_E.TXV"), Path.Combine(extractPath, "EVENTMAP.TXV"), true); // copy english poker text textures to new PS3 poker deck BlockCopy(Path.Combine(extractPath, "MINIGAMEPOKER_E.TXV"), 0x0, Path.Combine(extractPath, "MINIGAMEPOKER.TXV"), 0x0, 0x6AB900); BlockCopy(Path.Combine(extractPath, "MINIGAMEPOKER_E.TXV"), 0x14519E0, Path.Combine(extractPath, "MINIGAMEPOKER.TXV"), 0x14519E0, 0x5E620); // pack if (worker != null) { worker.ReportProgress(100, "Packing modified file..."); } Logger.LogDirData(extractPath, "UI dir patched"); using (var fps4btl = new FPS4(uiPath)) { fps4btl.Alignment = 0x800; fps4btl.Pack(extractPath, outPath); } Logger.LogFileData(outPath, "UI.svo patched"); Util.DeleteDirectoryAggressive(extractPath, true); if (outMd5 != null) { CompareMd5Output(outPath, outMd5); } }
public static void PatchEffect(string effectPath, string patchDir, string outDir, string outMd5 = null, BackgroundWorker worker = null) { if (!File.Exists(effectPath)) { throw new PatchingException("File not found: " + effectPath); } if (worker != null) { worker.ReportProgress(0, "Confirming source file..."); } // if patched file exists and matches, exit early string outPath = Path.Combine(outDir, "effect.svo"); try { CompareMd5Output(outPath, outMd5); return; } catch (PatchingException) { } catch (FileNotFoundException) { } CompareMd5(effectPath, "ada3bdb2e2ca481b44bc9e209b019dc8"); Logger.LogFileData(effectPath, "effect.svo"); Logger.LogDirData(patchDir, "effect patches"); // extract effect.svo if (worker != null) { worker.ReportProgress(0, "Extracting source file..."); } string extractPath = svoExtractToTempDir(effectPath); if (worker != null) { worker.ReportProgress(0, "Patching files..."); } // image assets for SURPRISE ENCOUNTER! and so on string surpriseJpn = tlzcDecompressToTempFile(Path.Combine(extractPath, "E_A023.DAT")); string surpriseEng = tlzcDecompressToTempFile(Path.Combine(extractPath, "E_A034.DAT")); BlockCopy(surpriseEng, 0x100, surpriseJpn, 0x100, 0x80000); tlzcCompress(surpriseJpn, Path.Combine(extractPath, "E_A023.DAT")); System.IO.File.Delete(surpriseJpn); System.IO.File.Delete(surpriseEng); // image assets for game over screen string gameover = tlzcDecompressToTempFile(Path.Combine(extractPath, "E_A104_GAMEOVER.DAT")); BlockCopy(gameover, 0x55D80, gameover, 0xD80, 0x55000); BlockCopy(gameover, 0x55D80, gameover, 0xAAD80, 0x55000); tlzcCompress(gameover, Path.Combine(extractPath, "E_A104_GAMEOVER.DAT")); System.IO.File.Delete(gameover); // image assets for dice minigame string dice1 = tlzcDecompressToTempFile(Path.Combine(extractPath, "E_MG_STONERESULT01.DAT")); BlockCopy(dice1, 0x100, dice1, 0x100100, 0x100000); tlzcCompress(dice1, Path.Combine(extractPath, "E_MG_STONERESULT01.DAT")); System.IO.File.Delete(dice1); string dice2 = tlzcDecompressToTempFile(Path.Combine(extractPath, "E_MG_STONERESULT02.DAT")); BlockCopy(dice2, 0x100, dice2, 0x100100, 0x100000); tlzcCompress(dice2, Path.Combine(extractPath, "E_MG_STONERESULT02.DAT")); System.IO.File.Delete(dice2); // remaining assets with xdelta patches foreach (string patch in Util.DirectoryGetFilesWorkaround(patchDir)) { string fileName = Path.GetFileNameWithoutExtension(patch); string sourcePath = Path.Combine(extractPath, fileName + ".DAT"); string decompressedPath = tlzcDecompressToTempFile(sourcePath); string patchedPath = TempUtil.GetTempFileName(); XdeltaApply(decompressedPath, patchedPath, patch); tlzcCompress(patchedPath, sourcePath); System.IO.File.Delete(decompressedPath); System.IO.File.Delete(patchedPath); } // pack up modified effect.svo if (worker != null) { worker.ReportProgress(100, "Packing modified file..."); } Logger.LogDirData(extractPath, "effect dir patched"); using (var fps4 = new FPS4(effectPath)) { fps4.Alignment = 0x800; fps4.Pack(extractPath, outPath); } Logger.LogFileData(outPath, "effect.svo patched"); // clean up Util.DeleteDirectoryAggressive(extractPath, true); if (outMd5 != null) { CompareMd5Output(outPath, outMd5); } }
public FPS4FileSystem(FPS4 FPS4) { this.FPS4 = FPS4; }