diff --git a/.vscode/launch.json b/.vscode/launch.json
index e867f06..befa809 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -8,8 +8,8 @@
"name": ".NET Launch (console)",
"type": "coreclr",
"request": "launch",
- "preLaunchTask": "build",
- "program": "${workspaceFolder}/src/JUS.CLI/bin/Debug/net8.0/JUS.CLI.dll",
+ "preLaunchTask": "Build",
+ "program": "${workspaceFolder}/src/JUS.CLI/bin/Debug/net10.0/JUS.CLI.dll",
"args": [
"jus",
"texts",
diff --git a/src/JUS.CLI/JUS/Rom/DemoImageFile.cs b/src/JUS.CLI/JUS/Rom/DemoImageFile.cs
new file mode 100644
index 0000000..40ab06e
--- /dev/null
+++ b/src/JUS.CLI/JUS/Rom/DemoImageFile.cs
@@ -0,0 +1,202 @@
+// Copyright (c) 2024 Priverop
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+using System.Text.RegularExpressions;
+using JUS.Tool.BatchConverters;
+using JUS.Tool.Containers.Converters;
+using JUS.Tool.Utils;
+using Yarhl.FileFormat;
+using Yarhl.FileSystem;
+
+namespace JUS.CLI.JUS.Rom
+{
+ ///
+ /// Strategy Pattern: Interface for rom importing logic.
+ ///
+ public class DemoImageFile : IFileImportStrategy
+ {
+ private static readonly Dictionary SpecialDigNumbers = new() {
+ { '0', '3' },
+ { '1', '5' },
+ { '2', '7' },
+ { '3', '9' },
+ };
+
+ private static readonly Regex DemoPattern = new(@"^demo-.*\.png$");
+
+ ///
+ public bool Matches(string filename)
+ {
+ return DemoPattern.IsMatch(filename);
+ }
+
+ ///
+ /// Import files into the Rom.
+ ///
+ /// The node of the Rom.
+ /// The input file to import.
+ public void Import(Node gameNode, Node file)
+ {
+ string containerPath = "/demo/demo.aar";
+
+ file.Name = StringFunctions.GetDemoName(file.Name);
+
+ // Ignore the _n_ and _m_, because we obtain them later with the original
+ if (!IsSpecialDemoNM(file.Name)) {
+ ProcessContainer(gameNode, file, containerPath);
+ }
+ }
+
+ private static void ProcessContainer(Node gameNode, Node pngFile, string containerPath)
+ {
+ Node originalAlar = Navigator.SearchNode(gameNode, $"/root/data{containerPath}") ?? throw new FormatException($"Container not found /root/data{containerPath}");
+
+ IConverter image2Alar3;
+
+ string digName = GetDemoDigName(pngFile.Name) + ".dig";
+ string atmName = Path.GetFileNameWithoutExtension(pngFile.Name) + ".atm";
+
+ // Special demo (3, 5, 7, 9) needs 3 atm, 3 pngs and 1 dig
+ // The rest (non special 2, 4, 6, title..., opening or sel) are 1 dig = 1 atm = 1 png
+ if (IsSpecialDemo(pngFile.Name) && !pngFile.Name.Contains("opening") && !pngFile.Name.Contains("sel01")) {
+ string[] atms = GetSpecialAtms(atmName);
+ Node[] pngs = GetSpecialPngs(pngFile);
+ image2Alar3 = new Demo2Alar3(pngs, digName, atms, true);
+ } else {
+ image2Alar3 = new Png2Alar3(pngFile, digName, atmName, true);
+ }
+
+ _ = originalAlar.TransformWith()
+ .TransformWith(image2Alar3)
+ .TransformWith(new Alar3ToBinary());
+
+ Console.WriteLine($"File replaced: /root/data{containerPath}/{pngFile.Name}");
+ }
+
+ ///
+ /// Returns true if the png is a Special Demo Image.
+ ///
+ /// The name of the Png we are importing.
+ /// True if it's a special demo image (03, 05, 07, 09, _m_ or _n_). False otherwise.
+ private static bool IsSpecialDemo(string pngName) =>
+ pngName.Contains("_03") ||
+ pngName.Contains("_05") ||
+ pngName.Contains("_07") ||
+ pngName.Contains("_09") ||
+ pngName.Contains("_m_") ||
+ pngName.Contains("_n_");
+
+ ///
+ /// Returns true if the png is a _m_ or _n_ Special Demo Image.
+ ///
+ /// The name of the Png we are importing.
+ /// True if it's a special demo image (_m_ or _n_). False otherwise.
+ private static bool IsSpecialDemoNM(string pngName) =>
+ pngName.Contains("_m_") ||
+ pngName.Contains("_n_");
+
+ ///
+ /// Obtains the name of the corresponding Dig.
+ ///
+ ///
+ /// bb_00.png => bb_00.dig
+ /// bb_m_00.png => bb_03.dig
+ /// bb_n_00.png => bb_03.dig
+ /// bb_m_01.png => bb_05.dig
+ /// bb_n_01.png => bb_05.dig
+ /// bb_m_02.png => bb_07.dig
+ /// bb_n_02.png => bb_07.dig
+ /// bb_m_03.png => bb_09.dig
+ /// bb_n_03.png => bb_09.dig.
+ ///
+ private static string GetDemoDigName(string pngName)
+ {
+ // SpecialChar is the 4th character of the demo png name.
+ // jj_m_00.png => m
+ // jj_n_00.png => n
+ // jj_03.png => not n nor m, so it's not a special one
+ if (pngName.Contains("_m_") || pngName.Contains("_n_")) {
+ // jj_m_01.png => 1
+ char number = pngName[6];
+ string manga = pngName[..2];
+ return manga + "_0" + SpecialDigNumbers.GetValueOrDefault(number);
+ } else {
+ return Path.GetFileNameWithoutExtension(pngName);
+ }
+ }
+
+ ///
+ /// Constructs the names of the _m_ and _n_ files for the given base node name and extension.
+ ///
+ /// The base name of the node ("bb_03.png").
+ /// The file extension (".png", ".atm").
+ /// An array of strings containing the names of the base, _m_, and _n_ files.
+ private static string[] GetSpecialFileNames(string nodeName, string extension)
+ {
+ string manga = nodeName[..2]; // "bb"
+ char number = nodeName[4]; // '3'
+
+ if (!SpecialDigNumbers.Any(kv => kv.Value == number)) {
+ throw new InvalidOperationException($"Value {number} is not found in SpecialDigNumbers.");
+ }
+
+ char specialNumber = SpecialDigNumbers.First(kv => kv.Value == number).Key;
+
+ string nameOfMFile = $"{manga}_m_0{specialNumber}{extension}";
+ string nameOfNFile = $"{manga}_n_0{specialNumber}{extension}";
+
+ return [nodeName, nameOfMFile, nameOfNFile];
+ }
+
+ ///
+ /// Returns an array of Nodes with the given PNG Node, the _m_ and _n_ Nodes.
+ ///
+ ///
+ /// bb_03.png => [bb_03.png, bb_m_00.png, bb_n_00.png]
+ /// bb_05.png => [bb_05.png, bb_m_01.png, bb_n_01.png]
+ /// bb_07.png => [bb_07.png, bb_m_02.png, bb_n_02.png]
+ /// bb_09.png => [bb_09.png, bb_m_03.png, bb_n_03.png].
+ ///
+ private static Node[] GetSpecialPngs(Node png)
+ {
+ string[] fileNames = GetSpecialFileNames(png.Name, ".png");
+
+ Node mNode = png.Parent!.Children["demo-" + fileNames[1]] ??
+ throw new FormatException("Special m file not found: " + fileNames[1]);
+ Node nNode = png.Parent.Children["demo-" + fileNames[2]] ??
+ throw new FormatException("Special nfile not found: " + fileNames[2]);
+
+ return [png, mNode, nNode];
+ }
+
+ ///
+ /// Returns an array of strings with the names of the given ATM file, the _m_, and the _n_ files.
+ ///
+ ///
+ /// bb_03.atm => [bb_03.atm, bb_m_00.atm, bb_n_00.atm]
+ /// bb_05.atm => [bb_05.atm, bb_m_01.atm, bb_n_01.atm]
+ /// bb_07.atm => [bb_07.atm, bb_m_02.atm, bb_n_02.atm]
+ /// bb_09.atm => [bb_09.atm, bb_m_03.atm, bb_n_03.atm].
+ ///
+ private static string[] GetSpecialAtms(string atm)
+ {
+ return GetSpecialFileNames(atm, ".atm");
+ }
+ }
+}
diff --git a/src/JUS.CLI/JUS/Rom/IFileImportStrategy.cs b/src/JUS.CLI/JUS/Rom/IFileImportStrategy.cs
index 1b09f70..9d6949d 100644
--- a/src/JUS.CLI/JUS/Rom/IFileImportStrategy.cs
+++ b/src/JUS.CLI/JUS/Rom/IFileImportStrategy.cs
@@ -26,6 +26,12 @@ namespace JUS.CLI.JUS.Rom
///
public interface IFileImportStrategy
{
+ ///
+ /// Checks if the strategy supports a filename.
+ ///
+ /// The name of the file to check.
+ bool Matches(string filename);
+
///
/// Import files into the Rom.
///
diff --git a/src/JUS.CLI/JUS/Rom/ImageContainerFile.cs b/src/JUS.CLI/JUS/Rom/ImageContainerFile.cs
deleted file mode 100644
index 09c7432..0000000
--- a/src/JUS.CLI/JUS/Rom/ImageContainerFile.cs
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright (c) 2024 Priverop
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-using System.Text.RegularExpressions;
-using JUS.Tool.BatchConverters;
-using JUS.Tool.Containers;
-using JUS.Tool.Containers.Converters;
-using JUS.Tool.Utils;
-using Yarhl.FileFormat;
-using Yarhl.FileSystem;
-using Yarhl.IO;
-
-namespace JUS.CLI.JUS.Rom
-{
- ///
- /// Strategy Pattern: Interface for rom importing logic.
- ///
- public class ImageContainerFile : IFileImportStrategy
- {
- private static readonly Dictionary ContainerLocations = new() {
- { "menu-Commu-code.png", ["code.dig", "code.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-matchmake.png", ["matchmake.dig", "matchmake.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-member.png", ["member.dig", "member.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-member_data.png", ["member.dig", "member_data.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-member_wireless.png", ["member.dig", "member_wireless.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-sure02.png", ["sure02.dig", "sure02.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-top_left.png", ["top_left.dig", "top_left.atm", "/Commu/commu_pack.aar"] },
- { "menu-Commu-top_right.png", ["top_right.dig", "top_right.atm", "/Commu/commu_pack.aar"] },
- { "menu-JArena-a_result01.png", ["a_result01.dig", "a_result01.atm", "/JArena/JArena.aar"] },
- { "menu-JArena-congra_top00.png", ["congra_top00.dig", "congra_top00.atm", "/JArena/JArena.aar"] },
- { "menu-JArena-mis01.png", ["mis01.dig", "mis01.atm", "/JArena/JArena.aar"] },
- { "menu-JArena-mis_top10.png", ["mis_top10.dig", "mis_top10.atm", "/JArena/JArena.aar"] },
- { "menu-JArena-ranking_list.png", ["ranking_list.dig", "ranking_list.atm", "/JArena/JArena.aar"] },
- { "menu-database-list_bg0.png", ["list_bg0.dig", "list_bg0.atm", "/database/database.aar"] },
- { "menu-database-personal_bg.png", ["personal_bg.dig", "personal_bg.atm", "/database/database.aar"] },
- { "menu-database-personal_bg2.png", ["personal_bg2.dig", "personal_bg2.atm", "/database/database.aar"] },
- { "menu-database-playing.png", ["playing.dig", "playing.atm", "/database/database.aar"] },
- { "menu-database-story_bg0.png", ["story_bg0.dig", "story_bg0.atm", "/database/database.aar"] },
- { "menu-database-story_bg1.png", ["story_bg1.dig", "story_bg1.atm", "/database/database.aar"] },
- { "menu-deckcheck-win_a.png", ["win.dig", "win_a.atm", "/deckcheck/deckcheck.aar"] },
- { "menu-deckcheck-win_g.png", ["win.dig", "win_g.atm", "/deckcheck/deckcheck.aar"] },
- { "menu-deckselect-deck_standby00.png", ["deck_standby00.dig", "deck_standby00.atm", "/deckselect/deckselect.aar"] },
- { "menu-deckselect-deck_standby01.png", ["deck_standby01.dig", "deck_standby01.atm", "/deckselect/deckselect.aar"] },
- { "menu-input-mode_bg0.png", ["mode_bg0.dig", "mode_bg0.atm", "/input/input.aar"] },
- { "menu-input-mode_bg1.png", ["mode_bg1.dig", "mode_bg1.atm", "/input/input.aar"] },
- { "menu-input-mode_bg2.png", ["mode_bg2.dig", "mode_bg2.atm", "/input/input.aar"] },
- { "menu-input-mode_bg3.png", ["mode_bg3.dig", "mode_bg3.atm", "/input/input.aar"] },
- { "menu-jgalaxy-ba_m_sel01.png", ["ba_m_sel01.dig", "ba_m_sel01.atm", "/jgalaxy/jgalaxy.aar"] },
- { "menu-jgalaxy-victory00.png", ["victory00.dig", "victory00.atm", "/jgalaxy/jgalaxy.aar"] },
- { "menu-jgalaxy-victory01.png", ["victory00.dig", "victory01.atm", "/jgalaxy/jgalaxy.aar"] },
- { "menu-jgalaxy-win_sel.png", ["win_sel.dig", "win_sel.atm", "/jgalaxy/jgalaxy.aar"] },
- { "menu-jpower-jp.png", ["jp.dig", "jp.atm", "/jpower/jpower.aar"] },
- { "menu-jpower-jp_top.png", ["jp_top.dig", "jp_top.atm", "/jpower/jpower.aar"] },
- { "menu-option-info00.png", ["info00.dig", "info00.atm", "/option/option.aar"] },
- { "menu-option-option.png", ["option.dig", "option.atm", "/option/option.aar"] },
- { "menu-ruleselect-rule_sel00.png", ["rule_sel00.dig", "rule_sel00.atm", "/ruleselect/ruleselect.aar"] },
- { "menu-stageselect-st_sel01.png", ["st_sel01.dig", "st_sel01.atm", "/stageselect/stageselect.aar"] },
- { "menu-topmenu-top_bg01.png", ["top_bg01.dig", "top_bg01.atm", "/topmenu/topmenu.aar"] },
- };
-
- private static readonly Dictionary SpecialDigNumbers = new() {
- { '0', '3' },
- { '1', '5' },
- { '2', '7' },
- { '3', '9' },
- };
-
- private static readonly List<(Regex, string[])> PatternList = new()
- {
- (new Regex(@"^demo-.*\.png$"), ["/demo/demo.aar"]),
- };
-
- ///
- /// Import files into the Rom.
- ///
- /// The node of the Rom.
- /// The input file to import.
- public void Import(Node gameNode, Node file)
- {
- if (ContainerLocations.TryGetValue(file.Name, out string[]? imageInfo)) {
- file.Name = StringFunctions.GetOriginalName(file.Name);
- ProcessContainer(gameNode, file, imageInfo);
- } else {
- // Si no se encuentra, intenta encontrar la ruta interna usando patrones
- foreach ((Regex pattern, string[] containerPath) in PatternList) {
- if (pattern.IsMatch(file.Name)) {
- file.Name = StringFunctions.GetDemoName(file.Name);
-
- // Ignore the _n_ and _m_, because we obtain them later with the original
- if (!IsSpecialDemoNM(file.Name)) {
- // Get the Dig, Atm and Alar
- string[] demoInfo = GetDemoInfo(file.Name, containerPath);
- ProcessContainer(gameNode, file, demoInfo, true);
- }
-
- return;
- }
- }
-
- Console.WriteLine($"File not compatible as image container: {file.Name}");
- }
- }
-
- private static void ProcessContainer(Node gameNode, Node pngFile, string[] imageInfo, bool transparentTile = false)
- {
- // 1 - Search the Original Alar3
- Node originalAlar = Navigator.SearchNode(gameNode, $"/root/data{imageInfo[2]}") ?? throw new FormatException($"Container not found /root/data{imageInfo[2]}");
- _ = originalAlar.TransformWith();
-
- // 2 - Insert the Png into the Alar3
- IConverter image2Alar3;
-
- // Special demo needs 3 atm, 3 pngs and 1 dig (imageInfo[0])
- if (IsSpecialDemo(pngFile.Name) && !pngFile.Name.Contains("opening") && !pngFile.Name.Contains("sel01")) {
- string[] atms = GetSpecialAtms(imageInfo[1]);
- Node[] pngs = GetSpecialPngs(pngFile);
- image2Alar3 = new Demo2Alar3(pngs, imageInfo[0], atms, transparentTile);
- } else {
- image2Alar3 = new Png2Alar3(pngFile, imageInfo[0], imageInfo[1], transparentTile);
- }
-
- Alar newAlar = originalAlar
- .TransformWith(image2Alar3)
- .GetFormatAs()!;
-
- BinaryFormat newBinary = newAlar.ConvertWith(new Alar3ToBinary());
-
- // 3 - Sustituirlo
- _ = originalAlar.ChangeFormat(newBinary);
-
- Console.WriteLine($"File replaced: /root/data{imageInfo[2]}/{pngFile.Name}");
- }
-
- ///
- /// Get the atm and dig names.
- ///
- /// The name of the Png we are importing.
- /// The path of the alar container of the file.
- /// An array with the DIG, ATM, and ContainerPath (.aar) names.
- private static string[] GetDemoInfo(string pngName, string[] containerPath)
- => [GetDemoDigName(pngName) + ".dig",
- Path.GetFileNameWithoutExtension(pngName) + ".atm",
- containerPath[0]];
-
- ///
- /// Returns true if the png is a Special Demo Image.
- ///
- /// The name of the Png we are importing.
- /// True if it's a special demo image (03, 05, 07, 09, _m_ or _n_). False otherwise.
- private static bool IsSpecialDemo(string pngName) =>
- pngName.Contains("_03") ||
- pngName.Contains("_05") ||
- pngName.Contains("_07") ||
- pngName.Contains("_09") ||
- pngName.Contains("_m_") ||
- pngName.Contains("_n_");
-
- ///
- /// Returns true if the png is a _m_ or _n_ Special Demo Image.
- ///
- /// The name of the Png we are importing.
- /// True if it's a special demo image (_m_ or _n_). False otherwise.
- private static bool IsSpecialDemoNM(string pngName) =>
- pngName.Contains("_m_") ||
- pngName.Contains("_n_");
-
- ///
- /// Obtains the name of the corresponding Dig.
- ///
- ///
- /// bb_00.png => bb_00.dig
- /// bb_m_00.png => bb_03.dig
- /// bb_n_00.png => bb_03.dig
- /// bb_m_01.png => bb_05.dig
- /// bb_n_01.png => bb_05.dig
- /// bb_m_02.png => bb_07.dig
- /// bb_n_02.png => bb_07.dig
- /// bb_m_03.png => bb_09.dig
- /// bb_n_03.png => bb_09.dig.
- ///
- private static string GetDemoDigName(string pngName)
- {
- // SpecialChar is the 4th character of the demo png name.
- // jj_m_00.png => m
- // jj_n_00.png => n
- // jj_03.png => not n nor m, so it's not a special one
- if (pngName.Contains("_m_") || pngName.Contains("_n_")) {
- // jj_m_01.png => 1
- char number = pngName[6];
- string manga = pngName[..2];
- return manga + "_0" + SpecialDigNumbers.GetValueOrDefault(number);
- } else {
- return Path.GetFileNameWithoutExtension(pngName);
- }
- }
-
- ///
- /// Constructs the names of the _m_ and _n_ files for the given base node name and extension.
- ///
- /// The base name of the node ("bb_03.png").
- /// The file extension (".png", ".atm").
- /// An array of strings containing the names of the base, _m_, and _n_ files.
- private static string[] GetSpecialFileNames(string nodeName, string extension)
- {
- string manga = nodeName[..2]; // "bb"
- char number = nodeName[4]; // '3'
-
- if (!SpecialDigNumbers.Any(kv => kv.Value == number)) {
- throw new InvalidOperationException($"Value {number} is not found in SpecialDigNumbers.");
- }
-
- char specialNumber = SpecialDigNumbers.First(kv => kv.Value == number).Key;
-
- string nameOfMFile = $"{manga}_m_0{specialNumber}{extension}";
- string nameOfNFile = $"{manga}_n_0{specialNumber}{extension}";
-
- return new[] { nodeName, nameOfMFile, nameOfNFile };
- }
-
- ///
- /// Returns an array of Nodes with the given PNG Node, the _m_ and _n_ Nodes.
- ///
- ///
- /// bb_03.png => [bb_03.png, bb_m_00.png, bb_n_00.png]
- /// bb_05.png => [bb_05.png, bb_m_01.png, bb_n_01.png]
- /// bb_07.png => [bb_07.png, bb_m_02.png, bb_n_02.png]
- /// bb_09.png => [bb_09.png, bb_m_03.png, bb_n_03.png].
- ///
- private static Node[] GetSpecialPngs(Node png)
- {
- string[] fileNames = GetSpecialFileNames(png.Name, ".png");
-
- Node mNode = png.Parent!.Children["demo-" + fileNames[1]] ??
- throw new FormatException("Special m file not found: " + fileNames[1]);
- Node nNode = png.Parent.Children["demo-" + fileNames[2]] ??
- throw new FormatException("Special nfile not found: " + fileNames[2]);
-
- return new[] { png, mNode, nNode };
- }
-
- ///
- /// Returns an array of strings with the names of the given ATM file, the _m_, and the _n_ files.
- ///
- ///
- /// bb_03.atm => [bb_03.atm, bb_m_00.atm, bb_n_00.atm]
- /// bb_05.atm => [bb_05.atm, bb_m_01.atm, bb_n_01.atm]
- /// bb_07.atm => [bb_07.atm, bb_m_02.atm, bb_n_02.atm]
- /// bb_09.atm => [bb_09.atm, bb_m_03.atm, bb_n_03.atm].
- ///
- private static string[] GetSpecialAtms(string atm)
- {
- return GetSpecialFileNames(atm, ".atm");
- }
- }
-}
diff --git a/src/JUS.CLI/JUS/Rom/MenuImageFile.cs b/src/JUS.CLI/JUS/Rom/MenuImageFile.cs
new file mode 100644
index 0000000..d530575
--- /dev/null
+++ b/src/JUS.CLI/JUS/Rom/MenuImageFile.cs
@@ -0,0 +1,105 @@
+// Copyright (c) 2024 Priverop
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+using JUS.Tool.BatchConverters;
+using JUS.Tool.Containers.Converters;
+using JUS.Tool.Utils;
+using Yarhl.FileSystem;
+
+namespace JUS.CLI.JUS.Rom
+{
+ ///
+ /// Strategy Pattern: Interface for rom importing logic.
+ ///
+ public class MenuImageFile : IFileImportStrategy
+ {
+ private static readonly Dictionary ContainerLocations = new() {
+ { "menu-Commu-code.png", ["code.dig", "code.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-matchmake.png", ["matchmake.dig", "matchmake.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-member.png", ["member.dig", "member.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-member_data.png", ["member.dig", "member_data.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-member_wireless.png", ["member.dig", "member_wireless.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-sure02.png", ["sure02.dig", "sure02.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-top_left.png", ["top_left.dig", "top_left.atm", "/Commu/commu_pack.aar"] },
+ { "menu-Commu-top_right.png", ["top_right.dig", "top_right.atm", "/Commu/commu_pack.aar"] },
+ { "menu-JArena-a_result01.png", ["a_result01.dig", "a_result01.atm", "/JArena/JArena.aar"] },
+ { "menu-JArena-congra_top00.png", ["congra_top00.dig", "congra_top00.atm", "/JArena/JArena.aar"] },
+ { "menu-JArena-mis01.png", ["mis01.dig", "mis01.atm", "/JArena/JArena.aar"] },
+ { "menu-JArena-mis_top10.png", ["mis_top10.dig", "mis_top10.atm", "/JArena/JArena.aar"] },
+ { "menu-JArena-ranking_list.png", ["ranking_list.dig", "ranking_list.atm", "/JArena/JArena.aar"] },
+ { "menu-database-list_bg0.png", ["list_bg0.dig", "list_bg0.atm", "/database/database.aar"] },
+ { "menu-database-personal_bg.png", ["personal_bg.dig", "personal_bg.atm", "/database/database.aar"] },
+ { "menu-database-personal_bg2.png", ["personal_bg2.dig", "personal_bg2.atm", "/database/database.aar"] },
+ { "menu-database-playing.png", ["playing.dig", "playing.atm", "/database/database.aar"] },
+ { "menu-database-story_bg0.png", ["story_bg0.dig", "story_bg0.atm", "/database/database.aar"] },
+ { "menu-database-story_bg1.png", ["story_bg1.dig", "story_bg1.atm", "/database/database.aar"] },
+ { "menu-deckcheck-win_a.png", ["win.dig", "win_a.atm", "/deckcheck/deckcheck.aar"] },
+ { "menu-deckcheck-win_g.png", ["win.dig", "win_g.atm", "/deckcheck/deckcheck.aar"] },
+ { "menu-deckselect-deck_standby00.png", ["deck_standby00.dig", "deck_standby00.atm", "/deckselect/deckselect.aar"] },
+ { "menu-deckselect-deck_standby01.png", ["deck_standby01.dig", "deck_standby01.atm", "/deckselect/deckselect.aar"] },
+ { "menu-input-mode_bg0.png", ["mode_bg0.dig", "mode_bg0.atm", "/input/input.aar"] },
+ { "menu-input-mode_bg1.png", ["mode_bg1.dig", "mode_bg1.atm", "/input/input.aar"] },
+ { "menu-input-mode_bg2.png", ["mode_bg2.dig", "mode_bg2.atm", "/input/input.aar"] },
+ { "menu-input-mode_bg3.png", ["mode_bg3.dig", "mode_bg3.atm", "/input/input.aar"] },
+ { "menu-jgalaxy-ba_m_sel01.png", ["ba_m_sel01.dig", "ba_m_sel01.atm", "/jgalaxy/jgalaxy.aar"] },
+ { "menu-jgalaxy-victory00.png", ["victory00.dig", "victory00.atm", "/jgalaxy/jgalaxy.aar"] },
+ { "menu-jgalaxy-victory01.png", ["victory00.dig", "victory01.atm", "/jgalaxy/jgalaxy.aar"] },
+ { "menu-jgalaxy-win_sel.png", ["win_sel.dig", "win_sel.atm", "/jgalaxy/jgalaxy.aar"] },
+ { "menu-jpower-jp.png", ["jp.dig", "jp.atm", "/jpower/jpower.aar"] },
+ { "menu-jpower-jp_top.png", ["jp_top.dig", "jp_top.atm", "/jpower/jpower.aar"] },
+ { "menu-option-info00.png", ["info00.dig", "info00.atm", "/option/option.aar"] },
+ { "menu-option-option.png", ["option.dig", "option.atm", "/option/option.aar"] },
+ { "menu-ruleselect-rule_sel00.png", ["rule_sel00.dig", "rule_sel00.atm", "/ruleselect/ruleselect.aar"] },
+ { "menu-stageselect-st_sel01.png", ["st_sel01.dig", "st_sel01.atm", "/stageselect/stageselect.aar"] },
+ { "menu-topmenu-top_bg01.png", ["top_bg01.dig", "top_bg01.atm", "/topmenu/topmenu.aar"] },
+ };
+
+ ///
+ public bool Matches(string filename)
+ {
+ return ContainerLocations.ContainsKey(filename);
+ }
+
+ ///
+ /// Import files into the Rom.
+ ///
+ /// The node of the Rom.
+ /// The input file to import.
+ public void Import(Node gameNode, Node file)
+ {
+ if (ContainerLocations.TryGetValue(file.Name, out string[]? imageInfo)) {
+ file.Name = StringFunctions.GetOriginalName(file.Name);
+ ProcessContainer(gameNode, file, imageInfo);
+ } else {
+ Console.WriteLine($"File not compatible as menu image: {file.Name}");
+ }
+ }
+
+ private static void ProcessContainer(Node gameNode, Node pngFile, string[] imageInfo)
+ {
+ Node originalAlar = Navigator.SearchNode(gameNode, $"/root/data{imageInfo[2]}") ?? throw new FormatException($"Container not found /root/data{imageInfo[2]}");
+
+ originalAlar.TransformWith()
+ .TransformWith(new Png2Alar3(pngFile, imageInfo[0], imageInfo[1]))
+ .TransformWith(new Alar3ToBinary());
+
+ Console.WriteLine($"File replaced: /root/data{imageInfo[2]}/{pngFile.Name}");
+ }
+ }
+}
diff --git a/src/JUS.CLI/JUS/Rom/TextContainerFile.cs b/src/JUS.CLI/JUS/Rom/TextContainerFile.cs
index c70e82a..dda9e87 100644
--- a/src/JUS.CLI/JUS/Rom/TextContainerFile.cs
+++ b/src/JUS.CLI/JUS/Rom/TextContainerFile.cs
@@ -17,14 +17,9 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-using System.Text.RegularExpressions;
using JUS.Tool.Containers;
using JUS.Tool.Containers.Converters;
-using JUS.Tool.Graphics.Converters;
-using JUS.Tool.Utils;
-using Yarhl.FileFormat;
using Yarhl.FileSystem;
-using Yarhl.IO;
namespace JUS.CLI.JUS.Rom
{
@@ -40,11 +35,11 @@ public class TextContainerFile : IFileImportStrategy
{ "jquiz.bin", "/jquiz/jquiz_pack.aar" },
};
- private static readonly List<(Regex, string)> PatternList = new()
+ ///
+ public bool Matches(string filename)
{
- (new Regex(@"^bin-.*-.*\.bin$"), "/bin/InfoDeck.aar"), // "{container}/bin/deck/{file.Name}"
- (new Regex(@"^deck-.*-.*\.bin$"), "/deck/Deck.aar"), // "{container}/bin/deck/{file.Name}"
- };
+ return ContainerLocations.ContainsKey(filename);
+ }
///
/// Import files into the Rom.
@@ -57,39 +52,23 @@ public void Import(Node gameNode, Node file)
file.Name = GetFileName(file.Name);
ProcessContainer(gameNode, file, path);
} else {
- // Si no se encuentra, intenta encontrar la ruta interna usando patrones
- foreach ((Regex pattern, string containerPath) in PatternList) {
- if (pattern.IsMatch(file.Name)) {
- string? parent = GetParentName(file.Name);
- file.Name = StringFunctions.GetOriginalName(file.Name);
- ProcessContainer(gameNode, file, containerPath, parent);
- return;
- }
- }
-
Console.WriteLine($"File not compatible as text container: {file.Name}");
}
}
- private static void ProcessContainer(Node gameNode, Node file, string containerPath, string? parent = null)
+ private static void ProcessContainer(Node gameNode, Node file, string containerPath)
{
- Node containerNode = Navigator.SearchNode(gameNode, $"/root/data{containerPath}")!;
-
- Alar alar = containerNode.TransformWith()
- .GetFormatAs()!;
- alar.InsertModification(file, parent!);
- BinaryFormat newBinary = alar.ConvertWith(new Alar3ToBinary());
+ Node containerNode = Navigator.SearchNode(gameNode, $"/root/data{containerPath}") ?? throw new FormatException($"Container not found /root/data{containerPath}");
- _ = containerNode.ChangeFormat(newBinary);
+ Alar alar = containerNode.TransformWith().GetFormatAs()!;
+ alar.InsertModification(file);
+ _ = containerNode.TransformWith(new Alar3ToBinary());
- string fullPath = parent != null
- ? $"/root/data{containerPath}/{parent}/{file.Name}"
- : $"/root/data{containerPath}/{file.Name}";
- Console.WriteLine($"File replaced: {fullPath}");
+ Console.WriteLine($"File replaced: /root/data{containerPath}/{file.Name}");
}
///
- /// Gets the file name without the container prefix. "jgalaxy-mission.bin" will return "mission.bin".
+ /// Gets the file name without the container prefix. "jgalaxy-mission.bin" returns "mission.bin".
///
private static string GetFileName(string name)
{
@@ -99,27 +78,5 @@ private static string GetFileName(string name)
return name[(name.IndexOf('-') + 1)..];
}
-
- ///
- /// Gets the directory name of the file (parent). "bin-deck-bb.bin" will return "deck".
- ///
- /// The string containing potentially "bin-deck-", "bin-info-", "deck-play"... prefixes.
- /// The directory name. If the input string is null or empty, the original string is returned.
- private static string? GetParentName(string name)
- {
- if (string.IsNullOrEmpty(name) || !name.Contains('-')) {
- return null;
- }
-
- // Regular expression to capture the second word
- var regex = new Regex(@"^[^-]+-([^-]+)-");
- Match match = regex.Match(name);
-
- if (match.Success && match.Groups.Count > 1) {
- return match.Groups[1].Value;
- }
-
- return null;
- }
}
}
diff --git a/src/JUS.CLI/JUS/Rom/TextFile.cs b/src/JUS.CLI/JUS/Rom/TextFile.cs
index 68db0ba..19798e9 100644
--- a/src/JUS.CLI/JUS/Rom/TextFile.cs
+++ b/src/JUS.CLI/JUS/Rom/TextFile.cs
@@ -26,32 +26,37 @@ namespace JUS.CLI.JUS.Rom
///
public class TextFile : IFileImportStrategy
{
- // ToDo: Remove filename of the second string, we only need the directory
private static readonly Dictionary TextLocations = new() {
- { "tutorial.bin", "/deckmake/tutorial.bin" },
- { "tutorial0.bin", "/battle/tutorial0.bin" },
- { "tutorial1.bin", "/battle/tutorial1.bin" },
- { "tutorial2.bin", "/battle/tutorial2.bin" },
- { "tutorial3.bin", "/battle/tutorial3.bin" },
- { "tutorial4.bin", "/battle/tutorial4.bin" },
- { "tutorial5.bin", "/battle/tutorial5.bin" },
- { "ability_t.bin", "/bin/ability_t.bin" },
- { "bgm.bin", "/bin/bgm.bin" },
- { "chr_b_t.bin", "/bin/chr_b_t.bin" },
- { "chr_s_t.bin", "/bin/chr_s_t.bin" },
- { "clearlst.bin", "/bin/clearlst.bin" },
- { "commwin.bin", "/bin/commwin.bin" },
- { "demo.bin", "/bin/demo.bin" },
- { "infoname.bin", "/bin/infoname.bin" },
- { "komatxt.bin", "/bin/komatxt.bin" },
- { "location.bin", "/bin/location.bin" },
- { "piece.bin", "/bin/piece.bin" },
- { "pname.bin", "/bin/pname.bin" },
- { "rulemess.bin", "/bin/rulemess.bin" },
- { "stage.bin", "/bin/stage.bin" },
- { "title.bin", "/bin/title.bin" },
+ { "tutorial.bin", "/deckmake" },
+ { "tutorial0.bin", "/battle" },
+ { "tutorial1.bin", "/battle" },
+ { "tutorial2.bin", "/battle" },
+ { "tutorial3.bin", "/battle" },
+ { "tutorial4.bin", "/battle" },
+ { "tutorial5.bin", "/battle" },
+ { "ability_t.bin", "/bin" },
+ { "bgm.bin", "/bin" },
+ { "chr_b_t.bin", "/bin" },
+ { "chr_s_t.bin", "/bin" },
+ { "clearlst.bin", "/bin" },
+ { "commwin.bin", "/bin" },
+ { "demo.bin", "/bin" },
+ { "infoname.bin", "/bin" },
+ { "komatxt.bin", "/bin" },
+ { "location.bin", "/bin" },
+ { "piece.bin", "/bin" },
+ { "pname.bin", "/bin" },
+ { "rulemess.bin", "/bin" },
+ { "stage.bin", "/bin" },
+ { "title.bin", "/bin" },
};
+ ///
+ public bool Matches(string filename)
+ {
+ return TextLocations.ContainsKey(filename);
+ }
+
///
/// Import files into the Rom.
///
@@ -60,9 +65,9 @@ public class TextFile : IFileImportStrategy
public void Import(Node gameNode, Node file)
{
if (TextLocations.TryGetValue(file.Name, out string? value)) {
- Node toReplace = Navigator.SearchNode(gameNode, $"/root/data{value}")!;
+ Node toReplace = Navigator.SearchNode(gameNode, $"/root/data{value}/{file.Name}")!;
toReplace.ChangeFormat(file.Format!);
- Console.WriteLine($"File replaced: /root/data{value}");
+ Console.WriteLine($"File replaced: /root/data{value}/{file.Name}");
}
}
}
diff --git a/src/JUS.CLI/JUS/Rom/TextPatternFile.cs b/src/JUS.CLI/JUS/Rom/TextPatternFile.cs
new file mode 100644
index 0000000..d63903e
--- /dev/null
+++ b/src/JUS.CLI/JUS/Rom/TextPatternFile.cs
@@ -0,0 +1,89 @@
+// Copyright (c) 2024 Priverop
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+using System.Text.RegularExpressions;
+using JUS.Tool.Containers;
+using JUS.Tool.Containers.Converters;
+using JUS.Tool.Utils;
+using Yarhl.FileSystem;
+
+namespace JUS.CLI.JUS.Rom
+{
+ ///
+ /// Strategy Pattern: Interface for rom importing logic.
+ ///
+ public class TextPatternFile : IFileImportStrategy
+ {
+ private static readonly List<(Regex Pattern, string)> PatternList =
+ [
+ (new Regex(@"^bin-.*-.*\.bin$"), "/bin/InfoDeck.aar"), // "{container}/bin/deck/{file.Name}"
+ (new Regex(@"^deck-.*-.*\.bin$"), "/deck/Deck.aar"), // "{container}/bin/deck/{file.Name}"
+ ];
+
+ public bool Matches(string filename)
+ {
+ return PatternList.Any(x => x.Pattern.IsMatch(filename));
+ }
+
+ ///
+ /// Import files into the Rom.
+ ///
+ /// The node of the Rom.
+ /// The input file to import.
+ public void Import(Node gameNode, Node file)
+ {
+ // Si no se encuentra, intenta encontrar la ruta interna usando patrones
+ foreach ((Regex pattern, string containerPath) in PatternList) {
+ if (pattern.IsMatch(file.Name)) {
+ string parent = GetParentName(file.Name);
+ file.Name = StringFunctions.GetOriginalName(file.Name);
+ ProcessContainer(gameNode, file, containerPath, parent);
+ return;
+ }
+ }
+
+ Console.WriteLine($"File not compatible as text container: {file.Name}");
+ }
+
+ private static void ProcessContainer(Node gameNode, Node file, string containerPath, string parent)
+ {
+ Node containerNode = Navigator.SearchNode(gameNode, $"/root/data{containerPath}") ?? throw new FormatException($"Container not found /root/data{containerPath}");
+
+ Alar alar = containerNode.TransformWith().GetFormatAs()!;
+ alar.InsertModification(file, parent);
+ _ = containerNode.TransformWith(new Alar3ToBinary());
+
+ Console.WriteLine($"File replaced: /root/data{containerPath}/{parent}/{file.Name}");
+ }
+
+ ///
+ /// Gets the directory name of the file (parent). "bin-deck-bb.bin" will return "deck".
+ ///
+ /// The string containing potentially "bin-deck-", "bin-info-", "deck-play"... prefixes.
+ /// The directory name. If the input string is null or empty, the original string is returned.
+ private static string GetParentName(string name)
+ {
+ // Regular expression to capture the second word
+ var regex = new Regex(@"^[^-]+-([^-]+)-");
+ Match match = regex.Match(name);
+
+ return match.Groups[1].Value;
+ }
+ }
+}
diff --git a/src/JUS.CLI/JUS/RomCommands.cs b/src/JUS.CLI/JUS/RomCommands.cs
index 745ce6e..65c2418 100644
--- a/src/JUS.CLI/JUS/RomCommands.cs
+++ b/src/JUS.CLI/JUS/RomCommands.cs
@@ -17,7 +17,6 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-using System.Text.RegularExpressions;
using JUS.CLI.JUS.Rom;
using SceneGate.Ekona.Containers.Rom;
using Yarhl.FileSystem;
@@ -30,43 +29,14 @@ namespace JUS.CLI.JUS
///
public static class RomCommands
{
- private static readonly Dictionary ImportStrategies = new()
- {
- { "tutorial.bin", new TextFile() },
- { "tutorial0.bin", new TextFile() },
- { "tutorial1.bin", new TextFile() },
- { "tutorial2.bin", new TextFile() },
- { "tutorial3.bin", new TextFile() },
- { "tutorial4.bin", new TextFile() },
- { "tutorial5.bin", new TextFile() },
- { "ability_t.bin", new TextFile() },
- { "bgm.bin", new TextFile() },
- { "chr_b_t.bin", new TextFile() },
- { "chr_s_t.bin", new TextFile() },
- { "clearlst.bin", new TextFile() },
- { "commwin.bin", new TextFile() },
- { "demo.bin", new TextFile() },
- { "infoname.bin", new TextFile() },
- { "komatxt.bin", new TextFile() },
- { "location.bin", new TextFile() },
- { "piece.bin", new TextFile() },
- { "pname.bin", new TextFile() },
- { "rulemess.bin", new TextFile() },
- { "stage.bin", new TextFile() },
- { "title.bin", new TextFile() },
- { "jgalaxy-jgalaxy.bin", new TextContainerFile() },
- { "jgalaxy-mission.bin", new TextContainerFile() },
- { "jgalaxy-battle.bin", new TextContainerFile() },
- { "jquiz.bin", new TextContainerFile() },
- };
-
- private static readonly List<(Regex pattern, IFileImportStrategy strategy)> PatternStrategies = new()
- {
- (new Regex(@"^bin-.*-.*\.bin$"), new TextContainerFile()),
- (new Regex(@"^deck-.*-.*\.bin$"), new TextContainerFile()),
- (new Regex(@"^menu-.*-.*\.png$"), new ImageContainerFile()),
- (new Regex(@"^demo-.*\.png$"), new ImageContainerFile()),
- };
+ private static readonly IFileImportStrategy[] Strategies =
+ [
+ new TextFile(),
+ new TextContainerFile(),
+ new TextPatternFile(),
+ new MenuImageFile(),
+ new DemoImageFile(),
+ ];
///
/// Import files into the Rom.
@@ -84,24 +54,19 @@ public static void Import(string game, string input, string output)
Node inputFiles = NodeFactory.FromDirectory(input);
inputFiles.SortChildren((x, y) => string.Compare(x.Name, y.Name, StringComparison.CurrentCulture));
+ bool match = false;
+
+ // TODO: find a way to not do 1 by 1.
foreach (Node file in inputFiles.Children) {
- // Fixed names
- if (ImportStrategies.TryGetValue(file.Name, out IFileImportStrategy? strategy)) {
- strategy.Import(gameNode, file);
- } else {
- // Pattern names
- bool matched = false;
- foreach ((Regex pattern, IFileImportStrategy patternStrategy) in PatternStrategies) {
- if (pattern.IsMatch(file.Name)) {
- patternStrategy.Import(gameNode, file);
- matched = true;
- break;
- }
+ foreach (IFileImportStrategy strategy in Strategies) {
+ if (strategy.Matches(file.Name)) {
+ match = true;
+ strategy.Import(gameNode, file);
}
+ }
- if (!matched) {
- Console.WriteLine($"File not compatible: {file.Name}");
- }
+ if (!match) {
+ Console.WriteLine($"File not compatible: {file.Name}");
}
}