From bc802748b0c469421a00ce517a60785ce32bc2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sat, 1 Jul 2023 19:44:38 -0400 Subject: [PATCH 01/18] Add work-in-progress GCI auto-rename feature for replays --- .gitignore | 2 + libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- libs/Manifold.Core | 2 +- src/gfz-cli/ActionsGCI.cs | 58 ++++++++++++++++++++++ src/gfz-cli/GfzCliActions.cs | 2 + src/gfz-cli/Program.cs | 2 + src/gfz-cli/Properties/launchSettings.json | 4 ++ src/gfz-cli/gfz-cli.csproj | 3 ++ src/gfz-cli/gfz-cli.sln | 30 +++++++++++ 10 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 src/gfz-cli/ActionsGCI.cs diff --git a/.gitignore b/.gitignore index cf0e572..4616c05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Ignore build.bat files [Bb]uild [Bb]uilds +#Local files can be placed here +[Ll]ocal ############################################################################################## diff --git a/libs/GameCube.Core b/libs/GameCube.Core index 1060786..8119d9b 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit 1060786e598f502f0bd771a8e8beb87da56b5217 +Subproject commit 8119d9be3fb947b1a6930fad2ed9883c8e4e604a diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index b120301..1cabd2c 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit b1203018e7d94aaea86d469bec41f1303056eb47 +Subproject commit 1cabd2cf2806ea4bf58108920b5430087673da3f diff --git a/libs/Manifold.Core b/libs/Manifold.Core index 091c627..c28b43a 160000 --- a/libs/Manifold.Core +++ b/libs/Manifold.Core @@ -1 +1 @@ -Subproject commit 091c627d5e98a0643833bc7e5b8db8eb476ce9ba +Subproject commit c28b43ac18f4b7be700e14ddbb1dfbca8afcdb34 diff --git a/src/gfz-cli/ActionsGCI.cs b/src/gfz-cli/ActionsGCI.cs new file mode 100644 index 0000000..99082c8 --- /dev/null +++ b/src/gfz-cli/ActionsGCI.cs @@ -0,0 +1,58 @@ +using GameCube.GCI; +using GameCube.GFZ.Replay; +using Manifold.IO; +using System.IO; +using static Manifold.GFZCLI.GfzCliUtilities; + +namespace Manifold.GFZCLI +{ + public class ActionsGCI + { + public static void RenameGCI(Options options) + { + Terminal.WriteLine("GCI: converting emblems from BIN files."); + int fileCount = DoFileInFileOutTasks(options, RenameGciFile); + Terminal.WriteLine($"GCI: done renaming {fileCount} file{Plural(fileCount)}."); + } + + public static void RenameGciFile(Options options, FilePath inputFilePath, FilePath outputFilePath) + { + Gci gci = new Gci(); + inputFilePath.ThrowIfDoesNotExist(); + using var reader = new EndianBinaryReader(File.OpenRead(inputFilePath), Gci.endianness); + gci.Deserialize(reader); + reader.SeekBegin(); + + string name = GetName(gci.UniqueID, reader); + outputFilePath.SetName(name); + + var fileWrite = () => + { + File.Copy(inputFilePath, outputFilePath, options.OverwriteFiles); + }; + var info = new FileWriteInfo() + { + InputFilePath = inputFilePath, + OutputFilePath = outputFilePath, + PrintDesignator = "GCI", + PrintActionDescription = "renaming file", + }; + FileWriteOverwriteHandler(options, fileWrite, info); + } + + public static string GetName(ushort uniqueID, EndianBinaryReader reader) + { + switch (uniqueID) + { + case ReplayGCI.UID: + var replay = new ReplayGCI(); + replay.Deserialize(reader); + return "replay"; + + default: + return "UNHANDLED"; + } + } + + } +} diff --git a/src/gfz-cli/GfzCliActions.cs b/src/gfz-cli/GfzCliActions.cs index 80185a7..ddfeb40 100644 --- a/src/gfz-cli/GfzCliActions.cs +++ b/src/gfz-cli/GfzCliActions.cs @@ -7,6 +7,8 @@ public enum GfzCliAction arc_decompress, arc_compress, + auto_rename_gci, + cardata_bin_to_tsv, cardata_tsv_to_bin, diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index caa0d89..aace2d8 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -60,6 +60,8 @@ public static void ExecuteAction(Options options) // ARC case GfzCliAction.arc_compress: ActionsARC.ArcCompress(options); break; case GfzCliAction.arc_decompress: ActionsARC.ArcDecompress(options); break; + // + case GfzCliAction.auto_rename_gci: ActionsGCI.RenameGCI(options); break; // CARDATA case GfzCliAction.cardata_bin_to_tsv: ActionsCarData.CarDataBinToTsv(options); break; case GfzCliAction.cardata_tsv_to_bin: ActionsCarData.CarDataTsvToBin(options); break; diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index 7256c27..5e82aa5 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -66,6 +66,10 @@ "arc-compress": { "commandName": "Project", "commandLineArgs": "arc-compress D:\\test-gfz\\maybe\\jpeg\\compo\\ --search-subdirs --overwrite --search-pattern \"*\"" + }, + "gci": { + "commandName": "Project", + "commandLineArgs": "auto-rename-gci D:\\test-gfz\\ --search-subdirs --search-pattern \"*.gci\"" } } } \ No newline at end of file diff --git a/src/gfz-cli/gfz-cli.csproj b/src/gfz-cli/gfz-cli.csproj index 1ec95ae..11c0dee 100644 --- a/src/gfz-cli/gfz-cli.csproj +++ b/src/gfz-cli/gfz-cli.csproj @@ -20,7 +20,9 @@ + + @@ -32,6 +34,7 @@ + diff --git a/src/gfz-cli/gfz-cli.sln b/src/gfz-cli/gfz-cli.sln index 8962858..49edd5e 100644 --- a/src/gfz-cli/gfz-cli.sln +++ b/src/gfz-cli/gfz-cli.sln @@ -51,6 +51,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.GFZ.Emblem", "..\. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.DiskImage", "..\..\libs\GameCube.Core\src\GameCube.DiskImage\GameCube.DiskImage.csproj", "{61FBA1BF-80A4-4E23-BC10-E12E5BA446B3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.GCI", "..\..\libs\GameCube.Core\src\GameCube.GCI\GameCube.GCI.csproj", "{389098C7-62D4-4E44-A8A6-03B749CD764F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.GFZ.Replay", "..\..\libs\GameCube.GFZ\src\GameCube.GFZ.Replay\GameCube.GFZ.Replay.csproj", "{75153813-979F-4802-BB80-FB03AA853751}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.Common", "..\..\libs\GameCube.Core\src\GameCube.Common\GameCube.Common.csproj", "{01014172-CB65-438C-BA04-BA22619A679B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -251,6 +257,30 @@ Global {61FBA1BF-80A4-4E23-BC10-E12E5BA446B3}.Release|Any CPU.Build.0 = Release|Any CPU {61FBA1BF-80A4-4E23-BC10-E12E5BA446B3}.Release|x64.ActiveCfg = Release|Any CPU {61FBA1BF-80A4-4E23-BC10-E12E5BA446B3}.Release|x64.Build.0 = Release|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Debug|x64.ActiveCfg = Debug|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Debug|x64.Build.0 = Debug|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Release|Any CPU.Build.0 = Release|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Release|x64.ActiveCfg = Release|Any CPU + {389098C7-62D4-4E44-A8A6-03B749CD764F}.Release|x64.Build.0 = Release|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Debug|x64.ActiveCfg = Debug|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Debug|x64.Build.0 = Debug|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Release|Any CPU.Build.0 = Release|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Release|x64.ActiveCfg = Release|Any CPU + {75153813-979F-4802-BB80-FB03AA853751}.Release|x64.Build.0 = Release|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Debug|x64.ActiveCfg = Debug|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Debug|x64.Build.0 = Debug|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Release|Any CPU.Build.0 = Release|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Release|x64.ActiveCfg = Release|Any CPU + {01014172-CB65-438C-BA04-BA22619A679B}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 9e0aef73c75141b766974ffefd14d5a46c702616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sat, 1 Jul 2023 23:49:03 -0400 Subject: [PATCH 02/18] Update submodules --- libs/GameCube.GFZ | 2 +- libs/Manifold.Core | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 1cabd2c..c1ba609 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 1cabd2cf2806ea4bf58108920b5430087673da3f +Subproject commit c1ba6096ef1e173dfad7a48f4169bd541c4f32b4 diff --git a/libs/Manifold.Core b/libs/Manifold.Core index c28b43a..ff37155 160000 --- a/libs/Manifold.Core +++ b/libs/Manifold.Core @@ -1 +1 @@ -Subproject commit c28b43ac18f4b7be700e14ddbb1dfbca8afcdb34 +Subproject commit ff37155ad54e977c38b36477ee8124c41af76ddd From 02145998a456aaeeb0c7e7834303511c907ab7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 2 Jul 2023 00:50:36 -0400 Subject: [PATCH 03/18] Update submodules --- libs/GameCube.GFZ | 2 +- libs/Manifold.Core | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index c1ba609..3451222 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit c1ba6096ef1e173dfad7a48f4169bd541c4f32b4 +Subproject commit 3451222f2d789565290cd085c5c053018b917026 diff --git a/libs/Manifold.Core b/libs/Manifold.Core index ff37155..73603cd 160000 --- a/libs/Manifold.Core +++ b/libs/Manifold.Core @@ -1 +1 @@ -Subproject commit ff37155ad54e977c38b36477ee8124c41af76ddd +Subproject commit 73603cd60a8aa076820924080928a2089e0e9073 From d4c26d313d62572fbe73db6a9a6443a3778e2a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 2 Jul 2023 13:40:43 -0400 Subject: [PATCH 04/18] Set aside Replay GCI parsing for now --- libs/GameCube.GFZ | 2 +- libs/Manifold.Core | 2 +- src/gfz-cli/Program.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 3451222..25842fa 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 3451222f2d789565290cd085c5c053018b917026 +Subproject commit 25842fa7c1436c704eae451be1d493176334a798 diff --git a/libs/Manifold.Core b/libs/Manifold.Core index 73603cd..b9e20b2 160000 --- a/libs/Manifold.Core +++ b/libs/Manifold.Core @@ -1 +1 @@ -Subproject commit 73603cd60a8aa076820924080928a2089e0e9073 +Subproject commit b9e20b2d6208cb2d4d36e2f3fea86c006aabd6a1 diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index aace2d8..50f468c 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -60,8 +60,8 @@ public static void ExecuteAction(Options options) // ARC case GfzCliAction.arc_compress: ActionsARC.ArcCompress(options); break; case GfzCliAction.arc_decompress: ActionsARC.ArcDecompress(options); break; - // - case GfzCliAction.auto_rename_gci: ActionsGCI.RenameGCI(options); break; + // GCI Utility + //case GfzCliAction.auto_rename_gci: ActionsGCI.RenameGCI(options); break; // CARDATA case GfzCliAction.cardata_bin_to_tsv: ActionsCarData.CarDataBinToTsv(options); break; case GfzCliAction.cardata_tsv_to_bin: ActionsCarData.CarDataTsvToBin(options); break; From c4cbdc75b0e5cd33e1e070b65cacf6238ab46fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 2 Jul 2023 16:07:42 -0400 Subject: [PATCH 05/18] Add small pipeline for testing GhostData --- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsGhost.cs | 44 ++++++++++++++ src/gfz-cli/ActionsMisc.cs | 69 ++++++++++++++++++++++ src/gfz-cli/GfzCliActions.cs | 5 ++ src/gfz-cli/Program.cs | 5 ++ src/gfz-cli/Properties/launchSettings.json | 4 ++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/gfz-cli/ActionsGhost.cs create mode 100644 src/gfz-cli/ActionsMisc.cs diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 25842fa..6684736 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 25842fa7c1436c704eae451be1d493176334a798 +Subproject commit 6684736e42f69b59751039bd42c19097c5223b8a diff --git a/src/gfz-cli/ActionsGhost.cs b/src/gfz-cli/ActionsGhost.cs new file mode 100644 index 0000000..bc7eda7 --- /dev/null +++ b/src/gfz-cli/ActionsGhost.cs @@ -0,0 +1,44 @@ +using GameCube.GFZ.Ghosts; +using Manifold.IO; +using System.IO; +using static Manifold.GFZCLI.GfzCliUtilities; + +namespace Manifold.GFZCLI +{ + public class ActionsGhost + { + public static void ReadGhosts(Options options) + { + Terminal.WriteLine("Ghost: reading ghost data."); + int binCount = DoFileInFileOutTasks(options, ReadGhost); + Terminal.WriteLine($"Ghost: done reading {binCount} file{Plural(binCount)}."); + } + + private static void ReadGhost(Options options, FilePath inputFile, FilePath outputFile) + { + // Read BIN Emblem data + var ghost = new GhostData(); + using (var reader = new EndianBinaryReader(File.OpenRead(inputFile), GhostData.endianness)) + { + ghost.Deserialize(reader); + ghost.FileName = Path.GetFileNameWithoutExtension(inputFile); + } + + outputFile.AppendExtension(".bin"); + var fileWrite = () => + { + using var writer = new EndianBinaryWriter(File.Create(outputFile), GhostData.endianness); + writer.Write(ghost); + }; + var info = new FileWriteInfo() + { + InputFilePath = inputFile, + OutputFilePath = outputFile, + PrintDesignator = "GHOST", + PrintActionDescription = "writing file", + }; + FileWriteOverwriteHandler(options, fileWrite, info); + } + + } +} diff --git a/src/gfz-cli/ActionsMisc.cs b/src/gfz-cli/ActionsMisc.cs new file mode 100644 index 0000000..bd876a2 --- /dev/null +++ b/src/gfz-cli/ActionsMisc.cs @@ -0,0 +1,69 @@ +using GameCube.GFZ.Replay; +using Manifold.IO; +using System.IO; +using static Manifold.GFZCLI.GfzCliUtilities; + +namespace Manifold.GFZCLI +{ + public static class ActionsMisc + { + public static void DumpHex32(Options options) + { + var inputFilePaths = GetInputFiles(options); + var readers = new EndianBinaryReader[inputFilePaths.Length]; + for (int i = 0; i < readers.Length; i++) + { + readers[i] = new EndianBinaryReader(File.OpenRead(inputFilePaths[i]), Endianness.BigEndian); + } + + string outputPath = GetOutputDirectory(options); + FilePath fileOutputPath = new FilePath(outputPath); + fileOutputPath.SetName("test"); + fileOutputPath.SetExtension("tsv"); + using var writer = new StreamWriter(File.Create(fileOutputPath)); + + writer.WriteNextCol("Filename:"); + for (int i = 0; i < inputFilePaths.Length; i++) + { + string name = Path.GetFileNameWithoutExtension(inputFilePaths[i]); + writer.WriteNextCol(name); + } + writer.WriteNextRow(); + + int address = 0; + int streamsCompleted = 0; + while (streamsCompleted < readers.Length) + { + streamsCompleted = 0; + for (int i = 0; i < readers.Length; i++) + { + // Write address + if (i == 0) + writer.WriteNextCol($"0x{address:x4}"); + + // Only write if able + var reader = readers[i]; + if (reader.IsAtEndOfStream()) + { + streamsCompleted++; + writer.WriteNextCol(); + continue; + } + + // Write data + var value = reader.ReadUInt16(); + writer.WriteNextCol($"0x{value:x4}"); + // hack + address = reader.GetPositionAsPointer(); + + // End line + if (i == readers.Length - 1) + writer.WriteNextRow(); + } + } + + foreach (var reader in readers) + reader.Close(); + } + } +} diff --git a/src/gfz-cli/GfzCliActions.cs b/src/gfz-cli/GfzCliActions.cs index ddfeb40..94a7cb8 100644 --- a/src/gfz-cli/GfzCliActions.cs +++ b/src/gfz-cli/GfzCliActions.cs @@ -19,6 +19,8 @@ public enum GfzCliAction image_to_emblem_bin, image_to_emblem_gci, + read_ghost, + live_camera_stage_bin_to_tsv, live_camera_stage_tsv_to_bin, @@ -26,5 +28,8 @@ public enum GfzCliAction lz_decompress, tpl_unpack, + + // + dump_hex, } } diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index 50f468c..247f9fa 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -72,6 +72,8 @@ public static void ExecuteAction(Options options) case GfzCliAction.emblem_gci_to_image: ActionsEmblem.EmblemGciToImage(options); break; case GfzCliAction.image_to_emblem_bin: ActionsEmblem.ImageToEmblemBIN(options); break; case GfzCliAction.image_to_emblem_gci: ActionsEmblem.ImageToEmblemGCI(options); break; + // + case GfzCliAction.read_ghost: ActionsGhost.ReadGhosts(options); break; // LIVE CAMERA STAGE case GfzCliAction.live_camera_stage_bin_to_tsv: ActionsLiveCameraStage.LiveCameraStageBinToTsv(options); break; case GfzCliAction.live_camera_stage_tsv_to_bin: ActionsLiveCameraStage.LiveCameraStageTsvToBin(options); break; @@ -82,6 +84,9 @@ public static void ExecuteAction(Options options) case GfzCliAction.tpl_unpack: ActionsTPL.TplUnpack(options); break; //case GfzCliAction.tpl_pack: TplPack(options); break; + // + case GfzCliAction.dump_hex: ActionsMisc.DumpHex32(options); break; + // UNSET case GfzCliAction.none: { diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index 5e82aa5..ffd6ec5 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -70,6 +70,10 @@ "gci": { "commandName": "Project", "commandLineArgs": "auto-rename-gci D:\\test-gfz\\ --search-subdirs --search-pattern \"*.gci\"" + }, + "dump-hex-32": { + "commandName": "Project", + "commandLineArgs": "read-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"ghost1.dat\" --overwrite" } } } \ No newline at end of file From 586648c047980cfde1e5bb167fcdc0f15548ae77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 2 Jul 2023 23:13:57 -0400 Subject: [PATCH 06/18] m: WIP solve ghost data (use commit to easily edit data) --- src/gfz-cli/ActionsGhost.cs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/gfz-cli/ActionsGhost.cs b/src/gfz-cli/ActionsGhost.cs index bc7eda7..6433fec 100644 --- a/src/gfz-cli/ActionsGhost.cs +++ b/src/gfz-cli/ActionsGhost.cs @@ -27,8 +27,40 @@ private static void ReadGhost(Options options, FilePath inputFile, FilePath outp outputFile.AppendExtension(".bin"); var fileWrite = () => { - using var writer = new EndianBinaryWriter(File.Create(outputFile), GhostData.endianness); - writer.Write(ghost); + // 0: ghost does not appear. Can win if time is better than timestamp in file. + // 1: timestamp seconds? When behind, estimate is borked AF. + // UNKNOWN + //ghost.Mutate(0, 0); // interpolation mode? 1-4 + //ghost.Mutate(1, 0); // UNK lap data. Seems almost like "which lap", but 02 not on final dat + + // ROTATION + //ghost.Mutate(2, 0); + //ghost.Mutate(3, 0); + //ghost.Mutate(4, 0); + //ghost.Mutate(5, 0); + //ghost.Mutate(6, 0); + //ghost.Mutate(7, 0); + + // POSITION + // 8+ 9: pos x + // 10+11: pos y + // 12+13: pos z + //ghost.Mutate(8, 0); + //ghost.Mutate(9, 0); + //ghost.Mutate(10, 0); + //ghost.Mutate(11, 0); + //ghost.Mutate(12, 0); + //ghost.Mutate(13, 0); + + // INTERPOLATION - maybe fixed point duration? + //ghost.Mutate(14, 0); + //ghost.Mutate(15, 0); + + using (var writer = new EndianBinaryWriter(File.Create(outputFile), GhostData.endianness)) + { + writer.Write(ghost); + } + File.Copy(outputFile, "D:\\boot-gfzj\\files\\staff_ghost\\" + outputFile.Name + ".dat", true); }; var info = new FileWriteInfo() { From 6ab1eba2a8314071f2f0d16281c56f9b0909d026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Mon, 3 Jul 2023 00:38:10 -0400 Subject: [PATCH 07/18] Add ability to read ghost data. TODO: make this useful ;) --- libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsGhost.cs | 38 +++------------------- src/gfz-cli/Properties/launchSettings.json | 4 +-- 4 files changed, 8 insertions(+), 38 deletions(-) diff --git a/libs/GameCube.Core b/libs/GameCube.Core index 8119d9b..c51ff66 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit 8119d9be3fb947b1a6930fad2ed9883c8e4e604a +Subproject commit c51ff664a86e9d69add5735ddec064d13b127268 diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 6684736..4b6206c 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 6684736e42f69b59751039bd42c19097c5223b8a +Subproject commit 4b6206c3629481569b163c220bee0b1cd16d8d53 diff --git a/src/gfz-cli/ActionsGhost.cs b/src/gfz-cli/ActionsGhost.cs index 6433fec..5756488 100644 --- a/src/gfz-cli/ActionsGhost.cs +++ b/src/gfz-cli/ActionsGhost.cs @@ -9,6 +9,7 @@ public class ActionsGhost { public static void ReadGhosts(Options options) { + //string[] files = GetInputFiles(options); Terminal.WriteLine("Ghost: reading ghost data."); int binCount = DoFileInFileOutTasks(options, ReadGhost); Terminal.WriteLine($"Ghost: done reading {binCount} file{Plural(binCount)}."); @@ -24,43 +25,12 @@ private static void ReadGhost(Options options, FilePath inputFile, FilePath outp ghost.FileName = Path.GetFileNameWithoutExtension(inputFile); } + // TODO: parameterize extensions outputFile.AppendExtension(".bin"); var fileWrite = () => { - // 0: ghost does not appear. Can win if time is better than timestamp in file. - // 1: timestamp seconds? When behind, estimate is borked AF. - // UNKNOWN - //ghost.Mutate(0, 0); // interpolation mode? 1-4 - //ghost.Mutate(1, 0); // UNK lap data. Seems almost like "which lap", but 02 not on final dat - - // ROTATION - //ghost.Mutate(2, 0); - //ghost.Mutate(3, 0); - //ghost.Mutate(4, 0); - //ghost.Mutate(5, 0); - //ghost.Mutate(6, 0); - //ghost.Mutate(7, 0); - - // POSITION - // 8+ 9: pos x - // 10+11: pos y - // 12+13: pos z - //ghost.Mutate(8, 0); - //ghost.Mutate(9, 0); - //ghost.Mutate(10, 0); - //ghost.Mutate(11, 0); - //ghost.Mutate(12, 0); - //ghost.Mutate(13, 0); - - // INTERPOLATION - maybe fixed point duration? - //ghost.Mutate(14, 0); - //ghost.Mutate(15, 0); - - using (var writer = new EndianBinaryWriter(File.Create(outputFile), GhostData.endianness)) - { - writer.Write(ghost); - } - File.Copy(outputFile, "D:\\boot-gfzj\\files\\staff_ghost\\" + outputFile.Name + ".dat", true); + using var writer = new EndianBinaryWriter(File.Create(outputFile), GhostData.endianness); + writer.Write(ghost); }; var info = new FileWriteInfo() { diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index ffd6ec5..c29ee18 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -71,9 +71,9 @@ "commandName": "Project", "commandLineArgs": "auto-rename-gci D:\\test-gfz\\ --search-subdirs --search-pattern \"*.gci\"" }, - "dump-hex-32": { + "read-ghost": { "commandName": "Project", - "commandLineArgs": "read-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"ghost1.dat\" --overwrite" + "commandLineArgs": "read-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"*.dat\" --overwrite" } } } \ No newline at end of file From a322182693f510d7982700dc4509c9b9bedff3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Wed, 5 Jul 2023 00:51:17 -0400 Subject: [PATCH 08/18] Convert read-ghost into gci-extract-ghost --- libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsGCI.cs | 2 +- src/gfz-cli/ActionsGhost.cs | 24 +++++++++++++--------- src/gfz-cli/ActionsMisc.cs | 2 +- src/gfz-cli/FilePath.cs | 2 +- src/gfz-cli/GfzCliActions.cs | 2 +- src/gfz-cli/Program.cs | 2 +- src/gfz-cli/Properties/launchSettings.json | 4 ++-- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/libs/GameCube.Core b/libs/GameCube.Core index c51ff66..44cd0b6 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit c51ff664a86e9d69add5735ddec064d13b127268 +Subproject commit 44cd0b61fe38468461a2fe99e9e5bc125c7e6b88 diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 4b6206c..2a19697 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 4b6206c3629481569b163c220bee0b1cd16d8d53 +Subproject commit 2a1969790b405f073bfcaef9396cd84766693ae9 diff --git a/src/gfz-cli/ActionsGCI.cs b/src/gfz-cli/ActionsGCI.cs index 99082c8..c9a35eb 100644 --- a/src/gfz-cli/ActionsGCI.cs +++ b/src/gfz-cli/ActionsGCI.cs @@ -23,7 +23,7 @@ public static void RenameGciFile(Options options, FilePath inputFilePath, FilePa gci.Deserialize(reader); reader.SeekBegin(); - string name = GetName(gci.UniqueID, reader); + string name = GetName(gci.header.UniqueID, reader); outputFilePath.SetName(name); var fileWrite = () => diff --git a/src/gfz-cli/ActionsGhost.cs b/src/gfz-cli/ActionsGhost.cs index 5756488..a5c811d 100644 --- a/src/gfz-cli/ActionsGhost.cs +++ b/src/gfz-cli/ActionsGhost.cs @@ -1,5 +1,7 @@ -using GameCube.GFZ.Ghosts; +using GameCube.GCI; +using GameCube.GFZ.Ghosts; using Manifold.IO; +using System; using System.IO; using static Manifold.GFZCLI.GfzCliUtilities; @@ -7,26 +9,28 @@ namespace Manifold.GFZCLI { public class ActionsGhost { - public static void ReadGhosts(Options options) + public static void ExtractGhostFromGci(Options options) { //string[] files = GetInputFiles(options); - Terminal.WriteLine("Ghost: reading ghost data."); - int binCount = DoFileInFileOutTasks(options, ReadGhost); - Terminal.WriteLine($"Ghost: done reading {binCount} file{Plural(binCount)}."); + Terminal.WriteLine("Ghost: extracting ghost data."); + int binCount = DoFileInFileOutTasks(options, ExtractGhostDataFromGci); + Terminal.WriteLine($"Ghost: done extracting ghost data from {binCount} file{Plural(binCount)}."); } - private static void ReadGhost(Options options, FilePath inputFile, FilePath outputFile) + private static void ExtractGhostDataFromGci(Options options, FilePath inputFile, FilePath outputFile) { // Read BIN Emblem data - var ghost = new GhostData(); - using (var reader = new EndianBinaryReader(File.OpenRead(inputFile), GhostData.endianness)) + var gci = new GhostDataGCI(); + GhostData ghost; + using (var reader = new EndianBinaryReader(File.OpenRead(inputFile), Gci.endianness)) { - ghost.Deserialize(reader); + gci.Deserialize(reader); + ghost = gci.GhostData; ghost.FileName = Path.GetFileNameWithoutExtension(inputFile); } // TODO: parameterize extensions - outputFile.AppendExtension(".bin"); + outputFile.SetExtensions(GhostData.fileExtension); var fileWrite = () => { using var writer = new EndianBinaryWriter(File.Create(outputFile), GhostData.endianness); diff --git a/src/gfz-cli/ActionsMisc.cs b/src/gfz-cli/ActionsMisc.cs index bd876a2..826192f 100644 --- a/src/gfz-cli/ActionsMisc.cs +++ b/src/gfz-cli/ActionsMisc.cs @@ -19,7 +19,7 @@ public static void DumpHex32(Options options) string outputPath = GetOutputDirectory(options); FilePath fileOutputPath = new FilePath(outputPath); fileOutputPath.SetName("test"); - fileOutputPath.SetExtension("tsv"); + fileOutputPath.PushExtension("tsv"); using var writer = new StreamWriter(File.Create(fileOutputPath)); writer.WriteNextCol("Filename:"); diff --git a/src/gfz-cli/FilePath.cs b/src/gfz-cli/FilePath.cs index a754459..a30fc0d 100644 --- a/src/gfz-cli/FilePath.cs +++ b/src/gfz-cli/FilePath.cs @@ -150,7 +150,7 @@ public void SetExtensions(string extensions) string[] entensionsSplit = extensions.Split('.'); SetExtensions(entensionsSplit); } - public void SetExtension(string value) + public void PushExtension(string value) { PopExtension(); diff --git a/src/gfz-cli/GfzCliActions.cs b/src/gfz-cli/GfzCliActions.cs index 94a7cb8..edfac16 100644 --- a/src/gfz-cli/GfzCliActions.cs +++ b/src/gfz-cli/GfzCliActions.cs @@ -19,7 +19,7 @@ public enum GfzCliAction image_to_emblem_bin, image_to_emblem_gci, - read_ghost, + gci_extract_ghost, live_camera_stage_bin_to_tsv, live_camera_stage_tsv_to_bin, diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index 247f9fa..7f019a1 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -73,7 +73,7 @@ public static void ExecuteAction(Options options) case GfzCliAction.image_to_emblem_bin: ActionsEmblem.ImageToEmblemBIN(options); break; case GfzCliAction.image_to_emblem_gci: ActionsEmblem.ImageToEmblemGCI(options); break; // - case GfzCliAction.read_ghost: ActionsGhost.ReadGhosts(options); break; + case GfzCliAction.gci_extract_ghost: ActionsGhost.ExtractGhostFromGci(options); break; // LIVE CAMERA STAGE case GfzCliAction.live_camera_stage_bin_to_tsv: ActionsLiveCameraStage.LiveCameraStageBinToTsv(options); break; case GfzCliAction.live_camera_stage_tsv_to_bin: ActionsLiveCameraStage.LiveCameraStageTsvToBin(options); break; diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index c29ee18..45dbc2a 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -71,9 +71,9 @@ "commandName": "Project", "commandLineArgs": "auto-rename-gci D:\\test-gfz\\ --search-subdirs --search-pattern \"*.gci\"" }, - "read-ghost": { + "gci-extract-ghost": { "commandName": "Project", - "commandLineArgs": "read-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"*.dat\" --overwrite" + "commandLineArgs": "gci-extract-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"*fzg*.gci\"" } } } \ No newline at end of file From 415cb1e9666d29cf357ac1cefaee5173e8ab1227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sat, 8 Jul 2023 02:30:11 -0400 Subject: [PATCH 09/18] Genericize GCI file structure. Read works, write does not yet. --- libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsGCI.cs | 40 +++++++++++++++++++------------------ src/gfz-cli/ActionsGhost.cs | 4 ++-- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/libs/GameCube.Core b/libs/GameCube.Core index 44cd0b6..72bb4cf 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit 44cd0b61fe38468461a2fe99e9e5bc125c7e6b88 +Subproject commit 72bb4cff2a568e13bdb2f963a0e8d1e78645f9ed diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 2a19697..2beaa08 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 2a1969790b405f073bfcaef9396cd84766693ae9 +Subproject commit 2beaa08b41f1e31b87c404494c3a3344e1376496 diff --git a/src/gfz-cli/ActionsGCI.cs b/src/gfz-cli/ActionsGCI.cs index c9a35eb..98a7929 100644 --- a/src/gfz-cli/ActionsGCI.cs +++ b/src/gfz-cli/ActionsGCI.cs @@ -17,27 +17,29 @@ public static void RenameGCI(Options options) public static void RenameGciFile(Options options, FilePath inputFilePath, FilePath outputFilePath) { - Gci gci = new Gci(); - inputFilePath.ThrowIfDoesNotExist(); - using var reader = new EndianBinaryReader(File.OpenRead(inputFilePath), Gci.endianness); - gci.Deserialize(reader); - reader.SeekBegin(); + // Can no longer do generic renaming due to changes in structures + throw new System.NotImplementedException(); - string name = GetName(gci.header.UniqueID, reader); - outputFilePath.SetName(name); + //inputFilePath.ThrowIfDoesNotExist(); + //using var reader = new EndianBinaryReader(File.OpenRead(inputFilePath), Gci.endianness); + //gci.Deserialize(reader); + //reader.SeekBegin(); - var fileWrite = () => - { - File.Copy(inputFilePath, outputFilePath, options.OverwriteFiles); - }; - var info = new FileWriteInfo() - { - InputFilePath = inputFilePath, - OutputFilePath = outputFilePath, - PrintDesignator = "GCI", - PrintActionDescription = "renaming file", - }; - FileWriteOverwriteHandler(options, fileWrite, info); + //string name = GetName(gci.header.UniqueID, reader); + //outputFilePath.SetName(name); + + //var fileWrite = () => + //{ + // File.Copy(inputFilePath, outputFilePath, options.OverwriteFiles); + //}; + //var info = new FileWriteInfo() + //{ + // InputFilePath = inputFilePath, + // OutputFilePath = outputFilePath, + // PrintDesignator = "GCI", + // PrintActionDescription = "renaming file", + //}; + //FileWriteOverwriteHandler(options, fileWrite, info); } public static string GetName(ushort uniqueID, EndianBinaryReader reader) diff --git a/src/gfz-cli/ActionsGhost.cs b/src/gfz-cli/ActionsGhost.cs index a5c811d..eb0aff7 100644 --- a/src/gfz-cli/ActionsGhost.cs +++ b/src/gfz-cli/ActionsGhost.cs @@ -19,10 +19,10 @@ public static void ExtractGhostFromGci(Options options) private static void ExtractGhostDataFromGci(Options options, FilePath inputFile, FilePath outputFile) { - // Read BIN Emblem data + // var gci = new GhostDataGCI(); GhostData ghost; - using (var reader = new EndianBinaryReader(File.OpenRead(inputFile), Gci.endianness)) + using (var reader = new EndianBinaryReader(File.OpenRead(inputFile), GhostDataGCI.endianness)) { gci.Deserialize(reader); ghost = gci.GhostData; From 083bd54c921980a883f0a928ddf2259512479951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 9 Jul 2023 02:53:41 -0400 Subject: [PATCH 10/18] Continuing big GCI refatoring --- libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsEmblem.cs | 75 ++++++++++++---------- src/gfz-cli/ActionsTPL.cs | 8 ++- src/gfz-cli/Properties/launchSettings.json | 2 +- src/gfz-cli/gfz-cli.csproj | 2 +- src/gfz-cli/gfz-cli.sln | 10 +++ 7 files changed, 59 insertions(+), 42 deletions(-) diff --git a/libs/GameCube.Core b/libs/GameCube.Core index 72bb4cf..5a51e25 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit 72bb4cff2a568e13bdb2f963a0e8d1e78645f9ed +Subproject commit 5a51e25ea3812fc69bb780c0c8698640030bc0e4 diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 2beaa08..d882306 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 2beaa08b41f1e31b87c404494c3a3344e1376496 +Subproject commit d882306ec43986848e55afa59b9383b542930fa5 diff --git a/src/gfz-cli/ActionsEmblem.cs b/src/gfz-cli/ActionsEmblem.cs index f84d02c..7947610 100644 --- a/src/gfz-cli/ActionsEmblem.cs +++ b/src/gfz-cli/ActionsEmblem.cs @@ -10,6 +10,7 @@ using static Manifold.GFZCLI.GfzCliUtilities; using static Manifold.GFZCLI.GfzCliImageUtilities; using static Manifold.GFZCLI.Program; +using GameCube.GCI; namespace Manifold.GFZCLI { @@ -46,8 +47,10 @@ private static void EmblemBinToImages(Options options, FilePath inputFile, FileP } // Prepare image encoder - var encoder = new PngEncoder(); - encoder.CompressionLevel = PngCompressionLevel.BestCompression; + var encoder = new PngEncoder + { + CompressionLevel = PngCompressionLevel.BestCompression + }; outputFile.AppendDirectory(emblemBIN.FileName); outputFile.SetExtensions(".png"); @@ -84,8 +87,10 @@ private static void EmblemGciToImage(Options options, FilePath inputFile, FilePa } // Prepare image encoder - var encoder = new PngEncoder(); - encoder.CompressionLevel = PngCompressionLevel.BestCompression; + var encoder = new PngEncoder + { + CompressionLevel = PngCompressionLevel.BestCompression + }; // Strip .dat.gci extensions outputFile.SetExtensions("png"); @@ -108,7 +113,7 @@ private static void EmblemGciToImage(Options options, FilePath inputFile, FilePa { // Strip original file name, replace with GC game code FilePath textureOutput = new FilePath(outputFile); - textureOutput.SetName($"{emblemGCI.GameCode}-icon"); + textureOutput.SetName($"{emblemGCI.Header}-icon"); fileWriteInfo.OutputFilePath = textureOutput; fileWriteInfo.PrintActionDescription = "converting emblem icon"; WriteImage(options, encoder, emblemGCI.Emblem.Texture, fileWriteInfo); @@ -143,12 +148,12 @@ public static void ImageToEmblemGCI(Options options) public static Emblem ImageToEmblemBin(Options options, FilePath inputFile) { // Make sure some option parameters are appropriate - bool isTooLarge = IImageResizeOptions.IsSizeTooLarge(options, Emblem._Width, Emblem._Height); + bool isTooLarge = IImageResizeOptions.IsSizeTooLarge(options, Emblem.Width, Emblem.Height); if (isTooLarge) { string msg = $"Requested resize ({options.Width},{options.Height}) exceeds the maximum " + - $"bounds of an emblem ({Emblem._Width},{Emblem._Height})."; + $"bounds of an emblem ({Emblem.Width},{Emblem.Height})."; throw new ArgumentException(msg); } @@ -159,8 +164,8 @@ public static Emblem ImageToEmblemBin(Options options, FilePath inputFile) // Resize image to fit inside bounds of 64x64 ResizeOptions ResizeOptions = IImageResizeOptions.GetResizeOptions(options); // Emblem size is either 62x62 (1px alpha border, as intended) or 64x64 ("hacker" option) - int emblemX = options.EmblemHasAlphaBorder ? Emblem._Width - 2 : Emblem._Width; - int emblemY = options.EmblemHasAlphaBorder ? Emblem._Height - 2 : Emblem._Height; + int emblemX = options.EmblemHasAlphaBorder ? Emblem.Width - 2 : Emblem.Width; + int emblemY = options.EmblemHasAlphaBorder ? Emblem.Height - 2 : Emblem.Height; // Choose lowest dimensions as the default size (ie: preserve pixel-perfect if possible) int defaultX = Math.Min(emblemX, image.Width); int defaultY = Math.Min(emblemY, image.Height); @@ -171,12 +176,12 @@ public static Emblem ImageToEmblemBin(Options options, FilePath inputFile) // Create emblem, textures Emblem emblem = new Emblem(); Texture imageTexture = ImageToTexture(image, TextureFormat.RGB5A3); - Texture emblemTexture = new Texture(Emblem._Width, Emblem._Height, TextureColor.Clear, TextureFormat.RGB5A3); + Texture emblemTexture = new Texture(Emblem.Width, Emblem.Height, TextureColor.Clear, TextureFormat.RGB5A3); // Copy image texture to emblem center // Only works if image is 64px or less! Resize code block prepares this. - int offsetX = (emblem.Width - image.Width) / 2; - int offsetY = (emblem.Height - image.Height) / 2; + int offsetX = (Emblem.Width - image.Width) / 2; + int offsetY = (Emblem.Height - image.Height) / 2; Texture.Copy(imageTexture, emblemTexture, offsetX, offsetY); // Write some useful information to the terminal @@ -227,41 +232,41 @@ public static Emblem[] ImageToEmblemBin(Options options) return emblems; } + // TODO: should this be in Emblem class? + private static string GetFileName(string fileName) + { + const int maxChars = 20; + string fileName20Char = fileName.PadLeft(maxChars, '-'); + fileName20Char = fileName20Char.Substring(0, maxChars); + + // TODO: get strings from gamecode + string name = $"XX-GFZX-fzX020-{fileName20Char}"; + return name; + } + public static void ImageToEmblemGci(Options options, FilePath inputFile, FilePath outputFile) { - outputFile.SetExtensions(".dat.gci"); - string fileName = EmblemGCI.GetFileName(outputFile.Name, GameCube.GFZ.GameCode.GFZJ01); + string fileName = GetFileName(outputFile.Name); outputFile.SetName(fileName); + outputFile.SetExtensions(".dat.gci"); // Load image Image image = Image.Load(inputFile); - // TODO: appropriate scaling and stuff - genericize previous code Image imagePreview = image.Clone(); // - image.Mutate(ipc => ipc.Resize(64, 64)); - imagePreview.Mutate(ipc => ipc.Resize(32, 32)); + image.Mutate(ipc => ipc.Resize(Emblem.Width, Emblem.Height)); + imagePreview.Mutate(ipc => ipc.Resize(Gci.IconWidth, Gci.IconHeight)); Texture emblemTexture = ImageToTexture(image); Texture emblemPreview = ImageToTexture(imagePreview); - Emblem emblem = new Emblem() - { - Texture = emblemTexture - }; - // - MenuBanner banner = new MenuBanner(); - banner.Texture = new Texture(96, 32, new TextureColor(0, 255, 255), TextureFormat.RGB5A3); - Texture.Copy(emblemPreview, banner.Texture, 64, 0); - // - MenuIcon icon = new MenuIcon(); - icon.Texture = new Texture(32, 32, new TextureColor(255, 255, 0), TextureFormat.RGB5A3); - // + Texture banner = new Texture(Gci.BannerWidth, Gci.BannerHeight, Gci.DirectFormat); + Texture[] icons = new Texture[] { emblemPreview }; + Emblem emblem = new Emblem(emblemTexture); EmblemGCI gci = new EmblemGCI(); - gci.Banner = banner; - gci.Icon = icon; - gci.Emblem = emblem; - gci.SafeSetInternalFileName(outputFile.NameAndExtensions); - // TODO: not hardcoded - gci.SetRegionCode(GameCube.GFZ.GameCode.GFZJ01); + gci.SetFileData(); + gci.SetBanner(); + gci.SetIcons(); + gci.SetFileName(); // var fileWrite = () => diff --git a/src/gfz-cli/ActionsTPL.cs b/src/gfz-cli/ActionsTPL.cs index 5ddd5c6..a7ea64a 100644 --- a/src/gfz-cli/ActionsTPL.cs +++ b/src/gfz-cli/ActionsTPL.cs @@ -42,8 +42,10 @@ public static void TplUnpackFile(Options options, FilePath inputFile, FilePath o Directory.CreateDirectory(outputDirectory); // Prepare image encoder - var encoder = new PngEncoder(); - encoder.CompressionLevel = PngCompressionLevel.BestCompression; + var encoder = new PngEncoder + { + CompressionLevel = PngCompressionLevel.BestCompression + }; outputFile.SetExtensions(".png"); outputFile.AppendDirectory(tpl.FileName); @@ -136,7 +138,7 @@ public static void TplPack(Options options) //var encoding = Encoding.EncodingRGB5A3; //var encoding = Encoding.EncodingIA8; //var encoding = Encoding.EncodingIA4; - var blocks = Texture.CreateTextureDirectColorBlocks(texture, encoding, out int bch, out int bcv); + var blocks = Texture.CreateDirectColorBlocksFromTexture(texture, encoding, out int bch, out int bcv); encoding.WriteTexture(writer, blocks); writer.BaseStream.Position = 0; diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index 45dbc2a..ba49ca0 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -73,7 +73,7 @@ }, "gci-extract-ghost": { "commandName": "Project", - "commandLineArgs": "gci-extract-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"*fzg*.gci\"" + "commandLineArgs": "gci-extract-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"8P-GFZE-fzg003c3d1b98814015.dat.gci" } } } \ No newline at end of file diff --git a/src/gfz-cli/gfz-cli.csproj b/src/gfz-cli/gfz-cli.csproj index 11c0dee..61f89e9 100644 --- a/src/gfz-cli/gfz-cli.csproj +++ b/src/gfz-cli/gfz-cli.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/gfz-cli/gfz-cli.sln b/src/gfz-cli/gfz-cli.sln index 49edd5e..5ae9619 100644 --- a/src/gfz-cli/gfz-cli.sln +++ b/src/gfz-cli/gfz-cli.sln @@ -57,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.GFZ.Replay", "..\. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCube.Common", "..\..\libs\GameCube.Core\src\GameCube.Common\GameCube.Common.csproj", "{01014172-CB65-438C-BA04-BA22619A679B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCube.GFZ.GCI", "..\..\libs\GameCube.GFZ\src\GameCube.GFZ.GCI\GameCube.GFZ.GCI.csproj", "{52E58322-E8AC-46B6-95DE-82B71069FD5E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -281,6 +283,14 @@ Global {01014172-CB65-438C-BA04-BA22619A679B}.Release|Any CPU.Build.0 = Release|Any CPU {01014172-CB65-438C-BA04-BA22619A679B}.Release|x64.ActiveCfg = Release|Any CPU {01014172-CB65-438C-BA04-BA22619A679B}.Release|x64.Build.0 = Release|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Debug|x64.ActiveCfg = Debug|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Debug|x64.Build.0 = Debug|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Release|Any CPU.Build.0 = Release|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Release|x64.ActiveCfg = Release|Any CPU + {52E58322-E8AC-46B6-95DE-82B71069FD5E}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From a0a22d35df6e53053e5b5a52e735c3e839d07558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 9 Jul 2023 22:24:45 -0400 Subject: [PATCH 11/18] Clean up Emblems actions implementation --- libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsEmblem.cs | 191 +++++++++++---------- src/gfz-cli/Options.cs | 21 +++ src/gfz-cli/Properties/launchSettings.json | 3 +- 5 files changed, 129 insertions(+), 90 deletions(-) diff --git a/libs/GameCube.Core b/libs/GameCube.Core index 5a51e25..3e50a4f 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit 5a51e25ea3812fc69bb780c0c8698640030bc0e4 +Subproject commit 3e50a4f761a9d48339a9ef8c9eab767d2690c89c diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index d882306..e98f1c5 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit d882306ec43986848e55afa59b9383b542930fa5 +Subproject commit e98f1c5ebc27b0a440ba6fb79fef4943cded78e7 diff --git a/src/gfz-cli/ActionsEmblem.cs b/src/gfz-cli/ActionsEmblem.cs index 7947610..92a45bb 100644 --- a/src/gfz-cli/ActionsEmblem.cs +++ b/src/gfz-cli/ActionsEmblem.cs @@ -1,4 +1,5 @@ using GameCube.GFZ.Emblem; +using GameCube.GFZ.GCI; using GameCube.GX.Texture; using Manifold.IO; using SixLabors.ImageSharp; @@ -10,7 +11,6 @@ using static Manifold.GFZCLI.GfzCliUtilities; using static Manifold.GFZCLI.GfzCliImageUtilities; using static Manifold.GFZCLI.Program; -using GameCube.GCI; namespace Manifold.GFZCLI { @@ -103,20 +103,22 @@ private static void EmblemGciToImage(Options options, FilePath inputFile, FilePa // BANNER { - FilePath textureOutput = new FilePath(outputFile); + FilePath textureOutput = new(outputFile); textureOutput.SetName($"{outputFile.Name}-banner"); fileWriteInfo.OutputFilePath = textureOutput; fileWriteInfo.PrintActionDescription = "converting emblem banner"; - WriteImage(options, encoder, emblemGCI.Emblem.Texture, fileWriteInfo); + WriteImage(options, encoder, emblemGCI.Banner, fileWriteInfo); } // ICON + for (int i = 0; i < emblemGCI.Icons.Length; i++) { + var icon = emblemGCI.Icons[i]; // Strip original file name, replace with GC game code - FilePath textureOutput = new FilePath(outputFile); - textureOutput.SetName($"{emblemGCI.Header}-icon"); + FilePath textureOutput = new(outputFile); + textureOutput.SetName($"{emblemGCI.Header}-icon{i}"); fileWriteInfo.OutputFilePath = textureOutput; - fileWriteInfo.PrintActionDescription = "converting emblem icon"; - WriteImage(options, encoder, emblemGCI.Emblem.Texture, fileWriteInfo); + fileWriteInfo.PrintActionDescription = $"converting emblem icon #{i}"; + WriteImage(options, encoder, icon, fileWriteInfo); } // EMBLEM { @@ -126,6 +128,7 @@ private static void EmblemGciToImage(Options options, FilePath inputFile, FilePa } } + public static void ImageToEmblemBIN(Options options) { Terminal.WriteLine("Emblem: converting image(s) to emblem.bin."); @@ -135,14 +138,14 @@ public static void ImageToEmblemBIN(Options options) public static void ImageToEmblemGCI(Options options) { - // In this case where no search pattern is set, find *fz*.dat.gci (emblem) files. + // In this case where no search pattern is set, find *fze*.dat.gci (emblem) files. bool hasNoSearchPattern = string.IsNullOrEmpty(options.SearchPattern); if (hasNoSearchPattern) - options.SearchPattern = "*fz*.dat.gci"; + options.SearchPattern = "*fze*.dat.gci"; Terminal.WriteLine("Emblem: converting image(s) to emblem.dat.gci."); int gciCount = DoFileInFileOutTasks(options, ImageToEmblemGci); - Terminal.WriteLine($"Emblem: done converting {gciCount} image{(gciCount != 1 ? 's' : "")}."); + Terminal.WriteLine($"Emblem: done converting {gciCount} image{Plural(gciCount)}."); } public static Emblem ImageToEmblemBin(Options options, FilePath inputFile) @@ -157,32 +160,15 @@ public static Emblem ImageToEmblemBin(Options options, FilePath inputFile) throw new ArgumentException(msg); } + // Load image, get resize parameters, resize image Image image = Image.Load(inputFile); - - // TODO: auto-magically handle 64x64 images - - // Resize image to fit inside bounds of 64x64 - ResizeOptions ResizeOptions = IImageResizeOptions.GetResizeOptions(options); - // Emblem size is either 62x62 (1px alpha border, as intended) or 64x64 ("hacker" option) - int emblemX = options.EmblemHasAlphaBorder ? Emblem.Width - 2 : Emblem.Width; - int emblemY = options.EmblemHasAlphaBorder ? Emblem.Height - 2 : Emblem.Height; - // Choose lowest dimensions as the default size (ie: preserve pixel-perfect if possible) - int defaultX = Math.Min(emblemX, image.Width); - int defaultY = Math.Min(emblemY, image.Height); - // Set size override, then resize image - ResizeOptions.Size = IImageResizeOptions.GetResizeSize(options, defaultX, defaultY); - image.Mutate(ipc => ipc.Resize(ResizeOptions)); - - // Create emblem, textures - Emblem emblem = new Emblem(); - Texture imageTexture = ImageToTexture(image, TextureFormat.RGB5A3); - Texture emblemTexture = new Texture(Emblem.Width, Emblem.Height, TextureColor.Clear, TextureFormat.RGB5A3); - - // Copy image texture to emblem center - // Only works if image is 64px or less! Resize code block prepares this. - int offsetX = (Emblem.Width - image.Width) / 2; - int offsetY = (Emblem.Height - image.Height) / 2; - Texture.Copy(imageTexture, emblemTexture, offsetX, offsetY); + ResizeOptions resizeOptions = GetEmblemResizeOptions(options, image.Width, image.Height, Emblem.Width, Emblem.Height, options.EmblemHasAlphaBorder); + image.Mutate(ipc => ipc.Resize(resizeOptions)); + // Create emblem, convert image to texture + Emblem emblem = new() + { + Texture = ImageAsCenteredTexture(image, Emblem.Width, Emblem.Height) + }; // Write some useful information to the terminal lock (lock_ConsoleWrite) @@ -194,8 +180,6 @@ public static Emblem ImageToEmblemBin(Options options, FilePath inputFile) Terminal.WriteLine(); } - // Assign return - emblem.Texture = emblemTexture; return emblem; } @@ -216,15 +200,11 @@ public static Emblem[] ImageToEmblemBin(Options options) var fileWrite = () => { - using (var fileStream = File.Create(outputFilePath)) - { - using (var writer = new EndianBinaryWriter(fileStream, EmblemBIN.endianness)) - { - var emblemBin = new EmblemBIN(); - emblemBin.Emblems = emblems; - emblemBin.Serialize(writer); - } - } + using var fileStream = File.Create(outputFilePath); + using var writer = new EndianBinaryWriter(fileStream, EmblemBIN.endianness); + EmblemBIN emblemBin = new(); + emblemBin.Emblems = emblems; + emblemBin.Serialize(writer); }; FileWriteOverwriteHandler(options, fileWrite, info); @@ -232,53 +212,45 @@ public static Emblem[] ImageToEmblemBin(Options options) return emblems; } - // TODO: should this be in Emblem class? - private static string GetFileName(string fileName) - { - const int maxChars = 20; - string fileName20Char = fileName.PadLeft(maxChars, '-'); - fileName20Char = fileName20Char.Substring(0, maxChars); - - // TODO: get strings from gamecode - string name = $"XX-GFZX-fzX020-{fileName20Char}"; - return name; - } - public static void ImageToEmblemGci(Options options, FilePath inputFile, FilePath outputFile) { - string fileName = GetFileName(outputFile.Name); - outputFile.SetName(fileName); - outputFile.SetExtensions(".dat.gci"); - // Load image - Image image = Image.Load(inputFile); - Image imagePreview = image.Clone(); - // - image.Mutate(ipc => ipc.Resize(Emblem.Width, Emblem.Height)); - imagePreview.Mutate(ipc => ipc.Resize(Gci.IconWidth, Gci.IconHeight)); - - Texture emblemTexture = ImageToTexture(image); - Texture emblemPreview = ImageToTexture(imagePreview); - Texture banner = new Texture(Gci.BannerWidth, Gci.BannerHeight, Gci.DirectFormat); - Texture[] icons = new Texture[] { emblemPreview }; - Emblem emblem = new Emblem(emblemTexture); - EmblemGCI gci = new EmblemGCI(); - gci.SetFileData(); - gci.SetBanner(); - gci.SetIcons(); - gci.SetFileName(); - - // + Image emblemImage = Image.Load(inputFile); + Image iconImage = emblemImage.Clone(); + // Get resize targets + ResizeOptions emblemResize = GetEmblemResizeOptions(options, emblemImage.Width, emblemImage.Height, Emblem.Width, Emblem.Height, options.EmblemHasAlphaBorder); + ResizeOptions iconResize = GetEmblemResizeOptions(options, emblemImage.Width, emblemImage.Height, EmblemGCI.IconWidth, EmblemGCI.IconHeight, false); + // Resize images + emblemImage.Mutate(ipc => ipc.Resize(emblemResize)); + iconImage.Mutate(ipc => ipc.Resize(iconResize)); + + // Construct data for GCI + Texture emblemTexture = ImageAsCenteredTexture(emblemImage, Emblem.Width, Emblem.Height); + Texture iconTexture = ImageAsCenteredTexture(iconImage, EmblemGCI.IconWidth, EmblemGCI.IconHeight); + Texture banner = new(EmblemGCI.BannerWidth, EmblemGCI.BannerHeight, EmblemGCI.DirectFormat); + // todo: blank banner! + Texture[] icons = new[] { iconTexture }; + Emblem emblem = new(emblemTexture); + EmblemGCI emblemGci = new(options.Region); + options.ThrowIfInvalidRegion(); + + // Get name for output file + string gciFileName = EmblemGCI.FormatGciFileName(GfzGciFileType.Emblem, emblemGci.Header, outputFile.Name, out string fileName); + outputFile.SetName(gciFileName); + + // Assign data + emblemGci.Emblem = emblem; + emblemGci.SetBanner(banner); + emblemGci.SetIcons(icons); + emblemGci.SetFileName(fileName); + + // Write file var fileWrite = () => { // Save emblem - using (var fileStream = File.Create(outputFile)) - { - using (var writer = new EndianBinaryWriter(fileStream, EmblemGCI.endianness)) - { - gci.Serialize(writer); - } - } + using var fileStream = File.Create(outputFile); + using var writer = new EndianBinaryWriter(fileStream, EmblemGCI.endianness); + emblemGci.Serialize(writer); }; var info = new FileWriteInfo() { @@ -289,5 +261,50 @@ public static void ImageToEmblemGci(Options options, FilePath inputFile, FilePat }; FileWriteOverwriteHandler(options, fileWrite, info); } + + + private static ResizeOptions GetEmblemResizeOptions(Options options, int imageWidth, int imageHeight, int resizeWidth, int resizeHeight, bool resizeHasAlphaBorder) + { + // Resize image to fit inside bounds of image. + // eg: emblem is 64x64 + ResizeOptions resizeOptions = IImageResizeOptions.GetResizeOptions(options); + + // Emblem size is either 62x62 (1px alpha border, as intended) or 64x64 ("hacker" option) + if (resizeHasAlphaBorder) + { + resizeWidth -= 2; + resizeHeight -= 2; + } + // Choose lowest dimensions as the default size (ie: preserve pixel-perfect if possible) + int defaultX = Math.Min(resizeWidth, imageWidth); + int defaultY = Math.Min(resizeHeight, imageHeight); + // Set size override, then resize image + resizeOptions.Size = IImageResizeOptions.GetResizeSize(options, defaultX, defaultY); + + return resizeOptions; + } + private static Texture ImageAsCenteredTexture(Image image, int boundsX, int boundsY) + { + bool isInvalidSize = image.Width > boundsX || image.Height > boundsY; + if (isInvalidSize) + { + string msg = + $"Image size ({image.Width}, {image.Height}) cannot be " + + $"larger than bounds ({boundsX}, {boundsY})."; + throw new ArgumentException(msg); + } + + Texture imageAsTexture = ImageToTexture(image, TextureFormat.RGB5A3); + Texture centeredTexture = new(boundsX, boundsY, TextureColor.Clear, TextureFormat.RGB5A3); + + // Copy image texture to emblem center + // Only works if image is less than bounds! + int offsetX = (boundsX - image.Width) / 2; + int offsetY = (boundsX - image.Height) / 2; + Texture.Copy(imageAsTexture, centeredTexture, offsetX, offsetY); + + return centeredTexture; + } + } } diff --git a/src/gfz-cli/Options.cs b/src/gfz-cli/Options.cs index 708dc3f..5b55313 100644 --- a/src/gfz-cli/Options.cs +++ b/src/gfz-cli/Options.cs @@ -1,5 +1,6 @@ using CommandLine; using GameCube.AmusementVision; +using GameCube.DiskImage; using GameCube.GFZ.Stage; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -28,6 +29,11 @@ public class Options : public SerializeFormat SerializeFormat => Enum.Parse(SerializationFormatStr, true); public AvGame AvGame => GetAvFormat(SerializeFormat); + // TODO: + public string RegionStr { get; set; } = string.Empty; + public Region Region { get; set; } = Region.Japan; + + // ITplOptions public bool TplUnpackMipmaps { get; set; } public bool TplUnpackSaveCorruptedTextures { get; set; } @@ -112,5 +118,20 @@ private static Color StringToColor(string value) Color color = new Color(new Rgba32(r, g, b, a)); return color; } + + public void ThrowIfInvalidRegion() + { + switch (Region) + { + case Region.Japan: + case Region.NorthAmerica: + case Region.Europe: + return; + + default: + string msg = $"Invalid region \"{RegionStr}\"."; + throw new ArgumentException(msg); + } + } } } \ No newline at end of file diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index ba49ca0..998f935 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -49,7 +49,8 @@ "commandLineArgs": "image-to-emblem-bin D:\\desktop\\pkmn C:\\gfzj01-working\\files\\emblem\\sample.bin -p * -o" }, "image-to-emblem-gci": { - "commandName": "Project" + "commandName": "Project", + "commandLineArgs": "image-to-emblem-gci D:\\desktop\\pkmn C:\\gfzj01-working\\files\\emblem\\sample -p \"1.png\" " }, "WSL": { "commandName": "WSL2", From 0efdbb05b33923fae6fd3a161423364e0cb19a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 9 Jul 2023 23:04:24 -0400 Subject: [PATCH 12/18] Properly implement Options.Region --- libs/GameCube.Core | 2 +- src/gfz-cli/ActionsEmblem.cs | 2 +- src/gfz-cli/IGfzCliOptions.cs | 20 ++++++++++----- src/gfz-cli/Options.cs | 46 ++++++++++++++++++++++++++++------- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/libs/GameCube.Core b/libs/GameCube.Core index 3e50a4f..e802414 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit 3e50a4f761a9d48339a9ef8c9eab767d2690c89c +Subproject commit e8024140c86ea869ab818b8b73d8425b370bb647 diff --git a/src/gfz-cli/ActionsEmblem.cs b/src/gfz-cli/ActionsEmblem.cs index 92a45bb..e2cef69 100644 --- a/src/gfz-cli/ActionsEmblem.cs +++ b/src/gfz-cli/ActionsEmblem.cs @@ -231,7 +231,7 @@ public static void ImageToEmblemGci(Options options, FilePath inputFile, FilePat // todo: blank banner! Texture[] icons = new[] { iconTexture }; Emblem emblem = new(emblemTexture); - EmblemGCI emblemGci = new(options.Region); + EmblemGCI emblemGci = new(options.SerializationRegion); options.ThrowIfInvalidRegion(); // Get name for output file diff --git a/src/gfz-cli/IGfzCliOptions.cs b/src/gfz-cli/IGfzCliOptions.cs index 37f1d80..089b31a 100644 --- a/src/gfz-cli/IGfzCliOptions.cs +++ b/src/gfz-cli/IGfzCliOptions.cs @@ -1,4 +1,5 @@ using CommandLine; +using GameCube.DiskImage; using GameCube.GFZ.Stage; using System.IO; @@ -12,6 +13,7 @@ internal static class ArgsShort public const char SearchPattern = 'p'; public const char SearchSubdirectories = 's'; public const char SerializationFormat = 'f'; + public const char SerializationRegion = 'r'; } internal static class Args @@ -26,6 +28,7 @@ internal static class Args public const string SearchPattern = "search-pattern"; public const string SearchSubdirectories = "search-subdirs"; public const string SerializationFormat = "format"; + public const string SerializationRegion = "region"; public const string TplUnpackMipmaps = "tpl-unpack-mipmaps"; public const string TplUnpackSaveCorruptedTextures = "tpl-unpack-corrupted-cmpr"; @@ -67,11 +70,9 @@ internal static class Help public const string SerializationFormat = "The format used when serializing.\n" + "\tOptions: \"ax\", \"gx\". Set to \"gx\" by default."; - - public const string TplUnpackMipmaps = - "tpl-unpack (option): Export mipmap textures."; - public const string TplUnpackSaveCorruptedTextures = - "tpl-unpack (option): Export corrupted CMPR mipmap textures."; + public const string SerializationRegion = + "The region used when serializing.\n" + + "\tOptions: \"J\" (JP), \"E\" (NA), \"P\" (EU). Set to \"J\" by default."; } @@ -124,9 +125,16 @@ internal static class Help [Option(ArgsShort.SerializationFormat, Args.SerializationFormat, HelpText = Help.SerializationFormat)] public string SerializationFormatStr { get; set; } /// - /// Which game to serialize + /// Which game to serialize. /// public SerializeFormat SerializeFormat { get; } + [Option(ArgsShort.SerializationRegion, Args.SerializationRegion, HelpText = Help.SerializationRegion)] + public string SerializeRegionStr { get; set; } + /// + /// Which region to serialize to. + /// + public Region SerializationRegion { get; } + } } diff --git a/src/gfz-cli/Options.cs b/src/gfz-cli/Options.cs index 5b55313..bceaabb 100644 --- a/src/gfz-cli/Options.cs +++ b/src/gfz-cli/Options.cs @@ -28,11 +28,8 @@ public class Options : public string SerializationFormatStr { get; set; } = "gx"; public SerializeFormat SerializeFormat => Enum.Parse(SerializationFormatStr, true); public AvGame AvGame => GetAvFormat(SerializeFormat); - - // TODO: - public string RegionStr { get; set; } = string.Empty; - public Region Region { get; set; } = Region.Japan; - + public string SerializeRegionStr { get; set; } = "japan"; + public Region SerializationRegion => GetRegion(SerializeRegionStr); // ITplOptions public bool TplUnpackMipmaps { get; set; } @@ -58,8 +55,6 @@ public class Options : [Option("emblem-border")] public bool EmblemHasAlphaBorder { get; set; } = true; - //[Option("arc-root")] - //public string ArchiveRoot { get; set; } = string.Empty; /// @@ -81,6 +76,39 @@ private static AvGame GetAvFormat(SerializeFormat serializeFormat) throw new ArgumentException(msg); } } + private static Region GetRegion(string regionStr) + { + string regionStrClean = regionStr.ToUpper(); + + switch (regionStrClean) + { + case "J": + //case "JAPAN": + case "JP": + //case "JPN": + //case "NTSCJ": + //case "NTSC-J": + return Region.Japan; + + case "E": + case "NA": + //case "NTSCE": + //case "NTSC-E": + //case "US": + //case "USA": + return Region.NorthAmerica; + + case "P": + case "EU": + //case "EUROPE": + //case "PAL": + return Region.Europe; + + default: + string msg = $"Could not parge {nameof(Region)} \"{regionStr}\""; + throw new ArgumentException(msg); + } + } private static Color StringToColor(string value) { byte r = 0; @@ -121,7 +149,7 @@ private static Color StringToColor(string value) public void ThrowIfInvalidRegion() { - switch (Region) + switch (SerializationRegion) { case Region.Japan: case Region.NorthAmerica: @@ -129,7 +157,7 @@ public void ThrowIfInvalidRegion() return; default: - string msg = $"Invalid region \"{RegionStr}\"."; + string msg = $"Invalid region \"{SerializeRegionStr}\"."; throw new ArgumentException(msg); } } From 4f8155cea799dafb4417984d59ee22d1ed12ff5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 9 Jul 2023 23:06:07 -0400 Subject: [PATCH 13/18] m: Set correct Region as default --- src/gfz-cli/Options.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gfz-cli/Options.cs b/src/gfz-cli/Options.cs index bceaabb..1d8d288 100644 --- a/src/gfz-cli/Options.cs +++ b/src/gfz-cli/Options.cs @@ -28,7 +28,7 @@ public class Options : public string SerializationFormatStr { get; set; } = "gx"; public SerializeFormat SerializeFormat => Enum.Parse(SerializationFormatStr, true); public AvGame AvGame => GetAvFormat(SerializeFormat); - public string SerializeRegionStr { get; set; } = "japan"; + public string SerializeRegionStr { get; set; } = "J"; public Region SerializationRegion => GetRegion(SerializeRegionStr); // ITplOptions From f9f37183a407024c8fe2822ec1522192c766ec67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Sun, 9 Jul 2023 23:16:23 -0400 Subject: [PATCH 14/18] m: Test commit for github contributions --- src/gfz-cli/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index 7f019a1..ea07b71 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -85,7 +85,7 @@ public static void ExecuteAction(Options options) //case GfzCliAction.tpl_pack: TplPack(options); break; // - case GfzCliAction.dump_hex: ActionsMisc.DumpHex32(options); break; + //case GfzCliAction.dump_hex: ActionsMisc.DumpHex32(options); break; // UNSET case GfzCliAction.none: From 544b2eef28a6e7f7e05571811335a90bbde9f274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Mon, 13 Nov 2023 01:33:23 -0500 Subject: [PATCH 15/18] Add basis for REL functionality --- libs/GameCube.Core | 2 +- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsREL.cs | 60 ++++++++++++++++++++++ src/gfz-cli/GfzCliActions.cs | 3 ++ src/gfz-cli/Options.cs | 46 ++++++++++++++++- src/gfz-cli/Program.cs | 5 +- src/gfz-cli/Properties/launchSettings.json | 4 ++ 7 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 src/gfz-cli/ActionsREL.cs diff --git a/libs/GameCube.Core b/libs/GameCube.Core index e802414..bd75f03 160000 --- a/libs/GameCube.Core +++ b/libs/GameCube.Core @@ -1 +1 @@ -Subproject commit e8024140c86ea869ab818b8b73d8425b370bb647 +Subproject commit bd75f03e2720e3273a2f1e801a0812bac10808f9 diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index e98f1c5..6878dce 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit e98f1c5ebc27b0a440ba6fb79fef4943cded78e7 +Subproject commit 6878dce7226a4476afa0404488bfa5f3a89fa5fc diff --git a/src/gfz-cli/ActionsREL.cs b/src/gfz-cli/ActionsREL.cs new file mode 100644 index 0000000..52d8261 --- /dev/null +++ b/src/gfz-cli/ActionsREL.cs @@ -0,0 +1,60 @@ +using GameCube.GFZ; +using GameCube.GFZ.LZ; +using GameCube.GFZ.REL; +using System.IO; +using static Manifold.GFZCLI.GfzCliUtilities; + +namespace Manifold.GFZCLI +{ + public static class ActionsREL + { + public static void DecryptEnemyLine__(Options options) + { + // + bool hasNoSearchPattern = string.IsNullOrEmpty(options.SearchPattern); + if (hasNoSearchPattern) + options.SearchPattern = $"*line__.bin"; + + DoFileInFileOutTasks(options, DecryptEnemyLine); + } + public static void EncryptEnemyLine__(Options options) + { + // + bool hasNoSearchPattern = string.IsNullOrEmpty(options.SearchPattern); + if (hasNoSearchPattern) + options.SearchPattern = $"*line__.rel"; + + DoFileInFileOutTasks(options, EncryptEnemyLine); + } + + public static void CryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile, bool doEncrypt, string extension) + { + // Remove extension + outputFile.PopExtension(); + outputFile.SetExtensions(extension); + + // + var fileWrite = () => + { + GameCode gameCode = options.GetGameCode(); + var lookup = EnemyLineLookup.GetInfo(gameCode); + using var stream = EnemyLineUtility.Crypt(inputFile, lookup); + using var writer = File.Create(outputFile); + writer.Write(stream.ToArray()); + }; + var info = new FileWriteInfo() + { + InputFilePath = inputFile, + OutputFilePath = outputFile, + PrintDesignator = "REL", + PrintActionDescription = doEncrypt ? "encrypting file" : "decrypting file", + }; + FileWriteOverwriteHandler(options, fileWrite, info); + } + public static void DecryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile) + => CryptEnemyLine(options, inputFile, outputFile, false, "rel2"); + public static void EncryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile) + => CryptEnemyLine(options, inputFile, outputFile, true, "bin2"); + + } +} diff --git a/src/gfz-cli/GfzCliActions.cs b/src/gfz-cli/GfzCliActions.cs index edfac16..219bd33 100644 --- a/src/gfz-cli/GfzCliActions.cs +++ b/src/gfz-cli/GfzCliActions.cs @@ -27,6 +27,9 @@ public enum GfzCliAction lz_compress, lz_decompress, + rel_decrypt_line__, + rel_encrypt_line__, + tpl_unpack, // diff --git a/src/gfz-cli/Options.cs b/src/gfz-cli/Options.cs index 1d8d288..2d8777d 100644 --- a/src/gfz-cli/Options.cs +++ b/src/gfz-cli/Options.cs @@ -1,6 +1,7 @@ using CommandLine; using GameCube.AmusementVision; using GameCube.DiskImage; +using GameCube.GFZ; using GameCube.GFZ.Stage; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -109,6 +110,44 @@ private static Region GetRegion(string regionStr) throw new ArgumentException(msg); } } + public static GameCode GetGameCode(AvGame avGame, Region region) + { + GameCode code = 0; + + // Add region + switch (region) + { + case Region.Japan: + code += (int)GameCodeFields.Japan; + break; + case Region.NorthAmerica: + code += (int)GameCodeFields.NorthAmerica; + break; + case Region.Europe: + code += (int)GameCodeFields.Europe; + break; + + default: + throw new NotImplementedException(region.ToString()); + } + + // Add game + switch (avGame) + { + case AvGame.FZeroAX: + code += (int)GameCodeFields.AX; + break; + case AvGame.FZeroGX: + code += (int)GameCodeFields.GX; + break; + + default: + throw new NotImplementedException(avGame.ToString()); + } + + return code; + } + private static Color StringToColor(string value) { byte r = 0; @@ -160,6 +199,11 @@ public void ThrowIfInvalidRegion() string msg = $"Invalid region \"{SerializeRegionStr}\"."; throw new ArgumentException(msg); } - } + } + public GameCode GetGameCode() + { + GameCode gameCode = GetGameCode(AvGame, SerializationRegion); + return gameCode; + } } } \ No newline at end of file diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index ea07b71..b0a265a 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -26,7 +26,7 @@ public static void Main(string[] args) bool noArgumentsPassed = args.Length == 0; if (noArgumentsPassed) { - string msg = "You must call this program using arguments via the Console/Terminal. "; + string msg = "You must call this program using arguments via the Console/Terminal."; Terminal.WriteLine(msg, ConsoleColor.Black, ConsoleColor.Red); Terminal.WriteLine(); // Force help page @@ -80,6 +80,9 @@ public static void ExecuteAction(Options options) // LZ case GfzCliAction.lz_compress: ActionsLZ.LzCompress(options); break; case GfzCliAction.lz_decompress: ActionsLZ.LzDecompress(options); break; + // REL + case GfzCliAction.rel_decrypt_line__: ActionsREL.DecryptEnemyLine__(options); break; + case GfzCliAction.rel_encrypt_line__: ActionsREL.EncryptEnemyLine__(options); break; // TPL case GfzCliAction.tpl_unpack: ActionsTPL.TplUnpack(options); break; //case GfzCliAction.tpl_pack: TplPack(options); break; diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index 998f935..18c1380 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -75,6 +75,10 @@ "gci-extract-ghost": { "commandName": "Project", "commandLineArgs": "gci-extract-ghost D:\\gfzj01\\staff_ghost\\ --search-subdirs --search-pattern \"8P-GFZE-fzg003c3d1b98814015.dat.gci" + }, + "rel": { + "commandName": "Project", + "commandLineArgs": "rel-encrypt-line__ D:\\gfzj01\\ -s" } } } \ No newline at end of file From e633bf99b891dcae196c4a88383ffa84009cdc92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Tue, 14 Nov 2023 00:12:28 -0500 Subject: [PATCH 16/18] Add decrypt line__.bin and encrypt line__.rel --- src/gfz-cli/ActionsREL.cs | 43 ++++++++++++++++------ src/gfz-cli/Program.cs | 4 +- src/gfz-cli/Properties/launchSettings.json | 2 +- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/gfz-cli/ActionsREL.cs b/src/gfz-cli/ActionsREL.cs index 52d8261..4d7608a 100644 --- a/src/gfz-cli/ActionsREL.cs +++ b/src/gfz-cli/ActionsREL.cs @@ -1,5 +1,4 @@ using GameCube.GFZ; -using GameCube.GFZ.LZ; using GameCube.GFZ.REL; using System.IO; using static Manifold.GFZCLI.GfzCliUtilities; @@ -8,23 +7,21 @@ namespace Manifold.GFZCLI { public static class ActionsREL { - public static void DecryptEnemyLine__(Options options) + public static void DecryptLine__(Options options) { - // bool hasNoSearchPattern = string.IsNullOrEmpty(options.SearchPattern); if (hasNoSearchPattern) options.SearchPattern = $"*line__.bin"; - DoFileInFileOutTasks(options, DecryptEnemyLine); + DoFileInFileOutTasks(options, DecryptLine); } - public static void EncryptEnemyLine__(Options options) + public static void EncryptLine__(Options options) { - // bool hasNoSearchPattern = string.IsNullOrEmpty(options.SearchPattern); if (hasNoSearchPattern) options.SearchPattern = $"*line__.rel"; - DoFileInFileOutTasks(options, EncryptEnemyLine); + DoFileInFileOutTasks(options, EncryptLine); } public static void CryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile, bool doEncrypt, string extension) @@ -51,10 +48,34 @@ public static void CryptEnemyLine(Options options, FilePath inputFile, FilePath }; FileWriteOverwriteHandler(options, fileWrite, info); } - public static void DecryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile) - => CryptEnemyLine(options, inputFile, outputFile, false, "rel2"); - public static void EncryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile) - => CryptEnemyLine(options, inputFile, outputFile, true, "bin2"); + + public static void DecryptLine(Options options, FilePath inputFile, FilePath outputFile) + { + // Step 1: Decrypt line__.bin into line__.rel.lz + CryptEnemyLine(options, inputFile, outputFile, false, "rel.lz"); + + // Step 2: Get path to line__.rel.lz + FilePath lzInputFile = new FilePath(outputFile); + lzInputFile.SetExtensions("rel.lz"); + FilePath lzOutputFile = new FilePath(lzInputFile); + + // Step 3: Decompress line__.rel.lz into line__.rel + ActionsLZ.LzDecompressFile(options, lzInputFile, lzOutputFile); + } + + public static void EncryptLine(Options options, FilePath inputFile, FilePath outputFile) + { + // Step 1: Compress line__.rel to line__.rel.lz + ActionsLZ.LzCompressFile(options, inputFile, outputFile); + + // Step 2: Get path to line__.rel.lz + FilePath lzInputFile = new FilePath(outputFile); + lzInputFile.PushExtension("lz"); + FilePath lzOutputFile = new FilePath(lzInputFile); + + // Step 3: Encrypt line_rel.lz into line__.bin + CryptEnemyLine(options, lzInputFile, lzOutputFile, true, "bin"); + } } } diff --git a/src/gfz-cli/Program.cs b/src/gfz-cli/Program.cs index b0a265a..549c08b 100644 --- a/src/gfz-cli/Program.cs +++ b/src/gfz-cli/Program.cs @@ -81,8 +81,8 @@ public static void ExecuteAction(Options options) case GfzCliAction.lz_compress: ActionsLZ.LzCompress(options); break; case GfzCliAction.lz_decompress: ActionsLZ.LzDecompress(options); break; // REL - case GfzCliAction.rel_decrypt_line__: ActionsREL.DecryptEnemyLine__(options); break; - case GfzCliAction.rel_encrypt_line__: ActionsREL.EncryptEnemyLine__(options); break; + case GfzCliAction.rel_decrypt_line__: ActionsREL.DecryptLine__(options); break; + case GfzCliAction.rel_encrypt_line__: ActionsREL.EncryptLine__(options); break; // TPL case GfzCliAction.tpl_unpack: ActionsTPL.TplUnpack(options); break; //case GfzCliAction.tpl_pack: TplPack(options); break; diff --git a/src/gfz-cli/Properties/launchSettings.json b/src/gfz-cli/Properties/launchSettings.json index 18c1380..1eb02c8 100644 --- a/src/gfz-cli/Properties/launchSettings.json +++ b/src/gfz-cli/Properties/launchSettings.json @@ -78,7 +78,7 @@ }, "rel": { "commandName": "Project", - "commandLineArgs": "rel-encrypt-line__ D:\\gfzj01\\ -s" + "commandLineArgs": "rel-encrypt-line__ D:\\gfzj01\\ -s -o" } } } \ No newline at end of file From ce9ceaa8d7f7b9f3da7bc267569a74aaf96d3d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Tue, 14 Nov 2023 00:28:26 -0500 Subject: [PATCH 17/18] m: Clean up REL code --- libs/GameCube.GFZ | 2 +- src/gfz-cli/ActionsREL.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/GameCube.GFZ b/libs/GameCube.GFZ index 6878dce..e6fdf06 160000 --- a/libs/GameCube.GFZ +++ b/libs/GameCube.GFZ @@ -1 +1 @@ -Subproject commit 6878dce7226a4476afa0404488bfa5f3a89fa5fc +Subproject commit e6fdf0688d629fd727136df3560b8cd896ad1f61 diff --git a/src/gfz-cli/ActionsREL.cs b/src/gfz-cli/ActionsREL.cs index 4d7608a..afa7340 100644 --- a/src/gfz-cli/ActionsREL.cs +++ b/src/gfz-cli/ActionsREL.cs @@ -15,6 +15,7 @@ public static void DecryptLine__(Options options) DoFileInFileOutTasks(options, DecryptLine); } + public static void EncryptLine__(Options options) { bool hasNoSearchPattern = string.IsNullOrEmpty(options.SearchPattern); From f1ce184b65c20b603eb308b8b208a4c9b5c336a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20T=C3=A9treault?= Date: Tue, 14 Nov 2023 00:49:56 -0500 Subject: [PATCH 18/18] Update usage guides with REL for line__ --- docs/usage-guide.md | 61 ++++++++++++++++++++++++++++++++++----- src/gfz-cli/ActionsREL.cs | 6 ++-- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/docs/usage-guide.md b/docs/usage-guide.md index 9d0f366..5eb3ad8 100644 --- a/docs/usage-guide.md +++ b/docs/usage-guide.md @@ -9,7 +9,7 @@ This document provides examples using Windows and calls the `gfz.exe` program. C | Operating System | Program Call | | ---------------- | ------------ | | Windows | `gfz.exe` | -| Linux | `./gfz` | +| Linux | `gfz` | | macOS | `gfz` | @@ -74,12 +74,13 @@ gfz.exe [action] [input-path] [output-path] [other-options] There are a few options that apply to all actions. -| Option Token | Brief Description | -| ------------------ | ------------------------------------------------------------ | -| `--overwrite` | Allow overwriting output files. Off by default. | -| `--search-pattern` | When ***input-path*** is a directory, the search pattern applied to find files in that directory. Uses single (`?`) and multi (`*`) character wildcards. | -| `--search-subdirs` | When ***input-path*** is a directory, the search pattern applies to subdirectories. Off by default. | -| `--format` | The target serialization format used. Either `ax` or `gx`. Set to `gx` by default. | +| Short Op | Long Option | Brief Description | +| -------- | ------------------ | ------------------------------------------------------------ | +| `-o` | `--overwrite` | Allow overwriting output files. Off by default. | +| `-p` | `--search-pattern` | When ***input-path*** is a directory, the search pattern applied to find files in that directory. Uses single (`?`) and multi (`*`) character wildcards. | +| `-s` | `--search-subdirs` | When ***input-path*** is a directory, the search pattern applies to subdirectories. Off by default. | +| `-f` | `--format` | The target serialization format used. Either `ax` or `gx`. Set to `gx` by default. | +| `-r` | `--region` | The target serialization region used. Options include Japan (`j`, `jp`), Europe (`p`, `eu`), and North America (`e`, `na`). Only needed when IO requires specific knowledge of region. Set to `j` by default. | @@ -298,6 +299,52 @@ gfz.exe lz-decompress in/ --search-subdirs +## REL Files + +Actions for managing `.rel` files. + +### enemy_line line__ file + +The file at path `./enemy_line/line__.bin` is an obfuscated `.rel.lz` file that contains a sizeable chunk of game data. The game does a few things to hide the nature of the file. + +#### Decrypt line__.bin + +To decrypt the file. + +```shell +# Decrypt file at path to *.rel.lz and *.rel +gfz.exe rel-decrypt-line__ in/enemy_line/line__.bin +``` + +You must specify the region and serialization formats as they differ between regions. + +```shell +# The default region information and search "*line__.bin" +gfz.exe rel-decrypt-line__ in/ -search-subdirs --region j +``` + +Right now only GX is supported. AX stores the data elsewhere. + +#### Encrypt line__.rel + +To encrypt the file. + +```shell +# Encrypt file at path to *.rel.lz and *.bin +gfz.exe rel-encrypt-line__ in/enemy_line/line__.rel +``` + +You must specify the region and serialization formats as they differ between regions. + +```shell +# The default region information and search "*line__.rel" +gfz.exe rel-encrypt-line__ in/enemy_line/line__.rel --search-subdirs --region j +``` + +Right now only GX is supported. AX stores the data elsewhere. + + + ## TPL Texture Palettes Actions for managing `.tpl` files. diff --git a/src/gfz-cli/ActionsREL.cs b/src/gfz-cli/ActionsREL.cs index afa7340..07f71d4 100644 --- a/src/gfz-cli/ActionsREL.cs +++ b/src/gfz-cli/ActionsREL.cs @@ -25,7 +25,7 @@ public static void EncryptLine__(Options options) DoFileInFileOutTasks(options, EncryptLine); } - public static void CryptEnemyLine(Options options, FilePath inputFile, FilePath outputFile, bool doEncrypt, string extension) + public static void CryptLine(Options options, FilePath inputFile, FilePath outputFile, bool doEncrypt, string extension) { // Remove extension outputFile.PopExtension(); @@ -53,7 +53,7 @@ public static void CryptEnemyLine(Options options, FilePath inputFile, FilePath public static void DecryptLine(Options options, FilePath inputFile, FilePath outputFile) { // Step 1: Decrypt line__.bin into line__.rel.lz - CryptEnemyLine(options, inputFile, outputFile, false, "rel.lz"); + CryptLine(options, inputFile, outputFile, false, "rel.lz"); // Step 2: Get path to line__.rel.lz FilePath lzInputFile = new FilePath(outputFile); @@ -75,7 +75,7 @@ public static void EncryptLine(Options options, FilePath inputFile, FilePath out FilePath lzOutputFile = new FilePath(lzInputFile); // Step 3: Encrypt line_rel.lz into line__.bin - CryptEnemyLine(options, lzInputFile, lzOutputFile, true, "bin"); + CryptLine(options, lzInputFile, lzOutputFile, true, "bin"); } }