public void LoadingConfigShouldFailIfParametersAreMissing() { IConfigurationProcessor processor = new ConfigurationProcessor(); var content = File.ReadAllText("Files/invalid.json"); new Action(() => processor.ValidateAndLoad(content)).Should().Throw <ArgumentException>(); }
public async Task LoadingConfigWithCustomStoragePathShouldUseIt() { IConfigurationProcessor processor = new ConfigurationProcessor(); var content = File.ReadAllText("Files/config+custompath.json"); var cfg = processor.ValidateAndLoad(content); var cert = cfg.Certificates[0]; cert.HostNames.Should().BeEquivalentTo(new[] { "example.com", "www.example.com" }); cert.ChallengeResponder.Should().NotBeNull(); // fake grant MSI access var factory = new Mock <IStorageFactory>(); var storage = new Mock <IStorageProvider>(); storage.Setup(x => x.ExistsAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(true)); factory.Setup(x => x.FromMsiAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(storage.Object)); var parser = new RenewalOptionParser( new Mock <IAzureHelper>().Object, new Mock <IKeyVaultClient>().Object, factory.Object, new Mock <IAzureAppServiceClient>().Object, new Mock <IAzureCdnClient>().Object, new Mock <ILoggerFactory>().Object); var responder = await parser.ParseChallengeResponderAsync(cert, CancellationToken.None); var ctx = new Mock <IChallengeContext>(); // Certes .Http() extension method internall filters for this type ctx.SetupGet(x => x.Type) .Returns("http-01"); ctx.SetupGet(x => x.Token) .Returns("fileNAME"); ctx.SetupGet(x => x.KeyAuthz) .Returns("$content"); var auth = new Mock <IAuthorizationContext>(); auth.Setup(x => x.Challenges()) .Returns(Task.FromResult(new[] { ctx.Object }.AsEnumerable())); var order = new Mock <IOrderContext>(); order.Setup(x => x.Authorizations()) .Returns(Task.FromResult(new[] { auth.Object }.AsEnumerable())); _ = await responder.InitiateChallengesAsync(order.Object, CancellationToken.None); const string pathPrefix = "not/well-known/"; storage.Verify(x => x.SetAsync(pathPrefix + "fileNAME", "$content", It.IsAny <CancellationToken>()), Times.Once); }
private static async Task CheckDomainsForValidCertificateAsync(ILogger log, CancellationToken cancellationToken, ExecutionContext executionContext) { // internal storage (used for letsencrypt account metadata) IStorageProvider storageProvider = new AzureBlobStorageProvider(Environment.GetEnvironmentVariable("AzureWebJobsStorage"), "letsencrypt"); IConfigurationProcessor processor = new ConfigurationProcessor(); var configurations = await AutoRenewal.LoadConfigFilesAsync(storageProvider, processor, log, cancellationToken, executionContext); IAuthenticationService authenticationService = new AuthenticationService(storageProvider); var az = new AzureHelper(); var tokenProvider = new AzureServiceTokenProvider(); var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback)); var storageFactory = new StorageFactory(az); var renewalOptionsParser = new RenewalOptionParser(az, keyVaultClient, storageFactory, log); var certificateBuilder = new CertificateBuilder(); IRenewalService renewalService = new RenewalService(authenticationService, renewalOptionsParser, certificateBuilder, log); var errors = new List <Exception>(); var httpClient = new HttpClient(); foreach ((var name, var config) in configurations) { using (log.BeginScope($"Checking certificates from {name}")) { foreach (var cert in config.Certificates) { var hostNames = string.Join(";", cert.HostNames); try { // check each domain to verify HTTPS certificate is valid var request = WebRequest.CreateHttp($"https://{cert.HostNames.First()}"); request.ServerCertificateValidationCallback += ValidateTestServerCertificate; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { } } catch (Exception e) { log.LogError(e, $"Certificate check failed for: {hostNames}!"); errors.Add(e); continue; } log.LogInformation($"Certificate for {hostNames} looks valid"); } } } if (!configurations.Any()) { log.LogWarning("No configurations where processed, refere to the sample on how to set up configs!"); } if (errors.Any()) { throw new AggregateException("Failed to process all certificates", errors); } }
public void LoadingAppServiceConfig() { IConfigurationProcessor processor = new ConfigurationProcessor(); var content = File.ReadAllText("Files/appservice.json"); var cfg = processor.ValidateAndLoad(content); cfg.Acme.Email.Should().Be("*****@*****.**"); cfg.Acme.Staging.Should().BeFalse(); cfg.Acme.RenewXDaysBeforeExpiry.Should().Be(30); cfg.Certificates.Should().HaveCount(1); var cert = cfg.Certificates[0]; cert.HostNames.Should().BeEquivalentTo(new[] { "example.com", "www.example.com" }); cert.CertificateStore.Should().BeNull(); cert.ChallengeResponder.Should().BeNull(); cert.TargetResource.Type.Should().Be("appService"); cert.TargetResource.Name.Should().Be("example"); }
static int Main(string[] args) { Dictionary <string, List <string> > argsDictionary; if (args.Length == 1 && File.Exists(args[0]) && Path.GetExtension(args[0]) == ".mmr") { argsDictionary = new Dictionary <string, List <string> > { { "-inputpatch", args.ToList() } }; } else { argsDictionary = DictionaryHelper.FromProgramArguments(args); } if (argsDictionary.ContainsKey("-help")) { Console.WriteLine("All arguments are optional."); var helpTexts = new Dictionary <string, string> { { "-help", "See this help text." }, { "-settings <path>", "Path to a settings JSON file. Only the GameplaySettings will be loaded. Other settings will be loaded from your default settings.json file." }, { "-outputpatch", "Output a .mmr patch file." }, { "-inputpatch <path>", "Path to a .mmr patch file to apply." }, { "-spoiler", "Output a .txt spoiler log." }, { "-html", "Output a .html item tracker." }, { "-rom", "Output a .z64 ROM file." }, { "-seed", "Set the seed for the randomizer." }, { "-output <path>", "Path to output the output ROM. Other outputs will be based on the filename in this path. If omitted, will output to \"output/{timestamp}.z64\"" }, { "-input <path>", "Path to the input Majora's Mask (U) ROM. If omitted, will try to use \"input.z64\"." }, { "-save", "Save the settings to the default settings.json file." }, }; foreach (var kvp in helpTexts) { Console.WriteLine("{0, -17} {1}", kvp.Key, kvp.Value); } Console.WriteLine("settings.json details:"); Console.WriteLine(GetSettingPath(cfg => cfg.GameplaySettings) + ":"); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.LogicMode)); Console.WriteLine(GetArrayValueDescription(nameof(GameplaySettings.ItemCategoriesRandomized), Enum.GetValues <ItemCategory>().Where(c => c > 0).Select(c => c.ToString()))); Console.WriteLine(GetArrayValueDescription(nameof(GameplaySettings.LocationCategoriesRandomized), Enum.GetValues <LocationCategory>().Where(c => c > 0).Select(c => c.ToString()))); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.DamageMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.DamageEffect)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.MovementMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.FloorType)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.ClockSpeed)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.BlastMaskCooldown)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.GossipHintStyle)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.SmallKeyMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.BossKeyMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.StrayFairyMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.PriceMode)); Console.WriteLine(GetSettingDescription(nameof(GameplaySettings.EnabledTricks), "Array of trick IDs.")); Console.WriteLine(GetSettingPath(cfg => cfg.GameplaySettings.ShortenCutsceneSettings) + ":"); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.ShortenCutsceneSettings.General)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.ShortenCutsceneSettings.BossIntros)); Console.WriteLine(GetSettingPath(cfg => cfg.CosmeticSettings) + ":"); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.CosmeticSettings.TatlColorSchema)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.CosmeticSettings.Music)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.CosmeticSettings.DisableCombatMusic)); Console.WriteLine(GetArrayValueDescription(nameof(CosmeticSettings.Instruments), Enum.GetNames <Instrument>())); Console.WriteLine(GetArrayValueDescription(nameof(CosmeticSettings.HeartsSelection), ColorSelectionManager.Hearts.GetItems().Select(csi => csi.Name))); Console.WriteLine(GetArrayValueDescription(nameof(CosmeticSettings.MagicSelection), ColorSelectionManager.MagicMeter.GetItems().Select(csi => csi.Name))); Console.WriteLine(GetSettingPath(cfg => cfg.CosmeticSettings.DPad.Pad) + ":"); Console.WriteLine(GetEnumArraySettingDescription(cfg => cfg.CosmeticSettings.DPad.Pad.Values) + " Array length of 4."); return(0); } var configuration = LoadSettings(); if (configuration == null) { Console.WriteLine("Default settings file not found. Generating..."); configuration = new Configuration { CosmeticSettings = new CosmeticSettings(), GameplaySettings = new GameplaySettings { ShortenCutsceneSettings = new ShortenCutsceneSettings(), }, OutputSettings = new OutputSettings() { InputROMFilename = "input.z64", }, }; SaveSettings(configuration); Console.WriteLine($"Generated {Path.ChangeExtension(DEFAULT_SETTINGS_FILENAME, SETTINGS_EXTENSION)}. Edit it to set your settings."); } var settingsPath = argsDictionary.GetValueOrDefault("-settings")?.FirstOrDefault(); if (settingsPath != null) { var loadedConfiguration = LoadSettings(settingsPath); if (loadedConfiguration == null) { Console.WriteLine($"File not found \"{settingsPath}\"."); return(-1); } if (loadedConfiguration.GameplaySettings == null) { Console.WriteLine($"Error loading GameplaySettings from \"{settingsPath}\"."); return(-1); } configuration.GameplaySettings = loadedConfiguration.GameplaySettings; Console.WriteLine($"Loaded GameplaySettings from \"{settingsPath}\"."); } if (configuration.GameplaySettings.ItemCategoriesRandomized != null || configuration.GameplaySettings.LocationCategoriesRandomized != null) { var items = new List <Item>(); if (configuration.GameplaySettings.ItemCategoriesRandomized != null) { items.AddRange(ItemUtils.ItemsByItemCategory().Where(kvp => configuration.GameplaySettings.ItemCategoriesRandomized.Contains(kvp.Key)).SelectMany(kvp => kvp.Value)); configuration.GameplaySettings.ItemCategoriesRandomized = null; } if (configuration.GameplaySettings.LocationCategoriesRandomized != null) { items.AddRange(ItemUtils.ItemsByLocationCategory().Where(kvp => configuration.GameplaySettings.LocationCategoriesRandomized.Contains(kvp.Key)).SelectMany(kvp => kvp.Value)); configuration.GameplaySettings.LocationCategoriesRandomized = null; } configuration.GameplaySettings.CustomItemList.Clear(); foreach (var item in items) { configuration.GameplaySettings.CustomItemList.Add(item); } } else { configuration.GameplaySettings.CustomItemList = ConvertItemString(ItemUtils.AllLocations().ToList(), configuration.GameplaySettings.CustomItemListString).ToHashSet(); } configuration.GameplaySettings.CustomStartingItemList = ConvertItemString(ItemUtils.StartingItems().Where(item => !item.Name().Contains("Heart")).ToList(), configuration.GameplaySettings.CustomStartingItemListString); configuration.GameplaySettings.CustomJunkLocations = ConvertItemString(ItemUtils.AllLocations().ToList(), configuration.GameplaySettings.CustomJunkLocationsString); configuration.OutputSettings.InputPatchFilename = argsDictionary.GetValueOrDefault("-inputpatch")?.SingleOrDefault(); configuration.OutputSettings.GeneratePatch |= argsDictionary.ContainsKey("-outputpatch"); configuration.OutputSettings.GenerateSpoilerLog |= argsDictionary.ContainsKey("-spoiler"); configuration.OutputSettings.GenerateHTMLLog |= argsDictionary.ContainsKey("-html"); configuration.OutputSettings.GenerateROM |= argsDictionary.ContainsKey("-rom"); int seed; if (argsDictionary.ContainsKey("-seed")) { seed = int.Parse(argsDictionary["-seed"][0]); } else { seed = new Random().Next(); } var outputArg = argsDictionary.GetValueOrDefault("-output"); if (outputArg != null) { if (outputArg.Count > 1) { throw new ArgumentException("Invalid argument.", "-output"); } configuration.OutputSettings.OutputROMFilename = outputArg.SingleOrDefault(); } else if (!string.IsNullOrWhiteSpace(configuration.OutputSettings.InputPatchFilename)) { configuration.OutputSettings.OutputROMFilename = Path.ChangeExtension(configuration.OutputSettings.InputPatchFilename, "z64"); } configuration.OutputSettings.OutputROMFilename ??= "output/"; if (!Path.IsPathRooted(configuration.OutputSettings.OutputROMFilename)) { configuration.OutputSettings.OutputROMFilename = Path.Combine(Directory.GetCurrentDirectory(), configuration.OutputSettings.OutputROMFilename); } var directory = Path.GetDirectoryName(configuration.OutputSettings.OutputROMFilename); var filename = Path.GetFileName(configuration.OutputSettings.OutputROMFilename); if (!Directory.Exists(directory)) { Console.WriteLine($"Directory not found '{directory}'"); return(-1); } if (string.IsNullOrWhiteSpace(filename)) { filename = FileUtils.MakeFilenameValid($"MMR-{typeof(Randomizer.Randomizer).Assembly.GetName().Version}-{DateTime.UtcNow:o}") + ".z64"; } else if (Path.GetExtension(filename) != ".z64") { filename = Path.ChangeExtension(filename, "z64"); } configuration.OutputSettings.OutputROMFilename = Path.Combine(directory, filename); var inputArg = argsDictionary.GetValueOrDefault("-input"); if (inputArg != null) { if (inputArg.Count > 1) { throw new ArgumentException("Invalid argument.", "-input"); } configuration.OutputSettings.InputROMFilename = inputArg.SingleOrDefault(); } configuration.OutputSettings.InputROMFilename ??= "input.z64"; if (argsDictionary.ContainsKey("-save")) { SaveSettings(configuration); } var validationResult = configuration.GameplaySettings.Validate() ?? configuration.OutputSettings.Validate(); if (validationResult != null) { Console.WriteLine(validationResult); return(-1); } try { string result; using (var progressBar = new ProgressBar()) { //var progressReporter = new TextWriterProgressReporter(Console.Out); var progressReporter = new ProgressBarProgressReporter(progressBar); result = ConfigurationProcessor.Process(configuration, seed, progressReporter); } if (result != null) { Console.Error.WriteLine(result); } else { Console.WriteLine("Generation complete!"); } return(result == null ? 0 : -1); } catch (Exception e) { Console.Error.Write(e.Message); Console.Error.Write(e.StackTrace); return(-1); } }
public int Invoke(string[] args) { try { HelpCommand = new HelpCommand(Manager, "galops", "NuGet Gallery Operations", "https://github.com/NuGet/NuGetOperations/wiki/GalOps---Gallery-Operations-Commands"); // Add commands foreach (ICommand cmd in Commands) { Manager.RegisterCommand(cmd); } var secretReaderFactory = new SecretReaderFactory(ConfigurationManager.AppSettings); var configurationProcessor = new ConfigurationProcessor(secretReaderFactory); configurationProcessor.InjectSecretsInto(ConfigurationManager.AppSettings); // Parse the command var parser = new CommandLineParser(Manager, secretReaderFactory); ICommand command = parser.ParseCommandLine(args) ?? HelpCommand; // Fall back on help command if we failed to parse a valid command if (!ArgumentCountValid(command)) { string commandName = command.CommandAttribute.CommandName; Console.WriteLine("{0}: invalid arguments..", commandName); HelpCommand.ViewHelpForCommand(commandName); } else { // Ensure that SSLv3 is disabled and that Tls v1.2 is enabled. ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3; ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; command.Execute(); } } catch (AggregateException exception) { string message; Exception unwrappedEx = ExceptionUtility.Unwrap(exception); if (unwrappedEx == exception) { // If the AggregateException contains more than one InnerException, it cannot be unwrapped. In which case, simply print out individual error messages message = String.Join(Environment.NewLine, exception.InnerExceptions.Select(ex => ex.Message).Distinct(StringComparer.CurrentCulture)); } else { message = ExceptionUtility.Unwrap(exception).Message; } _logger.Error("{0}: {1}", unwrappedEx.GetType().Name, message); _logger.Error(" Stack Trace: " + unwrappedEx.StackTrace); return(1); } catch (Exception e) { var ex = ExceptionUtility.Unwrap(e); _logger.Error("{0}: {1}", ex.GetType().Name, ex.Message); _logger.Error(" Stack Trace: " + ex.StackTrace); return(1); } return(0); }
static int Main(string[] args) { var argsDictionary = DictionaryHelper.FromProgramArguments(args); var settings = new GameplaySettings(); var outputSettings = new OutputSettings(); settings.Update("fz1mr--16psr-lc-f"); settings.CustomItemListString = "81-80000000----3fff-ffffffff-ffffffff-fe000000-6619ff-7fffffff-f378ffff-ffffffff"; settings.CustomItemList = ConvertIntString(settings.CustomItemListString); settings.CustomStartingItemListString = "-3fc04000-"; settings.CustomStartingItemList = ConvertItemString(ItemUtils.StartingItems().Where(item => !item.Name().Contains("Heart")).ToList(), settings.CustomStartingItemListString); settings.CustomJunkLocationsString = "----------200000--f000"; settings.CustomJunkLocations = ConvertItemString(ItemUtils.AllLocations().ToList(), settings.CustomJunkLocationsString); outputSettings.GeneratePatch = argsDictionary.ContainsKey("-patch"); outputSettings.GenerateSpoilerLog = argsDictionary.ContainsKey("-spoiler"); outputSettings.GenerateHTMLLog = argsDictionary.ContainsKey("-html"); outputSettings.GenerateROM = argsDictionary.ContainsKey("-rom"); int seed; if (argsDictionary.ContainsKey("-seed")) { seed = int.Parse(argsDictionary["-seed"][0]); } else { seed = new Random().Next(); } var outputArg = argsDictionary.GetValueOrDefault("-output"); if (outputArg != null) { if (outputArg.Count > 1) { throw new ArgumentException("Invalid argument.", "-output"); } outputSettings.OutputROMFilename = outputArg.SingleOrDefault(); } outputSettings.OutputROMFilename ??= Path.Combine("output", FileUtils.MakeFilenameValid(DateTime.UtcNow.ToString("o"))); var inputArg = argsDictionary.GetValueOrDefault("-input"); if (inputArg != null) { if (inputArg.Count > 1) { throw new ArgumentException("Invalid argument.", "-input"); } outputSettings.InputROMFilename = inputArg.SingleOrDefault(); } outputSettings.InputROMFilename ??= "input.z64"; var validationResult = settings.Validate(); if (validationResult != null) { Console.WriteLine(validationResult); return(-1); } try { string result; using (var progressBar = new ProgressBar()) { //var progressReporter = new TextWriterProgressReporter(Console.Out); var progressReporter = new ProgressBarProgressReporter(progressBar); result = ConfigurationProcessor.Process(new Configuration { GameplaySettings = settings, OutputSettings = outputSettings, }, seed, progressReporter); } if (result != null) { Console.Error.WriteLine(result); } else { Console.WriteLine("Generation complete!"); } return(result == null ? 0 : -1); } catch (Exception e) { Console.Error.Write(e.Message); Console.Error.Write(e.StackTrace); return(-1); } }
private static async Task RenewAsync(Overrides overrides, ILogger log, CancellationToken cancellationToken, ExecutionContext executionContext) { // internal storage (used for letsencrypt account metadata) IStorageProvider storageProvider = new AzureBlobStorageProvider(Environment.GetEnvironmentVariable("AzureWebJobsStorage"), "letsencrypt"); IConfigurationProcessor processor = new ConfigurationProcessor(); var configurations = await LoadConfigFilesAsync(storageProvider, processor, log, cancellationToken, executionContext); IAuthenticationService authenticationService = new AuthenticationService(storageProvider); var az = new AzureHelper(); var tokenProvider = new AzureServiceTokenProvider(); var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback)); var storageFactory = new StorageFactory(az); var renewalOptionsParser = new RenewalOptionParser(az, keyVaultClient, storageFactory, log); var certificateBuilder = new CertificateBuilder(); IRenewalService renewalService = new RenewalService(authenticationService, renewalOptionsParser, certificateBuilder, log); var stopwatch = new Stopwatch(); // TODO: with lots of certificate renewals this could run into function timeout (10mins) // with 30 days to expiry (default setting) this isn't a big problem as next day all finished certs are skipped // user will only get email <= 14 days before expiry so acceptable for now var errors = new List <Exception>(); foreach ((var name, var config) in configurations) { using (log.BeginScope($"Working on certificates from {name}")) { foreach (var cert in config.Certificates) { stopwatch.Restart(); var hostNames = string.Join(";", cert.HostNames); cert.Overrides = overrides ?? Overrides.None; try { var result = await renewalService.RenewCertificateAsync(config.Acme, cert, cancellationToken); switch (result) { case RenewalResult.NoChange: log.LogInformation($"Certificate renewal skipped for: {hostNames} (no change required yet)"); break; case RenewalResult.Success: log.LogInformation($"Certificate renewal succeeded for: {hostNames}"); break; default: throw new ArgumentOutOfRangeException(result.ToString()); } } catch (Exception e) { log.LogError(e, $"Certificate renewal failed for: {hostNames}!"); errors.Add(e); } log.LogInformation($"Renewing certificates for {hostNames} took: {stopwatch.Elapsed}"); } } } if (!configurations.Any()) { log.LogWarning("No configurations where processed, refere to the sample on how to set up configs!"); } if (errors.Any()) { throw new AggregateException("Failed to process all certificates", errors); } }
static int Main(string[] args) { var argsDictionary = DictionaryHelper.FromProgramArguments(args); if (argsDictionary.ContainsKey("-help")) { Console.WriteLine("All arguments are optional."); var helpTexts = new Dictionary <string, string> { { "-help", "See this help text." }, { "-settings <path>", "Path to a settings JSON file. Only the GameplaySettings will be loaded. Other settings will be loaded from your default settings.json file." }, { "-patch", "Output a .mmr patch file." }, { "-spoiler", "Output a .txt spoiler log." }, { "-html", "Output a .html item tracker." }, { "-rom", "Output a .z64 ROM file." }, { "-seed", "Set the seed for the randomizer." }, { "-output <path>", "Path to output the output ROM. Other outputs will be based on the filename in this path. If omitted, will output to \"output/{timestamp}.z64\"" }, { "-input <path>", "Path to the input Majora's Mask (U) ROM. If omitted, will try to use \"input.z64\"." }, { "-save", "Save the settings to the default settings.json file." }, }; foreach (var kvp in helpTexts) { Console.WriteLine("{0, -17} {1}", kvp.Key, kvp.Value); } Console.WriteLine("settings.json details:"); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.LogicMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.DamageMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.DamageEffect)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.MovementMode)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.FloorType)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.ClockSpeed)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.BlastMaskCooldown)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.GameplaySettings.GossipHintStyle)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.CosmeticSettings.TatlColorSchema)); Console.WriteLine(GetEnumSettingDescription(cfg => cfg.CosmeticSettings.Music)); Console.WriteLine(GetEnumArraySettingDescription(cfg => cfg.CosmeticSettings.DPad.Pad.Values) + " Array length of 4."); Console.WriteLine(GetArrayValueDescription(nameof(CosmeticSettings.HeartsSelection), ColorSelectionManager.Hearts.GetItems().Select(csi => csi.Name))); Console.WriteLine(GetArrayValueDescription(nameof(CosmeticSettings.MagicSelection), ColorSelectionManager.MagicMeter.GetItems().Select(csi => csi.Name))); Console.WriteLine(GetSettingDescription(nameof(GameplaySettings.EnabledTricks), "Array of trick IDs.")); return(0); } var configuration = LoadSettings(); if (configuration == null) { Console.WriteLine("Default settings file not found. Generating..."); configuration = new Configuration { CosmeticSettings = new CosmeticSettings(), GameplaySettings = new GameplaySettings(), OutputSettings = new OutputSettings() { InputROMFilename = "input.z64", }, }; SaveSettings(configuration); Console.WriteLine($"Generated {Path.ChangeExtension(DEFAULT_SETTINGS_FILENAME, SETTINGS_EXTENSION)}. Edit it to set your settings."); } var settingsPath = argsDictionary.GetValueOrDefault("-settings")?.FirstOrDefault(); if (settingsPath != null) { var loadedConfiguration = LoadSettings(settingsPath); if (loadedConfiguration == null) { Console.WriteLine($"File not found \"{settingsPath}\"."); return(-1); } if (loadedConfiguration.GameplaySettings == null) { Console.WriteLine($"Error loading GameplaySettings from \"{settingsPath}\"."); return(-1); } configuration.GameplaySettings = loadedConfiguration.GameplaySettings; Console.WriteLine($"Loaded GameplaySettings from \"{settingsPath}\"."); } configuration.GameplaySettings.CustomItemList = ConvertIntString(configuration.GameplaySettings.CustomItemListString); configuration.GameplaySettings.CustomStartingItemList = ConvertItemString(ItemUtils.StartingItems().Where(item => !item.Name().Contains("Heart")).ToList(), configuration.GameplaySettings.CustomStartingItemListString); configuration.GameplaySettings.CustomJunkLocations = ConvertItemString(ItemUtils.AllLocations().ToList(), configuration.GameplaySettings.CustomJunkLocationsString); configuration.OutputSettings.GeneratePatch |= argsDictionary.ContainsKey("-patch"); configuration.OutputSettings.GenerateSpoilerLog |= argsDictionary.ContainsKey("-spoiler"); configuration.OutputSettings.GenerateHTMLLog |= argsDictionary.ContainsKey("-html"); configuration.OutputSettings.GenerateROM |= argsDictionary.ContainsKey("-rom"); int seed; if (argsDictionary.ContainsKey("-seed")) { seed = int.Parse(argsDictionary["-seed"][0]); } else { seed = new Random().Next(); } var outputArg = argsDictionary.GetValueOrDefault("-output"); if (outputArg != null) { if (outputArg.Count > 1) { throw new ArgumentException("Invalid argument.", "-output"); } configuration.OutputSettings.OutputROMFilename = outputArg.SingleOrDefault(); } configuration.OutputSettings.OutputROMFilename ??= Path.Combine("output", FileUtils.MakeFilenameValid(DateTime.UtcNow.ToString("o"))); if (Path.GetExtension(configuration.OutputSettings.OutputROMFilename) != ".z64") { configuration.OutputSettings.OutputROMFilename += ".z64"; } var inputArg = argsDictionary.GetValueOrDefault("-input"); if (inputArg != null) { if (inputArg.Count > 1) { throw new ArgumentException("Invalid argument.", "-input"); } configuration.OutputSettings.InputROMFilename = inputArg.SingleOrDefault(); } configuration.OutputSettings.InputROMFilename ??= "input.z64"; if (argsDictionary.ContainsKey("-save")) { SaveSettings(configuration); } var validationResult = configuration.GameplaySettings.Validate() ?? configuration.OutputSettings.Validate(); if (validationResult != null) { Console.WriteLine(validationResult); return(-1); } try { string result; using (var progressBar = new ProgressBar()) { //var progressReporter = new TextWriterProgressReporter(Console.Out); var progressReporter = new ProgressBarProgressReporter(progressBar); result = ConfigurationProcessor.Process(configuration, seed, progressReporter); } if (result != null) { Console.Error.WriteLine(result); } else { Console.WriteLine("Generation complete!"); } return(result == null ? 0 : -1); } catch (Exception e) { Console.Error.Write(e.Message); Console.Error.Write(e.StackTrace); return(-1); } }