From 83f20d2d335fde90e2f7b5d12e7e556aa1131e57 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Wed, 9 Nov 2022 22:54:53 +0400 Subject: Refactoring --- tools_sources/CoolgirlCombiner/Config.cs | 268 +++++++++++++++++++++++++ tools_sources/CoolgirlCombiner/Program.cs | 315 ++++++------------------------ 2 files changed, 332 insertions(+), 251 deletions(-) create mode 100644 tools_sources/CoolgirlCombiner/Config.cs diff --git a/tools_sources/CoolgirlCombiner/Config.cs b/tools_sources/CoolgirlCombiner/Config.cs new file mode 100644 index 0000000..37638c2 --- /dev/null +++ b/tools_sources/CoolgirlCombiner/Config.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace com.clusterrr.Famicom.CoolGirl +{ + internal class Config + { + const string DEFAULT_MAPPERS_FILE = @"coolgirl-mappers.json"; + const string DEFAULT_FIXES_FILE = @"coolgirl-fixes.json"; + const string DEFAULT_SYMBOLS_FILE = @"coolgirl-symbols.json"; + public const string commandPrepare = "prepare"; + public const string commandCombine = "combine"; + public const string commandBuild = "build"; + + public enum CombinerCommand + { + Prepare, + Combine, + Build, + } + + public enum CombinerLanguage + { + English, + Russian + } + + public CombinerCommand Command { get; private set; } = CombinerCommand.Prepare; + public string MappersFile { get; private set; } + public string FixesFile { get; private set; } + public string SymbolsFile { get; private set; } + public string NesAsm { get; private set; } = "nesasm"; + public string NesAsmArgs { get; private set; } = ""; + public string SourcesDir { get; private set; } = "."; + public string? GamesFile { get; private set; } = null; + public string? AsmFile { get; private set; } = null; + public string OffsetsFile { get; private set; } = "offsets.json"; + public string? ReportFile { get; private set; } = null; + public string? LoaderFile { get; private set; } = null; + public string? UnifFile { get; private set; } = null; + public string? Nes20File { get; private set; } = null; + public string? BinFile { get; private set; } = null; + public CombinerLanguage Language { get; private set; } = CombinerLanguage.English; + public List BadSectors { get; private set; } = new(); + public bool NoSort { get; private set; } = false; + public uint MaxRomSizeMB { get; private set; } = 256; + public uint MaxChrRamSizeKB { get; private set; } = 256; + + private Config() + { + MappersFile = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory) ?? String.Empty, DEFAULT_MAPPERS_FILE); + if (!File.Exists(MappersFile) && !OperatingSystem.IsWindows()) + MappersFile = Path.Combine("/etc", DEFAULT_MAPPERS_FILE); + FixesFile = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory) ?? String.Empty, DEFAULT_FIXES_FILE); + if (!File.Exists(FixesFile) && !OperatingSystem.IsWindows()) + FixesFile = Path.Combine("/etc", DEFAULT_FIXES_FILE); + SymbolsFile + = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory) ?? String.Empty, DEFAULT_SYMBOLS_FILE); + if (!File.Exists(SymbolsFile) && !OperatingSystem.IsWindows()) + SymbolsFile = Path.Combine("/etc", DEFAULT_SYMBOLS_FILE); + } + + // TODO: Replace magic strings with constants + public static Config? Parse(string[] args) + { + Config config = new Config(); + + if (args.Length > 0) + { + string command = args[0].ToLower(); + switch (command) + { + case commandPrepare: + config.Command = CombinerCommand.Prepare; + break; + case commandCombine: + config.Command = CombinerCommand.Combine; + break; + case commandBuild: + config.Command = CombinerCommand.Build; + break; + default: + if (!string.IsNullOrEmpty(command)) + Console.WriteLine("Unknown command: " + command); + return null; + } + } + else return null; + for (int i = 1; i < args.Length; i++) + { + string param = args[i]; + while (param.StartsWith("-")) param = param.Substring(1); + string value = i < args.Length - 1 ? args[i + 1] : ""; + switch (param.ToLower()) + { + case "mappers": + config.MappersFile = value; + i++; + break; + case "fixes": + config.FixesFile = value; + i++; + break; + case "symbols": + config.SymbolsFile = value; + i++; + break; + case "games": + config.GamesFile = value; + i++; + break; + case "asm": + config.AsmFile = value; + i++; + break; + case "offsets": + config.OffsetsFile = value; + i++; + break; + case "report": + config.ReportFile = value; + i++; + break; + case "loader": + config.LoaderFile = value; + i++; + break; + case "unif": + config.UnifFile = value; + i++; + break; + case "nes20": + config.Nes20File = value; + i++; + break; + case "bin": + config.BinFile = value; + i++; + break; + case "nosort": + config.NoSort = true; + break; + case "maxromsize": + config.MaxRomSizeMB = uint.Parse(value); + i++; + break; + case "maxchrsize": + config.MaxChrRamSizeKB = uint.Parse(value); + i++; + break; + case "language": + switch (value.ToLower()) + { + case "eng": + config.Language = CombinerLanguage.English; + break; + case "rus": + config.Language = CombinerLanguage.Russian; + break; + default: + throw new InvalidDataException($"Invalid language: {value}"); + } + i++; + break; + case "badsectors": + foreach (var v in value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + config.BadSectors.Add(int.Parse(v)); + i++; + break; + case "nesasm": + config.NesAsm = value; + i++; + break; + case "nesasm-args": + case "nesasmargs": + config.NesAsmArgs = value; + i++; + break; + case "sources": + config.SourcesDir = value; + i++; + break; + default: + Console.WriteLine("Unknown parameter: " + param); + return null; + } + } + + if ((config.GamesFile == null) && ((config.Command == CombinerCommand.Prepare) || (config.Command == CombinerCommand.Build))) + { + Console.WriteLine("Missing required parameter: --games"); + return null; + } + if ((config.AsmFile == null) && (config.Command == CombinerCommand.Prepare)) + { + Console.WriteLine("Missing required parameter: --asm"); + return null; + } + if ((config.OffsetsFile == null) && ((config.Command == CombinerCommand.Prepare) || (config.Command == CombinerCommand.Combine))) + { + Console.WriteLine("Missing required parameter: --offsets"); + return null; + } + if ((config.LoaderFile == null) && (config.Command == CombinerCommand.Combine)) + { + Console.WriteLine("Missing required parameter: --loader"); + return null; + } + if ((config.UnifFile == null) && (config.Nes20File == null) && (config.BinFile == null) + && ((config.Command == CombinerCommand.Combine) || (config.Command == CombinerCommand.Build))) + { + Console.WriteLine("At least one parameter required: --unif, --nes20 or --bin"); + return null; + } + + if (string.IsNullOrEmpty(config.AsmFile)) + config.AsmFile = Path.Combine(config.SourcesDir, "games.asm"); + + return config; + } + + public static void PrintHelp() + { + var exename = Path.GetFileName(Process.GetCurrentProcess()?.MainModule?.FileName); + Console.WriteLine("--- Usage ---"); + Console.WriteLine("First step:"); + Console.WriteLine($" {exename} prepare --games --asm --offsets [--report ] [--nosort] [--maxromsize ] [--maxchrsize ] [--language ] [--badsectors ]"); + Console.WriteLine(" {0,-20}{1}", "--games", "- input plain text file with a list of ROM files"); + Console.WriteLine(" {0,-20}{1}", "--asm", "- output file for the loader"); + Console.WriteLine(" {0,-20}{1}", "--offsets", "- output file with offsets for every game"); + Console.WriteLine(" {0,-20}{1}", "--report", "- output report file (human readable)"); + Console.WriteLine(" {0,-20}{1}", "--nosort", "- disable automatic sort by name"); + Console.WriteLine(" {0,-20}{1}", "--maxromsize", "- maximum size for final file (in megabytes)"); + Console.WriteLine(" {0,-20}{1}", "--maxchrsize", "- maximum CHR RAM size (in kilobytes), default is 256"); + Console.WriteLine(" {0,-20}{1}", "--language", "- language for system messages: \"eng\" or \"rus\""); + Console.WriteLine(" {0,-20}{1}", "--badsectors", "- comma-separated list of bad sectors,"); + Console.WriteLine("Second step:"); + Console.WriteLine($" {exename} combine --loader --offsets [--unif ] [--nes20 multirom.nes] [--bin ]"); + Console.WriteLine(" {0,-20}{1}", "--loader", "- loader (compiled using the asm file generated by the first step)"); + Console.WriteLine(" {0,-20}{1}", "--offsets", "- input file with offsets for every game (generated by the first step)"); + Console.WriteLine(" {0,-20}{1}", "--unif", "- output UNIF file"); + Console.WriteLine(" {0,-20}{1}", "--nes20", "- output NES 2.0 file"); + Console.WriteLine(" {0,-20}{1}", "--bin", "- output raw binary file"); + Console.WriteLine("All at once:"); + Console.WriteLine($" {exename} build --games --asm [--nesasm ] [--nesasm-args ] [--sources ] [--report ] [--nosort] [--maxromsize ] [--maxchrsize ] [--language ] [--badsectors ] [--unif ] [--nes20 ] [--bin ]"); + Console.WriteLine(" {0,-20}{1}", "--games", "- input plain text file with list of ROM files"); + Console.WriteLine(" {0,-20}{1}", "--asm", "- output file for the loader"); + Console.WriteLine(" {0,-20}{1}", "--nesasm", "- path to the nesasm compiler executable"); + Console.WriteLine(" {0,-20}{1}", "--nesasm-args", "- additional command-line arguments for nesasm"); + Console.WriteLine(" {0,-20}{1}", "--sources", "- directory with loader source files, default is current directory"); + Console.WriteLine(" {0,-20}{1}", "--report", "- output report file (human readable)"); + Console.WriteLine(" {0,-20}{1}", "--nosort", "- disable automatic sort by name"); + Console.WriteLine(" {0,-20}{1}", "--maxromsize", "- maximum size for final file (in megabytes)"); + Console.WriteLine(" {0,-20}{1}", "--maxchrsize", "- maximum CHR RAM size (in kilobytes), default is 256"); + Console.WriteLine(" {0,-20}{1}", "--language", "- language for system messages: \"eng\" or \"rus\", default is \"eng\""); + Console.WriteLine(" {0,-20}{1}", "--badsectors", "- comma-separated list of bad sectors,"); + Console.WriteLine(" {0,-20}{1}", "--unif", "- output UNIF file"); + Console.WriteLine(" {0,-20}{1}", "--nes20", "- output NES 2.0 file"); + Console.WriteLine(" {0,-20}{1}", "--bin", "- output raw binary file"); + } + } +} diff --git a/tools_sources/CoolgirlCombiner/Program.cs b/tools_sources/CoolgirlCombiner/Program.cs index ac07d55..4ea7ce0 100644 --- a/tools_sources/CoolgirlCombiner/Program.cs +++ b/tools_sources/CoolgirlCombiner/Program.cs @@ -17,9 +17,6 @@ namespace com.clusterrr.Famicom.CoolGirl { public const string REPO_PATH = "https://github.com/ClusterM/coolgirl-multirom-builder"; public static DateTime BUILD_TIME = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(long.Parse(Properties.Resources.buildtime.Trim())); - const string DEFAULT_MAPPERS_FILE = @"coolgirl-mappers.json"; - const string DEFAULT_FIXES_FILE = @"coolgirl-fixes.json"; - const string DEFAULT_SYMBOLS_FILE = @"coolgirl-symbols.json"; static int Main(string[] args) { @@ -33,38 +30,14 @@ namespace com.clusterrr.Famicom.CoolGirl Console.WriteLine(" (c) Alexey 'Cluster' Avdyukhin / https://clusterrr.com / clusterrr@clusterrr.com"); Console.WriteLine(""); - bool needShowHelp = false; - - const string commandPrepare = "prepare"; - const string commandCombine = "combine"; - const string commandBuild = "build"; - - string? command = null; - string optionMappersFile = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory) ?? String.Empty, DEFAULT_MAPPERS_FILE); - if (!File.Exists(optionMappersFile) && !OperatingSystem.IsWindows()) - optionMappersFile = Path.Combine("/etc", DEFAULT_MAPPERS_FILE); - string optionFixesFile = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory) ?? String.Empty, DEFAULT_FIXES_FILE); - if (!File.Exists(optionFixesFile) && !OperatingSystem.IsWindows()) - optionFixesFile = Path.Combine("/etc", DEFAULT_FIXES_FILE); - string optionSymbolsFile = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory) ?? String.Empty, DEFAULT_SYMBOLS_FILE); - if (!File.Exists(optionSymbolsFile) && !OperatingSystem.IsWindows()) - optionSymbolsFile = Path.Combine("/etc", DEFAULT_SYMBOLS_FILE); - string optionNesAsm = "nesasm"; - string optionNesAsmArgs = ""; - string optionSourcesDir = "."; - string? optionGamesFile = null; - string optionAsmFile = "games.asm"; - string optionOffsetsFile = "offsets.json"; - string? optionReportFile = null; - string? optionLoaderFile = null; - string? optionUnifFile = null; - string? optionNes20File = null; - string? optionBinFile = null; - string optionLanguage = "eng"; - var badSectors = new List(); - bool optionNoSort = false; - uint optionMaxRomSize = 256; - uint optionMaxChrRamSize = 256; + var config = Config.Parse(args); + + if (config == null) + { + Config.PrintHelp(); + return 1; + } + var jsonOptions = new JsonSerializerOptions() { WriteIndented = true, @@ -72,181 +45,13 @@ namespace com.clusterrr.Famicom.CoolGirl Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } }; - if (args.Length > 0) command = args[0].ToLower(); - if ((command != commandPrepare) && (command != commandCombine) && (command != commandBuild)) - { - if (!string.IsNullOrEmpty(command)) - Console.WriteLine("Unknown command: " + command); - needShowHelp = true; - } - for (int i = 1; i < args.Length; i++) - { - string param = args[i]; - while (param.StartsWith("-")) param = param.Substring(1); - string value = i < args.Length - 1 ? args[i + 1] : ""; - switch (param.ToLower()) - { - case "mappers": - optionMappersFile = value; - i++; - break; - case "fixes": - optionFixesFile = value; - i++; - break; - case "symbols": - optionSymbolsFile = value; - i++; - break; - case "games": - optionGamesFile = value; - i++; - break; - case "asm": - optionAsmFile = value; - i++; - break; - case "offsets": - optionOffsetsFile = value; - i++; - break; - case "report": - optionReportFile = value; - i++; - break; - case "loader": - optionLoaderFile = value; - i++; - break; - case "unif": - optionUnifFile = value; - i++; - break; - case "nes20": - optionNes20File = value; - i++; - break; - case "bin": - optionBinFile = value; - i++; - break; - case "nosort": - optionNoSort = true; - break; - case "maxromsize": - optionMaxRomSize = uint.Parse(value); - i++; - break; - case "maxchrsize": - optionMaxChrRamSize = uint.Parse(value); - i++; - break; - case "language": - switch (value.ToLower()) - { - case "eng": - case "rus": - optionLanguage = value.ToLower(); - break; - default: - throw new Exception($"Invalid language: {value}"); - } - i++; - break; - case "badsectors": - foreach (var v in value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) - badSectors.Add(int.Parse(v)); - i++; - break; - case "nesasm": - optionNesAsm = value; - i++; - break; - case "nesasm-args": - case "nesasmargs": - optionNesAsmArgs = value; - i++; - break; - case "sources": - optionSourcesDir = value; - i++; - break; - default: - Console.WriteLine("Unknown parameter: " + param); - needShowHelp = true; - break; - } - } - - if ((optionGamesFile == null) && ((command == commandPrepare) || (command == commandBuild))) - { - Console.WriteLine("Missing required parameter: --games"); - needShowHelp = true; - } - if ((optionOffsetsFile == null) && (command == commandPrepare)) - { - Console.WriteLine("Missing required parameter: --offsets"); - needShowHelp = true; - } - if ((optionLoaderFile == null) && (command == commandCombine)) - { - Console.WriteLine("Missing required parameter: --loader"); - needShowHelp = true; - } - if ((optionUnifFile == null) && (optionNes20File == null) && (optionBinFile == null) && ((command == commandCombine) || (command == commandBuild))) - { - Console.WriteLine("At least one parameter required: --unif, --nes20 or --bin"); - needShowHelp = true; - } - - if (needShowHelp) - { - var exename = Path.GetFileName(Process.GetCurrentProcess()?.MainModule?.FileName); - Console.WriteLine("--- Usage ---"); - Console.WriteLine("First step:"); - Console.WriteLine($" {exename} prepare --games --asm --offsets [--report ] [--nosort] [--maxromsize ] [--maxchrsize ] [--language ] [--badsectors ]"); - Console.WriteLine(" {0,-20}{1}", "--games", "- input plain text file with a list of ROM files"); - Console.WriteLine(" {0,-20}{1}", "--asm", "- output file for the loader"); - Console.WriteLine(" {0,-20}{1}", "--offsets", "- output file with offsets for every game"); - Console.WriteLine(" {0,-20}{1}", "--report", "- output report file (human readable)"); - Console.WriteLine(" {0,-20}{1}", "--nosort", "- disable automatic sort by name"); - Console.WriteLine(" {0,-20}{1}", "--maxromsize", "- maximum size for final file (in megabytes)"); - Console.WriteLine(" {0,-20}{1}", "--maxchrsize", "- maximum CHR RAM size (in kilobytes), default is 256"); - Console.WriteLine(" {0,-20}{1}", "--language", "- language for system messages: \"eng\" or \"rus\""); - Console.WriteLine(" {0,-20}{1}", "--badsectors", "- comma-separated list of bad sectors,"); - Console.WriteLine("Second step:"); - Console.WriteLine($" {exename} combine --loader --offsets [--unif ] [--nes20 multirom.nes] [--bin ]"); - Console.WriteLine(" {0,-20}{1}", "--loader", "- loader (compiled using the asm file generated by the first step)"); - Console.WriteLine(" {0,-20}{1}", "--offsets", "- input file with offsets for every game (generated by the first step)"); - Console.WriteLine(" {0,-20}{1}", "--unif", "- output UNIF file"); - Console.WriteLine(" {0,-20}{1}", "--nes20", "- output NES 2.0 file"); - Console.WriteLine(" {0,-20}{1}", "--bin", "- output raw binary file"); - Console.WriteLine("All at once:"); - Console.WriteLine($" {exename} build --games --asm [--nesasm ] [--nesasm-args ] [--sources ] [--report ] [--nosort] [--maxromsize ] [--maxchrsize ] [--language ] [--badsectors ] [--unif ] [--nes20 ] [--bin ]"); - Console.WriteLine(" {0,-20}{1}", "--games", "- input plain text file with list of ROM files"); - Console.WriteLine(" {0,-20}{1}", "--asm", "- output file for the loader"); - Console.WriteLine(" {0,-20}{1}", "--nesasm", "- path to the nesasm compiler executable"); - Console.WriteLine(" {0,-20}{1}", "--nesasm-args", "- additional command-line arguments for nesasm"); - Console.WriteLine(" {0,-20}{1}", "--sources", "- directory with loader source files, default is current directory"); - Console.WriteLine(" {0,-20}{1}", "--report", "- output report file (human readable)"); - Console.WriteLine(" {0,-20}{1}", "--nosort", "- disable automatic sort by name"); - Console.WriteLine(" {0,-20}{1}", "--maxromsize", "- maximum size for final file (in megabytes)"); - Console.WriteLine(" {0,-20}{1}", "--maxchrsize", "- maximum CHR RAM size (in kilobytes), default is 256"); - Console.WriteLine(" {0,-20}{1}", "--language", "- language for system messages: \"eng\" or \"rus\", default is \"eng\""); - Console.WriteLine(" {0,-20}{1}", "--badsectors", "- comma-separated list of bad sectors,"); - Console.WriteLine(" {0,-20}{1}", "--unif", "- output UNIF file"); - Console.WriteLine(" {0,-20}{1}", "--nes20", "- output NES 2.0 file"); - Console.WriteLine(" {0,-20}{1}", "--bin", "- output raw binary file"); - return 1; - } - // Reserved for loader byte?[] result = Enumerable.Repeat(byte.MaxValue, 128 * 1024).Select(b => (byte?)b).ToArray(); - if ((command == commandPrepare) || (command == commandBuild)) + if ((config.Command == Config.CombinerCommand.Prepare) || (config.Command == Config.CombinerCommand.Build)) { // Loading mappers file - var mappersJson = File.ReadAllText(optionMappersFile); + var mappersJson = File.ReadAllText(config.MappersFile); var mappers = JsonSerializer.Deserialize>(mappersJson, jsonOptions); if (mappers == null) throw new InvalidDataException("Can't read mappers file"); // Add padding zeros @@ -265,9 +70,9 @@ namespace com.clusterrr.Famicom.CoolGirl // Loading fixes file Dictionary? fixes; - if (File.Exists(optionFixesFile)) + if (File.Exists(config.FixesFile)) { - var fixesJson = File.ReadAllText(optionFixesFile); + var fixesJson = File.ReadAllText(config.FixesFile); var fixesStr = JsonSerializer.Deserialize>(fixesJson, jsonOptions); if (fixesStr == null) throw new InvalidDataException("Can't read fixes file"); // Convert string CRC32 to uint @@ -285,18 +90,18 @@ namespace com.clusterrr.Famicom.CoolGirl } // Loading symbols table - var symbolsJson = File.ReadAllText(optionSymbolsFile); + var symbolsJson = File.ReadAllText(config.SymbolsFile); var symbols = JsonSerializer.Deserialize>(symbolsJson, jsonOptions); if (symbols == null) throw new InvalidDataException("Can't load symbols file"); // Loading games list - var lines = File.ReadAllLines(optionGamesFile!); + var lines = File.ReadAllLines(config.GamesFile!); var regs = new Dictionary>(); var games = new List(); var report = new List(); // Bad sectors :( - foreach (var bad in badSectors) + foreach (var bad in config.BadSectors) { for (int a = bad * 4 * 0x8000; a < bad * 4 * 0x8000 + 128 * 1024; a++) { @@ -306,6 +111,7 @@ namespace com.clusterrr.Famicom.CoolGirl } } + bool nosort = config.NoSort; // Building list of ROMs foreach (var line in lines) { @@ -315,7 +121,7 @@ namespace com.clusterrr.Famicom.CoolGirl if (line.Trim().StartsWith(";")) continue; if (line.Trim().ToUpper() == "!NOSORT") { - optionNoSort = true; + nosort = true; continue; } var cols = line.Split(new char[] { '|' }, 2, StringSplitOptions.RemoveEmptyEntries); @@ -344,7 +150,7 @@ namespace com.clusterrr.Famicom.CoolGirl // Sorting IEnumerable sortedGames; - if (optionNoSort) + if (nosort) { sortedGames = Enumerable.Concat( @@ -383,7 +189,7 @@ namespace com.clusterrr.Famicom.CoolGirl { Console.Write($"Fitting PRG of {Path.GetFileName(game.FileName)} ({game.PRG.Length / 1024}KB)... "); bool fitted = false; - for (int pos = 0; pos < optionMaxRomSize * 1024 * 1024; pos += game.PRG.Length) + for (int pos = 0; pos < config.MaxRomSizeMB * 1024 * 1024; pos += game.PRG.Length) { if (WillFit(result, pos, game.PRG)) { @@ -409,7 +215,7 @@ namespace com.clusterrr.Famicom.CoolGirl { Console.Write($"Fitting CHR of {Path.GetFileName(game.FileName)} ({game.CHR.Length / 1024}KB)... "); bool fitted = false; - for (int pos = 0; pos < optionMaxRomSize * 1024 * 1024; pos += 0x2000) + for (int pos = 0; pos < config.MaxRomSizeMB * 1024 * 1024; pos += 0x2000) { if (WillFit(result, pos, game.CHR)) { @@ -478,8 +284,8 @@ namespace com.clusterrr.Famicom.CoolGirl Console.WriteLine($"Battery-backed games: {saveId}"); // Write report file if need - if (optionReportFile != null) - File.WriteAllLines(optionReportFile, report.ToArray()); + if (config.ReportFile != null) + File.WriteAllLines(config.ReportFile, report.ToArray()); if (games.Count - hiddenCount == 0) throw new InvalidOperationException("Games list is empty"); @@ -503,7 +309,7 @@ namespace com.clusterrr.Famicom.CoolGirl // Error collection var problems = new List(); - if (usedSpace > optionMaxRomSize * 1024 * 1024) + if (usedSpace > config.MaxRomSizeMB * 1024 * 1024) problems.Add(new OutOfMemoryException($"ROM is too big: {Math.Round(usedSpace / 1024.0 / 1024.0, 3)}MB")); if (games.Count > 256 * 6) problems.Add(new InvalidDataException($"Too many ROMs: {games.Count} (maximum {256 * 6})")); @@ -523,14 +329,14 @@ namespace com.clusterrr.Famicom.CoolGirl } } else mapperInfo = new Mapper(); - if (game.CHR.Length > optionMaxChrRamSize * 1024) + if (game.CHR.Length > config.MaxChrRamSizeKB * 1024) { problems.Add(new Exception($"CHR size is too big in \"{Path.GetFileName(game.FileName)}\"")); continue; } - if ((game.Mirroring == MirroringType.FourScreenVram) && (game.CHR.Length > optionMaxChrRamSize * 1024 - 0x1000)) + if ((game.Mirroring == MirroringType.FourScreenVram) && (game.CHR.Length > config.MaxChrRamSizeKB * 1024 - 0x1000)) { - problems.Add(new Exception($"Four-screen mode and such big CHR ({optionMaxChrRamSize}KB) is not supported for \"{Path.GetFileName(game.FileName)}\"")); + problems.Add(new Exception($"Four-screen mode and such big CHR ({config.MaxChrRamSizeKB}KB) is not supported for \"{Path.GetFileName(game.FileName)}\"")); continue; } if (game.Trained) @@ -585,7 +391,7 @@ namespace com.clusterrr.Famicom.CoolGirl // if CHR RAM banking is supported by mapper // set the maximum size if (mapperInfo.ChrRamBanking) - chrBankingSize = (int)optionMaxChrRamSize * 1024; + chrBankingSize = (int)config.MaxChrRamSizeKB * 1024; else // else banking is disabled chrBankingSize = 0x2000; } @@ -700,6 +506,7 @@ namespace com.clusterrr.Famicom.CoolGirl } // Some strings + // TODO: replace magic strings with constants asmResult.AppendLine(); asmResult.AppendLine(); asmResult.AppendLine("; Some strings"); @@ -707,7 +514,7 @@ namespace com.clusterrr.Famicom.CoolGirl asmResult.AppendLine(" .org $C800"); asmResult.AppendLine(); asmResult.AppendLine("string_file:"); - asmResult.Append(BytesToAsm(StringToTiles("FILE: " + Path.GetFileName(optionGamesFile), symbols))); + asmResult.Append(BytesToAsm(StringToTiles("FILE: " + Path.GetFileName(config.GamesFile), symbols))); asmResult.AppendLine("string_build_date:"); asmResult.Append(BytesToAsm(StringToTiles("BUILD DATE: " + DateTime.Now.ToString("yyyy-MM-dd"), symbols))); asmResult.AppendLine("string_build_time:"); @@ -754,16 +561,22 @@ namespace com.clusterrr.Famicom.CoolGirl asmResult.Append(BytesToAsm(StringToTiles("NOT AVAILABLE", symbols))); asmResult.AppendLine("string_commit:"); asmResult.Append(BytesToAsm(StringToTiles("COMMIT: " + Properties.Resources.gitCommit, symbols))); - asmResult.AppendLine("string_saving:"); - if (optionLanguage == "rus") - asmResult.Append(BytesToAsm(StringToTiles(" СОХРАНЯЕМСЯ... НЕ ВЫКЛЮЧАЙ! ", symbols))); - else - asmResult.Append(BytesToAsm(StringToTiles(" SAVING... DON'T TURN OFF! ", symbols))); - asmResult.AppendLine("string_incompatible_console:"); - if (optionLanguage == "rus") - asmResult.Append(BytesToAsm(StringToTiles(" ИЗВИНИТЕ, ДАННАЯ ИГРА НЕСОВМЕСТИМА С ЭТОЙ КОНСОЛЬЮ НАЖМИТЕ ЛЮБУЮ КНОПКУ ", symbols))); - else - asmResult.Append(BytesToAsm(StringToTiles(" SORRY, THIS GAME IS NOT COMPATIBLE WITH THIS CONSOLE PRESS ANY BUTTON ", symbols))); + switch (config.Language) + { + case Config.CombinerLanguage.English: + asmResult.AppendLine("string_saving:"); + asmResult.Append(BytesToAsm(StringToTiles(" SAVING... DON'T TURN OFF! ", symbols))); + asmResult.AppendLine("string_incompatible_console:"); + asmResult.Append(BytesToAsm(StringToTiles(" SORRY, THIS GAME IS NOT COMPATIBLE WITH THIS CONSOLE PRESS ANY BUTTON ", symbols))); + break; + case Config.CombinerLanguage.Russian: + asmResult.AppendLine("string_saving:"); + asmResult.Append(BytesToAsm(StringToTiles(" СОХРАНЯЕМСЯ... НЕ ВЫКЛЮЧАЙ! ", symbols))); + asmResult.AppendLine("string_incompatible_console:"); + asmResult.Append(BytesToAsm(StringToTiles(" ИЗВИНИТЕ, ДАННАЯ ИГРА НЕСОВМЕСТИМА С ЭТОЙ КОНСОЛЬЮ НАЖМИТЕ ЛЮБУЮ КНОПКУ ", symbols))); + break; + } + asmResult.AppendLine("string_prg_ram_test:"); asmResult.Append(BytesToAsm(StringToTiles("PRG RAM TEST:", symbols))); asmResult.AppendLine("string_chr_ram_test:"); @@ -777,27 +590,27 @@ namespace com.clusterrr.Famicom.CoolGirl asmResult.AppendLine("string_error:"); asmResult.Append(BytesToAsm(StringToTiles("ERROR", symbols))); - File.WriteAllText(optionAsmFile, asmResult.ToString()); + File.WriteAllText(config.AsmFile!, asmResult.ToString()); - if (command == commandPrepare) + if (config.Command == Config.CombinerCommand.Prepare) { var offsets = new Offsets(); offsets.Size = romSize; offsets.RomCount = gameCount; - offsets.GamesFile = Path.GetFileName(optionGamesFile); + offsets.GamesFile = Path.GetFileName(config.GamesFile); offsets.Games = sortedGames.Where(g => !g.IsSeparator).ToArray(); - File.WriteAllText(optionOffsetsFile!, JsonSerializer.Serialize(offsets, jsonOptions)); + File.WriteAllText(config.OffsetsFile!, JsonSerializer.Serialize(offsets, jsonOptions)); } - if (command == commandBuild) + if (config.Command == Config.CombinerCommand.Build) { Console.Write("Compiling using nesasm... "); Array.Resize(ref result, (int)romSize); var process = new Process(); var cp866 = CodePagesEncodingProvider.Instance.GetEncoding(866) ?? Encoding.ASCII; - process.StartInfo.FileName = optionNesAsm; - process.StartInfo.Arguments = $"\"menu.asm\" -r -o - -C \"GAMES_DB={optionAsmFile}\" " + optionNesAsmArgs; - process.StartInfo.WorkingDirectory = optionSourcesDir; + process.StartInfo.FileName = config.NesAsm; + process.StartInfo.Arguments = $"\"menu.asm\" -r -o - -C \"GAMES_DB={config.AsmFile}\" " + config.NesAsmArgs; + process.StartInfo.WorkingDirectory = config.SourcesDir; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; @@ -837,9 +650,9 @@ namespace com.clusterrr.Famicom.CoolGirl Console.WriteLine("OK"); } } - if (command == commandCombine) // Combine + if (config.Command == Config.CombinerCommand.Combine) // Combine { - var offsetsJson = File.ReadAllText(optionOffsetsFile!); + var offsetsJson = File.ReadAllText(config.OffsetsFile); var offsets = JsonSerializer.Deserialize(offsetsJson, jsonOptions); if (offsets == null) throw new InvalidDataException("Can't load offsets file"); result = new byte?[offsets.Size]; @@ -848,7 +661,7 @@ namespace com.clusterrr.Famicom.CoolGirl result[i] = 0xFF; Console.Write("Loading loader... "); - var loaderFile = new NesFile(optionLoaderFile!); + var loaderFile = new NesFile(config.LoaderFile!); var loader = loaderFile.PRG.ToArray(); for (int i = 0; i < loader.Length; i++) result[i] = loader[i]; @@ -890,9 +703,9 @@ namespace com.clusterrr.Famicom.CoolGirl } } - if ((command == commandCombine) || (command == commandBuild)) // Combine or build + if ((config.Command == Config.CombinerCommand.Combine) || (config.Command == Config.CombinerCommand.Build)) // Combine or build { - if (!string.IsNullOrEmpty(optionUnifFile)) + if (!string.IsNullOrEmpty(config.UnifFile)) { Console.Write("Saving UNIF file... "); var u = new UnifFile(); @@ -901,10 +714,10 @@ namespace com.clusterrr.Famicom.CoolGirl u.Mirroring = MirroringType.MapperControlled; u.PRG0 = result.Select(b => b ?? byte.MaxValue).ToArray(); u.Battery = true; - u.Save(optionUnifFile); + u.Save(config.UnifFile); Console.WriteLine("OK"); } - if (!string.IsNullOrEmpty(optionNes20File)) + if (!string.IsNullOrEmpty(config.Nes20File)) { Console.Write("Saving NES file... "); var nes = new NesFile(); @@ -913,15 +726,15 @@ namespace com.clusterrr.Famicom.CoolGirl nes.CHR = Array.Empty(); nes.Mapper = 342; nes.PrgNvRamSize = 32 * 1024; - nes.ChrRamSize = optionMaxChrRamSize * 1024; + nes.ChrRamSize = config.MaxChrRamSizeKB * 1024; nes.Battery = true; - nes.Save(optionNes20File); + nes.Save(config.Nes20File); Console.WriteLine("OK"); } - if (!string.IsNullOrEmpty(optionBinFile)) + if (!string.IsNullOrEmpty(config.BinFile)) { Console.Write("Saving BIN file... "); - File.WriteAllBytes(optionBinFile, result.Select(b => b ?? byte.MaxValue).ToArray()); + File.WriteAllBytes(config.BinFile, result.Select(b => b ?? byte.MaxValue).ToArray()); Console.WriteLine("OK"); } } -- cgit v1.2.3