Add Apr2025 Randomizer
This commit is contained in:
@@ -11,4 +11,4 @@ ALttPRandomizer/[Bb]in
|
|||||||
*/DR_*
|
*/DR_*
|
||||||
*/ER_*
|
*/ER_*
|
||||||
*/OR_*
|
*/OR_*
|
||||||
*/data/base2current.json
|
BaseRandomizer/data/base2current.json
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -4,3 +4,6 @@
|
|||||||
[submodule "BaseRandomizer"]
|
[submodule "BaseRandomizer"]
|
||||||
path = BaseRandomizer
|
path = BaseRandomizer
|
||||||
url = https://github.com/ardnaxelarak/ALttPDoorRandomizer
|
url = https://github.com/ardnaxelarak/ALttPDoorRandomizer
|
||||||
|
[submodule "Apr2025Randomizer"]
|
||||||
|
path = Apr2025Randomizer
|
||||||
|
url = https://github.com/ardnaxelarak/ALttPDoorRandomizer
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
namespace ALttPRandomizer.Model {
|
namespace ALttPRandomizer.Model {
|
||||||
|
using ALttPRandomizer.Randomizers;
|
||||||
using ALttPRandomizer.Settings;
|
using ALttPRandomizer.Settings;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
using static ALttPRandomizer.Model.RandomizerInstance;
|
||||||
|
|
||||||
public class SeedSettings {
|
public class SeedSettings {
|
||||||
|
[NoSettingName]
|
||||||
|
public RandomizerInstance Randomizer { get; set; } = RandomizerInstance.Base;
|
||||||
|
|
||||||
[NoSettingName]
|
[NoSettingName]
|
||||||
public RaceMode Race { get; set; } = RaceMode.Normal;
|
public RaceMode Race { get; set; } = RaceMode.Normal;
|
||||||
|
|
||||||
|
[ForbiddenSetting([Apr2025], Mode.Inverted)]
|
||||||
public Mode Mode { get; set; } = Mode.Open;
|
public Mode Mode { get; set; } = Mode.Open;
|
||||||
|
|
||||||
[SettingName("swords")]
|
[SettingName("swords")]
|
||||||
@@ -19,44 +25,75 @@
|
|||||||
|
|
||||||
[SettingName("crystals_gt")]
|
[SettingName("crystals_gt")]
|
||||||
[JsonPropertyName("crystals_gt")]
|
[JsonPropertyName("crystals_gt")]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public EntryRequirement CrystalsGT { get; set; } = EntryRequirement.Crystals7;
|
public EntryRequirement CrystalsGT { get; set; } = EntryRequirement.Crystals7;
|
||||||
|
|
||||||
[SettingName("shuffle")]
|
[SettingName("shuffle")]
|
||||||
|
[ForbiddenSetting([Apr2025], EntranceShuffle.Swapped)]
|
||||||
public EntranceShuffle EntranceShuffle { get; set; } = EntranceShuffle.Vanilla;
|
public EntranceShuffle EntranceShuffle { get; set; } = EntranceShuffle.Vanilla;
|
||||||
|
|
||||||
[SettingName("skullwoods")]
|
[SettingName("skullwoods")]
|
||||||
|
[RequiredSetting([Apr2025], SkullWoodsShuffle.Original)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public SkullWoodsShuffle SkullWoods { get; set; } = SkullWoodsShuffle.Original;
|
public SkullWoodsShuffle SkullWoods { get; set; } = SkullWoodsShuffle.Original;
|
||||||
|
|
||||||
[SettingName("linked_drops")]
|
[SettingName("linked_drops")]
|
||||||
|
[RequiredSetting([Apr2025], LinkedDrops.Unset)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public LinkedDrops LinkedDrops { get; set; } = LinkedDrops.Unset;
|
public LinkedDrops LinkedDrops { get; set; } = LinkedDrops.Unset;
|
||||||
|
|
||||||
[SettingName("shufflebosses")]
|
[SettingName("shufflebosses")]
|
||||||
|
[RequiredSetting([Apr2025], BossShuffle.Vanilla)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public BossShuffle BossShuffle { get; set; } = BossShuffle.Vanilla;
|
public BossShuffle BossShuffle { get; set; } = BossShuffle.Vanilla;
|
||||||
|
|
||||||
[SettingName("shuffleenemies")]
|
[SettingName("shuffleenemies")]
|
||||||
|
[RequiredSetting([Apr2025], EnemyShuffle.Vanilla)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public EnemyShuffle EnemyShuffle { get; set; } = EnemyShuffle.Vanilla;
|
public EnemyShuffle EnemyShuffle { get; set; } = EnemyShuffle.Vanilla;
|
||||||
|
|
||||||
[SettingName("keyshuffle")]
|
[SettingName("keyshuffle")]
|
||||||
public DungeonItemLocations SmallKeys { get; set; } = DungeonItemLocations.Dungeon;
|
[RequiredSetting([Apr2025], KeyLocations.Dungeon, KeyLocations.Wild)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
|
public KeyLocations SmallKeys { get; set; } = KeyLocations.Dungeon;
|
||||||
|
|
||||||
[SettingName("bigkeyshuffle")]
|
[SettingName("bigkeyshuffle")]
|
||||||
[DeniedValues(DungeonItemLocations.Universal)]
|
[RequiredSetting([Apr2025], DungeonItemLocations.Dungeon)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public DungeonItemLocations BigKeys { get; set; } = DungeonItemLocations.Dungeon;
|
public DungeonItemLocations BigKeys { get; set; } = DungeonItemLocations.Dungeon;
|
||||||
|
|
||||||
[SettingName("mapshuffle")]
|
[SettingName("mapshuffle")]
|
||||||
[DeniedValues(DungeonItemLocations.Universal)]
|
[RequiredSetting([Apr2025], DungeonItemLocations.Dungeon)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public DungeonItemLocations Maps { get; set; } = DungeonItemLocations.Dungeon;
|
public DungeonItemLocations Maps { get; set; } = DungeonItemLocations.Dungeon;
|
||||||
|
|
||||||
[SettingName("compassshuffle")]
|
[SettingName("compassshuffle")]
|
||||||
[DeniedValues(DungeonItemLocations.Universal)]
|
[RequiredSetting([Apr2025], DungeonItemLocations.Dungeon)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public DungeonItemLocations Compasses { get; set; } = DungeonItemLocations.Dungeon;
|
public DungeonItemLocations Compasses { get; set; } = DungeonItemLocations.Dungeon;
|
||||||
|
|
||||||
[NoSettingName]
|
[NoSettingName]
|
||||||
|
[RequiredSetting([Apr2025], ShopShuffle.Vanilla)]
|
||||||
public ShopShuffle ShopShuffle { get; set; } = ShopShuffle.Vanilla;
|
public ShopShuffle ShopShuffle { get; set; } = ShopShuffle.Vanilla;
|
||||||
|
|
||||||
|
[RequiredSetting([Apr2025], DropShuffle.Vanilla)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public DropShuffle DropShuffle { get; set; } = DropShuffle.Vanilla;
|
public DropShuffle DropShuffle { get; set; } = DropShuffle.Vanilla;
|
||||||
|
|
||||||
|
[RequiredSetting([Apr2025], Pottery.Vanilla)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public Pottery Pottery { get; set; } = Pottery.Vanilla;
|
public Pottery Pottery { get; set; } = Pottery.Vanilla;
|
||||||
|
|
||||||
|
[RequiredSetting([Apr2025], PrizeShuffle.Vanilla)]
|
||||||
|
[NoSettingName([Apr2025])]
|
||||||
public PrizeShuffle PrizeShuffle { get; set; } = PrizeShuffle.Vanilla;
|
public PrizeShuffle PrizeShuffle { get; set; } = PrizeShuffle.Vanilla;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum RandomizerInstance {
|
||||||
|
[RandomizerName(BaseRandomizer.Name)] Base,
|
||||||
|
[RandomizerName(Apr2025Randomizer.Name)] Apr2025,
|
||||||
|
}
|
||||||
|
|
||||||
public enum RaceMode {
|
public enum RaceMode {
|
||||||
Normal,
|
Normal,
|
||||||
[AdditionalSetting("--securerandom")] Race,
|
[AdditionalSetting("--securerandom")] Race,
|
||||||
@@ -132,11 +169,17 @@
|
|||||||
Mimics,
|
Mimics,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum KeyLocations {
|
||||||
|
[SettingName("none")] Dungeon,
|
||||||
|
[AdditionalSetting([Apr2025], "--keysanity")] Wild,
|
||||||
|
Nearby,
|
||||||
|
Universal,
|
||||||
|
}
|
||||||
|
|
||||||
public enum DungeonItemLocations {
|
public enum DungeonItemLocations {
|
||||||
[SettingName("none")] Dungeon,
|
[SettingName("none")] Dungeon,
|
||||||
Wild,
|
Wild,
|
||||||
Nearby,
|
Nearby,
|
||||||
Universal,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ShopShuffle {
|
public enum ShopShuffle {
|
||||||
@@ -168,5 +211,4 @@
|
|||||||
Nearby,
|
Nearby,
|
||||||
Wild,
|
Wild,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
public class ServiceOptions {
|
public class ServiceOptions {
|
||||||
public string Baserom { get; set; } = null!;
|
public string Baserom { get; set; } = null!;
|
||||||
public string PythonPath { get; set; } = null!;
|
public string PythonPath { get; set; } = null!;
|
||||||
public string RandomizerPath { get; set; } = null!;
|
public string FlipsPath { get; set; } = null!;
|
||||||
public IList<string> AllowedCors { get; set; } = new List<string>();
|
public IList<string> AllowedCors { get; set; } = new List<string>();
|
||||||
public AzureSettings AzureSettings { get; set; } = new AzureSettings();
|
public AzureSettings AzureSettings { get; set; } = new AzureSettings();
|
||||||
|
public IDictionary<string, string> RandomizerPaths { get; set; } = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AzureSettings {
|
public class AzureSettings {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ALttPRandomizer
|
namespace ALttPRandomizer {
|
||||||
{
|
|
||||||
using ALttPRandomizer.Azure;
|
using ALttPRandomizer.Azure;
|
||||||
using ALttPRandomizer.Options;
|
using ALttPRandomizer.Options;
|
||||||
|
using ALttPRandomizer.Randomizers;
|
||||||
using ALttPRandomizer.Service;
|
using ALttPRandomizer.Service;
|
||||||
using ALttPRandomizer.Settings;
|
using ALttPRandomizer.Settings;
|
||||||
using global::Azure.Identity;
|
using global::Azure.Identity;
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
@@ -60,9 +61,13 @@
|
|||||||
var seedClient = new BlobContainerClient(settings.AzureSettings.BlobstoreEndpoint, token);
|
var seedClient = new BlobContainerClient(settings.AzureSettings.BlobstoreEndpoint, token);
|
||||||
|
|
||||||
builder.Services.AddSingleton(seedClient);
|
builder.Services.AddSingleton(seedClient);
|
||||||
|
builder.Services.AddSingleton(sp => sp);
|
||||||
builder.Services.AddSingleton<AzureStorage>();
|
builder.Services.AddSingleton<AzureStorage>();
|
||||||
builder.Services.AddSingleton<CommonSettingsProcessor>();
|
builder.Services.AddSingleton<CommonSettingsProcessor>();
|
||||||
builder.Services.AddScoped<Randomizer>();
|
|
||||||
|
builder.Services.AddKeyedScoped<IRandomizer, BaseRandomizer>(BaseRandomizer.Name);
|
||||||
|
builder.Services.AddKeyedScoped<IRandomizer, Apr2025Randomizer>(Apr2025Randomizer.Name);
|
||||||
|
|
||||||
builder.Services.AddScoped<RandomizeService>();
|
builder.Services.AddScoped<RandomizeService>();
|
||||||
builder.Services.AddScoped<SeedService>();
|
builder.Services.AddScoped<SeedService>();
|
||||||
builder.Services.AddScoped<IdGenerator>();
|
builder.Services.AddScoped<IdGenerator>();
|
||||||
|
|||||||
159
ALttPRandomizer/Randomizers/Apr2025Randomizer.cs
Normal file
159
ALttPRandomizer/Randomizers/Apr2025Randomizer.cs
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
namespace ALttPRandomizer.Randomizers {
|
||||||
|
using ALttPRandomizer;
|
||||||
|
using ALttPRandomizer.Azure;
|
||||||
|
using ALttPRandomizer.Model;
|
||||||
|
using ALttPRandomizer.Options;
|
||||||
|
using ALttPRandomizer.Settings;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class Apr2025Randomizer : IRandomizer {
|
||||||
|
public const string Name = "apr2025";
|
||||||
|
public const RandomizerInstance Instance = RandomizerInstance.Apr2025;
|
||||||
|
|
||||||
|
public Apr2025Randomizer(
|
||||||
|
AzureStorage azureStorage,
|
||||||
|
CommonSettingsProcessor settingsProcessor,
|
||||||
|
IOptionsMonitor<ServiceOptions> optionsMonitor,
|
||||||
|
ILogger<BaseRandomizer> logger) {
|
||||||
|
AzureStorage = azureStorage;
|
||||||
|
SettingsProcessor = settingsProcessor;
|
||||||
|
OptionsMonitor = optionsMonitor;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommonSettingsProcessor SettingsProcessor { get; }
|
||||||
|
private AzureStorage AzureStorage { get; }
|
||||||
|
private IOptionsMonitor<ServiceOptions> OptionsMonitor { get; }
|
||||||
|
private ILogger<BaseRandomizer> Logger { get; }
|
||||||
|
private ServiceOptions Configuration => OptionsMonitor.CurrentValue;
|
||||||
|
|
||||||
|
public void Validate(SeedSettings settings) {
|
||||||
|
this.SettingsProcessor.ValidateSettings(Instance, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Randomize(string id, SeedSettings settings) {
|
||||||
|
Logger.LogDebug("Recieved request for id {id} to randomize settings {@settings}", id, settings);
|
||||||
|
|
||||||
|
var start = new ProcessStartInfo() {
|
||||||
|
FileName = Configuration.PythonPath,
|
||||||
|
WorkingDirectory = Configuration.RandomizerPaths[Name],
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var args = start.ArgumentList;
|
||||||
|
args.Add("EntranceRandomizer.py");
|
||||||
|
args.Add("--rom");
|
||||||
|
args.Add(Configuration.Baserom);
|
||||||
|
|
||||||
|
args.Add("--outputpath");
|
||||||
|
args.Add(Path.GetTempPath());
|
||||||
|
|
||||||
|
args.Add("--outputname");
|
||||||
|
args.Add(id);
|
||||||
|
|
||||||
|
args.Add("--json_spoiler");
|
||||||
|
|
||||||
|
args.Add("--quickswap");
|
||||||
|
|
||||||
|
foreach (var arg in SettingsProcessor.GetSettings(Instance, settings)) {
|
||||||
|
args.Add(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInformation("Randomizing with args: {args}", string.Join(" ", args));
|
||||||
|
|
||||||
|
var generating = string.Format("{0}/generating", id);
|
||||||
|
await AzureStorage.UploadFile(generating, BinaryData.Empty);
|
||||||
|
|
||||||
|
var process = Process.Start(start) ?? throw new GenerationFailedException("Process failed to start.");
|
||||||
|
process.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
process.OutputDataReceived += (_, args) => Logger.LogInformation("Randomizer STDOUT: {output}", args.Data);
|
||||||
|
process.ErrorDataReceived += (_, args) => Logger.LogInformation("Randomizer STDERR: {output}", args.Data);
|
||||||
|
|
||||||
|
process.BeginOutputReadLine();
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
|
||||||
|
process.Exited += async (sender, args) => {
|
||||||
|
var exitcode = process.ExitCode;
|
||||||
|
|
||||||
|
if (exitcode != 0) {
|
||||||
|
await GenerationFailed(id, exitcode);
|
||||||
|
} else {
|
||||||
|
await GenerationSucceeded(id, settings);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var settingsJson = JsonSerializer.SerializeToDocument(settings, JsonOptions.Default);
|
||||||
|
var settingsOut = string.Format("{0}/settings.json", id);
|
||||||
|
await AzureStorage.UploadFile(settingsOut, new BinaryData(settingsJson));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GenerationSucceeded(string id, SeedSettings settings) {
|
||||||
|
var rom = Path.Join(Path.GetTempPath(), string.Format("ER_{0}.sfc", id));
|
||||||
|
|
||||||
|
var spoilerIn = Path.Join(Path.GetTempPath(), string.Format("ER_{0}_Spoiler.json", id));
|
||||||
|
var spoilerOut = string.Format("{0}/spoiler.json", id);
|
||||||
|
var uploadSpoiler = AzureStorage.UploadFileAndDelete(spoilerOut, spoilerIn);
|
||||||
|
|
||||||
|
var metaIn = Path.Join(Path.GetTempPath(), string.Format("ER_{0}_Meta.json", id));
|
||||||
|
var metaOut = string.Format("{0}/meta.json", id);
|
||||||
|
var uploadMeta = AzureStorage.UploadFileAndDelete(metaOut, metaIn);
|
||||||
|
|
||||||
|
var bpsIn = Path.Join(Path.GetTempPath(), string.Format("ER_{0}.bps", id));
|
||||||
|
|
||||||
|
var flips = new ProcessStartInfo() {
|
||||||
|
FileName = Configuration.FlipsPath,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
};
|
||||||
|
var args = flips.ArgumentList;
|
||||||
|
args.Add("--create");
|
||||||
|
args.Add(Configuration.Baserom);
|
||||||
|
args.Add(rom);
|
||||||
|
args.Add(bpsIn);
|
||||||
|
|
||||||
|
var process = Process.Start(flips) ?? throw new GenerationFailedException("Process failed to start.");
|
||||||
|
process.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
process.OutputDataReceived += (_, args) => Logger.LogInformation("flips STDOUT: {output}", args.Data);
|
||||||
|
process.ErrorDataReceived += (_, args) => Logger.LogInformation("flips STDERR: {output}", args.Data);
|
||||||
|
|
||||||
|
process.BeginOutputReadLine();
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
|
||||||
|
await process.WaitForExitAsync();
|
||||||
|
|
||||||
|
if (process.ExitCode != 0) {
|
||||||
|
await this.GenerationFailed(id, process.ExitCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bpsOut = string.Format("{0}/patch.bps", id);
|
||||||
|
var uploadPatch = AzureStorage.UploadFileAndDelete(bpsOut, bpsIn);
|
||||||
|
|
||||||
|
var generating = string.Format("{0}/generating", id);
|
||||||
|
var deleteGenerating = AzureStorage.DeleteFile(generating);
|
||||||
|
|
||||||
|
await Task.WhenAll(uploadPatch, uploadSpoiler, uploadMeta, deleteGenerating);
|
||||||
|
|
||||||
|
Logger.LogDebug("Deleting file {filepath}", rom);
|
||||||
|
File.Delete(rom);
|
||||||
|
|
||||||
|
Logger.LogInformation("Finished uploading seed id {id}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GenerationFailed(string id, int exitcode) {
|
||||||
|
var generating = string.Format("{0}/generating", id);
|
||||||
|
var deleteGenerating = AzureStorage.DeleteFile(generating);
|
||||||
|
|
||||||
|
await Task.WhenAll(deleteGenerating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
namespace ALttPRandomizer {
|
namespace ALttPRandomizer.Randomizers {
|
||||||
|
using ALttPRandomizer;
|
||||||
using ALttPRandomizer.Azure;
|
using ALttPRandomizer.Azure;
|
||||||
using ALttPRandomizer.Model;
|
using ALttPRandomizer.Model;
|
||||||
using ALttPRandomizer.Options;
|
using ALttPRandomizer.Options;
|
||||||
@@ -12,30 +13,37 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public class Randomizer {
|
public class BaseRandomizer : IRandomizer {
|
||||||
public Randomizer(
|
public const string Name = "base";
|
||||||
|
public const RandomizerInstance Instance = RandomizerInstance.Base;
|
||||||
|
|
||||||
|
public BaseRandomizer(
|
||||||
AzureStorage azureStorage,
|
AzureStorage azureStorage,
|
||||||
CommonSettingsProcessor settingsProcessor,
|
CommonSettingsProcessor settingsProcessor,
|
||||||
IOptionsMonitor<ServiceOptions> optionsMonitor,
|
IOptionsMonitor<ServiceOptions> optionsMonitor,
|
||||||
ILogger<Randomizer> logger) {
|
ILogger<BaseRandomizer> logger) {
|
||||||
this.AzureStorage = azureStorage;
|
AzureStorage = azureStorage;
|
||||||
this.SettingsProcessor = settingsProcessor;
|
SettingsProcessor = settingsProcessor;
|
||||||
this.OptionsMonitor = optionsMonitor;
|
OptionsMonitor = optionsMonitor;
|
||||||
this.Logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommonSettingsProcessor SettingsProcessor { get; }
|
private CommonSettingsProcessor SettingsProcessor { get; }
|
||||||
private AzureStorage AzureStorage { get; }
|
private AzureStorage AzureStorage { get; }
|
||||||
private IOptionsMonitor<ServiceOptions> OptionsMonitor { get; }
|
private IOptionsMonitor<ServiceOptions> OptionsMonitor { get; }
|
||||||
private ILogger<Randomizer> Logger { get; }
|
private ILogger<BaseRandomizer> Logger { get; }
|
||||||
private ServiceOptions Configuration => this.OptionsMonitor.CurrentValue;
|
private ServiceOptions Configuration => OptionsMonitor.CurrentValue;
|
||||||
|
|
||||||
|
public void Validate(SeedSettings settings) {
|
||||||
|
this.SettingsProcessor.ValidateSettings(Instance, settings);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Randomize(string id, SeedSettings settings) {
|
public async Task Randomize(string id, SeedSettings settings) {
|
||||||
this.Logger.LogDebug("Recieved request for id {id} to randomize settings {@settings}", id, settings);
|
Logger.LogDebug("Recieved request for id {id} to randomize settings {@settings}", id, settings);
|
||||||
|
|
||||||
var start = new ProcessStartInfo() {
|
var start = new ProcessStartInfo() {
|
||||||
FileName = Configuration.PythonPath,
|
FileName = Configuration.PythonPath,
|
||||||
WorkingDirectory = Configuration.RandomizerPath,
|
WorkingDirectory = Configuration.RandomizerPaths[Name],
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
};
|
};
|
||||||
@@ -43,7 +51,7 @@
|
|||||||
var args = start.ArgumentList;
|
var args = start.ArgumentList;
|
||||||
args.Add("DungeonRandomizer.py");
|
args.Add("DungeonRandomizer.py");
|
||||||
args.Add("--rom");
|
args.Add("--rom");
|
||||||
args.Add(this.Configuration.Baserom);
|
args.Add(Configuration.Baserom);
|
||||||
args.Add("--bps");
|
args.Add("--bps");
|
||||||
|
|
||||||
args.Add("--outputpath");
|
args.Add("--outputpath");
|
||||||
@@ -60,17 +68,17 @@
|
|||||||
args.Add("--shufflelinks");
|
args.Add("--shufflelinks");
|
||||||
args.Add("--shuffletavern");
|
args.Add("--shuffletavern");
|
||||||
|
|
||||||
foreach (var arg in this.SettingsProcessor.GetSettings(settings)) {
|
foreach (var arg in SettingsProcessor.GetSettings(Instance, settings)) {
|
||||||
args.Add(arg);
|
args.Add(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Logger.LogInformation("Randomizing with args: {args}", string.Join(" ", args));
|
Logger.LogInformation("Randomizing with args: {args}", string.Join(" ", args));
|
||||||
|
|
||||||
var process = Process.Start(start) ?? throw new GenerationFailedException("Process failed to start.");
|
var process = Process.Start(start) ?? throw new GenerationFailedException("Process failed to start.");
|
||||||
process.EnableRaisingEvents = true;
|
process.EnableRaisingEvents = true;
|
||||||
|
|
||||||
process.OutputDataReceived += (_, args) => this.Logger.LogInformation("Randomizer STDOUT: {output}", args.Data);
|
process.OutputDataReceived += (_, args) => Logger.LogInformation("Randomizer STDOUT: {output}", args.Data);
|
||||||
process.ErrorDataReceived += (_, args) => this.Logger.LogInformation("Randomizer STDERR: {output}", args.Data);
|
process.ErrorDataReceived += (_, args) => Logger.LogInformation("Randomizer STDERR: {output}", args.Data);
|
||||||
|
|
||||||
process.BeginOutputReadLine();
|
process.BeginOutputReadLine();
|
||||||
process.BeginErrorReadLine();
|
process.BeginErrorReadLine();
|
||||||
@@ -79,18 +87,18 @@
|
|||||||
var exitcode = process.ExitCode;
|
var exitcode = process.ExitCode;
|
||||||
|
|
||||||
if (exitcode != 0) {
|
if (exitcode != 0) {
|
||||||
await this.GenerationFailed(id, exitcode);
|
await GenerationFailed(id, exitcode);
|
||||||
} else {
|
} else {
|
||||||
await this.GenerationSucceeded(id, settings);
|
await GenerationSucceeded(id, settings);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var settingsJson = JsonSerializer.SerializeToDocument(settings, JsonOptions.Default);
|
var settingsJson = JsonSerializer.SerializeToDocument(settings, JsonOptions.Default);
|
||||||
var settingsOut = string.Format("{0}/settings.json", id);
|
var settingsOut = string.Format("{0}/settings.json", id);
|
||||||
var uploadSettings = this.AzureStorage.UploadFile(settingsOut, new BinaryData(settingsJson));
|
var uploadSettings = AzureStorage.UploadFile(settingsOut, new BinaryData(settingsJson));
|
||||||
|
|
||||||
var generating = string.Format("{0}/generating", id);
|
var generating = string.Format("{0}/generating", id);
|
||||||
var uploadGenerating = this.AzureStorage.UploadFile(generating, BinaryData.Empty);
|
var uploadGenerating = AzureStorage.UploadFile(generating, BinaryData.Empty);
|
||||||
|
|
||||||
await Task.WhenAll(uploadSettings, uploadGenerating);
|
await Task.WhenAll(uploadSettings, uploadGenerating);
|
||||||
}
|
}
|
||||||
@@ -100,29 +108,29 @@
|
|||||||
|
|
||||||
var bpsIn = Path.Join(Path.GetTempPath(), string.Format("OR_{0}.bps", id));
|
var bpsIn = Path.Join(Path.GetTempPath(), string.Format("OR_{0}.bps", id));
|
||||||
var bpsOut = string.Format("{0}/patch.bps", id);
|
var bpsOut = string.Format("{0}/patch.bps", id);
|
||||||
var uploadPatch = this.AzureStorage.UploadFileAndDelete(bpsOut, bpsIn);
|
var uploadPatch = AzureStorage.UploadFileAndDelete(bpsOut, bpsIn);
|
||||||
|
|
||||||
var spoilerIn = Path.Join(Path.GetTempPath(), string.Format("OR_{0}_Spoiler.json", id));
|
var spoilerIn = Path.Join(Path.GetTempPath(), string.Format("OR_{0}_Spoiler.json", id));
|
||||||
var spoilerOut = string.Format("{0}/spoiler.json", id);
|
var spoilerOut = string.Format("{0}/spoiler.json", id);
|
||||||
var uploadSpoiler = this.AzureStorage.UploadFileAndDelete(spoilerOut, spoilerIn);
|
var uploadSpoiler = AzureStorage.UploadFileAndDelete(spoilerOut, spoilerIn);
|
||||||
|
|
||||||
var metaIn = Path.Join(Path.GetTempPath(), string.Format("OR_{0}_Meta.json", id));
|
var metaIn = Path.Join(Path.GetTempPath(), string.Format("OR_{0}_Meta.json", id));
|
||||||
var metaOut = string.Format("{0}/meta.json", id);
|
var metaOut = string.Format("{0}/meta.json", id);
|
||||||
var meta = this.ProcessMetadata(metaIn);
|
var meta = ProcessMetadata(metaIn);
|
||||||
var uploadMeta = this.AzureStorage.UploadFile(metaOut, new BinaryData(meta));
|
var uploadMeta = AzureStorage.UploadFile(metaOut, new BinaryData(meta));
|
||||||
|
|
||||||
var generating = string.Format("{0}/generating", id);
|
var generating = string.Format("{0}/generating", id);
|
||||||
var deleteGenerating = this.AzureStorage.DeleteFile(generating);
|
var deleteGenerating = AzureStorage.DeleteFile(generating);
|
||||||
|
|
||||||
await Task.WhenAll(uploadPatch, uploadSpoiler, uploadMeta, deleteGenerating);
|
await Task.WhenAll(uploadPatch, uploadSpoiler, uploadMeta, deleteGenerating);
|
||||||
|
|
||||||
this.Logger.LogDebug("Deleting file {filepath}", metaIn);
|
Logger.LogDebug("Deleting file {filepath}", metaIn);
|
||||||
File.Delete(metaIn);
|
File.Delete(metaIn);
|
||||||
|
|
||||||
this.Logger.LogDebug("Deleting file {filepath}", rom);
|
Logger.LogDebug("Deleting file {filepath}", rom);
|
||||||
File.Delete(rom);
|
File.Delete(rom);
|
||||||
|
|
||||||
this.Logger.LogInformation("Finished uploading seed id {id}", id);
|
Logger.LogInformation("Finished uploading seed id {id}", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonDocument ProcessMetadata(string path) {
|
private JsonDocument ProcessMetadata(string path) {
|
||||||
@@ -146,7 +154,7 @@
|
|||||||
|
|
||||||
private async Task GenerationFailed(string id, int exitcode) {
|
private async Task GenerationFailed(string id, int exitcode) {
|
||||||
var generating = string.Format("{0}/generating", id);
|
var generating = string.Format("{0}/generating", id);
|
||||||
var deleteGenerating = this.AzureStorage.DeleteFile(generating);
|
var deleteGenerating = AzureStorage.DeleteFile(generating);
|
||||||
|
|
||||||
await Task.WhenAll(deleteGenerating);
|
await Task.WhenAll(deleteGenerating);
|
||||||
}
|
}
|
||||||
10
ALttPRandomizer/Randomizers/IRandomizer.cs
Normal file
10
ALttPRandomizer/Randomizers/IRandomizer.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace ALttPRandomizer.Randomizers {
|
||||||
|
using ALttPRandomizer.Model;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public interface IRandomizer {
|
||||||
|
public void Validate(SeedSettings settings);
|
||||||
|
|
||||||
|
public Task Randomize(string id, SeedSettings settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace ALttPRandomizer {
|
namespace ALttPRandomizer {
|
||||||
using ALttPRandomizer.Model;
|
using ALttPRandomizer.Model;
|
||||||
using ALttPRandomizer.Service;
|
using ALttPRandomizer.Service;
|
||||||
|
using ALttPRandomizer.Settings;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -19,9 +20,13 @@
|
|||||||
[Route("/generate")]
|
[Route("/generate")]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<ActionResult> Generate(SeedSettings settings) {
|
public async Task<ActionResult> Generate(SeedSettings settings) {
|
||||||
var id = await this.RandomizeService.RandomizeSeed(settings);
|
try {
|
||||||
var url = string.Format("/seed/{0}", id);
|
var id = await this.RandomizeService.RandomizeSeed(settings);
|
||||||
return Accepted(url, id);
|
var url = string.Format("/seed/{0}", id);
|
||||||
|
return Accepted(url, id);
|
||||||
|
} catch (InvalidSettingsException ex) {
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/seed/{id}")]
|
[Route("/seed/{id}")]
|
||||||
|
|||||||
@@ -1,24 +1,41 @@
|
|||||||
using ALttPRandomizer.Model;
|
namespace ALttPRandomizer.Service {
|
||||||
using Microsoft.Extensions.Logging;
|
using ALttPRandomizer.Model;
|
||||||
using System.Threading.Tasks;
|
using ALttPRandomizer.Randomizers;
|
||||||
|
using ALttPRandomizer.Settings;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ALttPRandomizer.Service {
|
|
||||||
public class RandomizeService {
|
public class RandomizeService {
|
||||||
public RandomizeService(IdGenerator idGenerator, Randomizer randomizer, ILogger<RandomizeService> logger) {
|
public RandomizeService(IdGenerator idGenerator, IServiceProvider serviceProvider, ILogger<RandomizeService> logger) {
|
||||||
this.IdGenerator = idGenerator;
|
this.IdGenerator = idGenerator;
|
||||||
this.Randomizer = randomizer;
|
this.ServiceProvider = serviceProvider;
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILogger<RandomizeService> Logger { get; }
|
private ILogger<RandomizeService> Logger { get; }
|
||||||
|
|
||||||
private IdGenerator IdGenerator { get; }
|
private IdGenerator IdGenerator { get; }
|
||||||
private Randomizer Randomizer { get; }
|
private IServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
public async Task<string> RandomizeSeed(SeedSettings settings) {
|
public async Task<string> RandomizeSeed(SeedSettings settings) {
|
||||||
var id = this.IdGenerator.GenerateId();
|
var id = this.IdGenerator.GenerateId();
|
||||||
this.Logger.LogInformation("Generating seed {seedId} with settings {@settings}", id, settings);
|
this.Logger.LogInformation("Generating seed {seedId} with settings {@settings}", id, settings);
|
||||||
await this.Randomizer.Randomize(id, settings);
|
|
||||||
|
var fi = typeof(RandomizerInstance).GetField(settings.Randomizer.ToString(), BindingFlags.Static | BindingFlags.Public);
|
||||||
|
|
||||||
|
var randomizerKey = fi?.GetCustomAttribute<RandomizerNameAttribute>()?.Name;
|
||||||
|
|
||||||
|
if (randomizerKey == null) {
|
||||||
|
throw new InvalidSettingsException("Invalid randomizer: {0}", settings.Randomizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
var randomizer = this.ServiceProvider.GetRequiredKeyedService<IRandomizer>(randomizerKey);
|
||||||
|
randomizer.Validate(settings);
|
||||||
|
|
||||||
|
await randomizer.Randomize(id, settings);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,83 @@
|
|||||||
namespace ALttPRandomizer.Settings {
|
namespace ALttPRandomizer.Settings {
|
||||||
|
using ALttPRandomizer.Model;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
internal class SettingNameAttribute : Attribute {
|
internal class RandomizerNameAttribute : Attribute {
|
||||||
public SettingNameAttribute(string name) {
|
public RandomizerNameAttribute(string name) {
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NoSettingNameAttribute : Attribute { }
|
internal abstract class RandomizerSpecificAttribute : Attribute {
|
||||||
|
public RandomizerSpecificAttribute(RandomizerInstance[]? randomizers) {
|
||||||
|
this.Randomizers = randomizers;
|
||||||
|
}
|
||||||
|
|
||||||
internal class AdditionalSettingAttribute : Attribute {
|
protected RandomizerInstance[]? Randomizers { get; }
|
||||||
public AdditionalSettingAttribute(string setting) {
|
|
||||||
|
public bool HasRandomizer(RandomizerInstance name) {
|
||||||
|
if (this.Randomizers == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Randomizers.Contains(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SettingNameAttribute : RandomizerSpecificAttribute {
|
||||||
|
public SettingNameAttribute(string name) : base(null) {
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingNameAttribute(RandomizerInstance[] randomizers, string name) : base(randomizers) {
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class NoSettingNameAttribute : RandomizerSpecificAttribute {
|
||||||
|
public NoSettingNameAttribute() : base(null) { }
|
||||||
|
|
||||||
|
public NoSettingNameAttribute(RandomizerInstance[] randomizers) : base(randomizers) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AdditionalSettingAttribute : RandomizerSpecificAttribute {
|
||||||
|
public AdditionalSettingAttribute(string setting) : base(null) {
|
||||||
|
this.Setting = setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdditionalSettingAttribute(RandomizerInstance[] randomizers, string setting) : base(randomizers) {
|
||||||
this.Setting = setting;
|
this.Setting = setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Setting { get; }
|
public string Setting { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class RequiredSettingAttribute : RandomizerSpecificAttribute {
|
||||||
|
public RequiredSettingAttribute(params object[] values) : base(null) {
|
||||||
|
this.Values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequiredSettingAttribute(RandomizerInstance[] randomizers, params object[] values) : base(randomizers) {
|
||||||
|
this.Values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] Values { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ForbiddenSettingAttribute : RandomizerSpecificAttribute {
|
||||||
|
public ForbiddenSettingAttribute(params object[] values) : base(null) {
|
||||||
|
this.Values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbiddenSettingAttribute(RandomizerInstance[] randomizers, params object[] values) : base(randomizers) {
|
||||||
|
this.Values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] Values { get; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,61 @@
|
|||||||
using System;
|
namespace ALttPRandomizer.Settings {
|
||||||
|
|
||||||
namespace ALttPRandomizer.Settings {
|
|
||||||
using ALttPRandomizer.Model;
|
using ALttPRandomizer.Model;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
public class CommonSettingsProcessor {
|
public class CommonSettingsProcessor {
|
||||||
public IList<string> GetSettings(SeedSettings settings) {
|
public IEnumerable<string> GetSettings(RandomizerInstance randomizer, SeedSettings settings) {
|
||||||
var args = new List<string>();
|
|
||||||
|
|
||||||
var props = typeof(SeedSettings).GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
var props = typeof(SeedSettings).GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
||||||
foreach (var prop in props) {
|
foreach (var prop in props) {
|
||||||
var value = prop.GetValue(settings) ?? throw new SettingsLookupException("settings.{} not found", prop.Name);
|
var value = prop.GetValue(settings) ?? throw new SettingsLookupException("settings.{0} not found", prop.Name);
|
||||||
var valueFieldName = value.ToString() ?? throw new SettingsLookupException("settings.{}.ToString() returned null", prop.Name);
|
var valueFieldName = value.ToString() ?? throw new SettingsLookupException("settings.{0}.ToString() returned null", prop.Name);
|
||||||
var fi = prop.PropertyType.GetField(valueFieldName, BindingFlags.Static | BindingFlags.Public)
|
var fi = prop.PropertyType.GetField(valueFieldName, BindingFlags.Static | BindingFlags.Public)
|
||||||
?? throw new SettingsLookupException("Could not get field info for value {}.{}", prop.PropertyType, valueFieldName);
|
?? throw new SettingsLookupException("Could not get field info for value {0}.{1}", prop.PropertyType, valueFieldName);
|
||||||
|
|
||||||
if (prop.GetCustomAttribute<NoSettingNameAttribute>() == null) {
|
if (!prop.GetCustomAttributes<NoSettingNameAttribute>().Any(att => att.HasRandomizer(randomizer))) {
|
||||||
var settingName = prop.GetCustomAttribute<SettingNameAttribute>()?.Name ?? prop.Name.ToLower();
|
var settingName =
|
||||||
var valueName = fi.GetCustomAttribute<SettingNameAttribute>()?.Name ?? valueFieldName.ToLower();
|
prop.GetCustomAttributes<SettingNameAttribute>()
|
||||||
|
.FirstOrDefault(att => att.HasRandomizer(randomizer))?.Name ?? prop.Name.ToLower();
|
||||||
|
var valueName =
|
||||||
|
fi.GetCustomAttributes<SettingNameAttribute>()
|
||||||
|
.FirstOrDefault(att => att.HasRandomizer(randomizer))?.Name ?? valueFieldName.ToLower();
|
||||||
|
|
||||||
args.Add(string.Format("--{0}={1}", settingName, valueName));
|
yield return string.Format("--{0}={1}", settingName, valueName);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var att in fi.GetCustomAttributes<AdditionalSettingAttribute>()) {
|
foreach (var att in fi.GetCustomAttributes<AdditionalSettingAttribute>().Where(att => att.HasRandomizer(randomizer))) {
|
||||||
args.Add(att.Setting);
|
yield return att.Setting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return args;
|
public void ValidateSettings(RandomizerInstance randomizer, SeedSettings settings) {
|
||||||
|
var props = typeof(SeedSettings).GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
foreach (var prop in props) {
|
||||||
|
var value = prop.GetValue(settings) ?? throw new SettingsLookupException("settings.{0} not found", prop.Name);
|
||||||
|
|
||||||
|
foreach (var att in prop.GetCustomAttributes<RequiredSettingAttribute>().Where(att => att.HasRandomizer(randomizer))) {
|
||||||
|
if (!att.Values.Contains(value)) {
|
||||||
|
throw new InvalidSettingsException("{0} contains value {1} not in required set [{2}]", prop.Name, value, string.Join(", ", att.Values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var att in prop.GetCustomAttributes<ForbiddenSettingAttribute>().Where(att => att.HasRandomizer(randomizer))) {
|
||||||
|
if (att.Values.Contains(value)) {
|
||||||
|
throw new InvalidSettingsException("{0} contains forbidden value {1}", prop.Name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SettingsLookupException : Exception {
|
public class SettingsLookupException : Exception {
|
||||||
public SettingsLookupException(string message, params object?[] args) : base(string.Format(message, args)) { }
|
public SettingsLookupException(string message, params object?[] args) : base(string.Format(message, args)) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class InvalidSettingsException : Exception {
|
||||||
|
public InvalidSettingsException(string message, params object?[] args) : base(string.Format(message, args)) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"ALttPRandomizer": {
|
"ALttPRandomizer": {
|
||||||
"baserom": "/randomizer/alttp.sfc",
|
"baserom": "/randomizer/alttp.sfc",
|
||||||
"pythonPath": "/usr/bin/python3",
|
"pythonPath": "/usr/bin/python3",
|
||||||
"randomizerPath": "/randomizer",
|
"flipsPath": "/flips/flips",
|
||||||
"allowedCors": [
|
"allowedCors": [
|
||||||
"https://new.alttpr.gwaa.kiwi",
|
"https://new.alttpr.gwaa.kiwi",
|
||||||
"http://localhost:8082"
|
"http://localhost:8082"
|
||||||
@@ -10,6 +10,10 @@
|
|||||||
"azureSettings": {
|
"azureSettings": {
|
||||||
"clientId": "a48d5ae1-fa0a-4e33-9586-18c0eca0a28c",
|
"clientId": "a48d5ae1-fa0a-4e33-9586-18c0eca0a28c",
|
||||||
"blobstoreEndpoint": "https://alttprstorage.blob.core.windows.net/seeds"
|
"blobstoreEndpoint": "https://alttprstorage.blob.core.windows.net/seeds"
|
||||||
|
},
|
||||||
|
"randomizerPaths": {
|
||||||
|
"base": "/randomizer",
|
||||||
|
"apr2025": "/apr2025_randomizer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
|
|||||||
1
Apr2025Randomizer
Submodule
1
Apr2025Randomizer
Submodule
Submodule Apr2025Randomizer added at 1d84a6b348
@@ -12,7 +12,10 @@ FROM mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0 AS final
|
|||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
EXPOSE 8081
|
EXPOSE 8081
|
||||||
|
|
||||||
RUN tdnf install -y python3
|
RUN tdnf install -y python3 wget unzip
|
||||||
|
RUN wget https://github.com/Alcaro/Flips/releases/download/v198/flips-linux.zip
|
||||||
|
RUN unzip flips-linux.zip -d /flips
|
||||||
|
RUN rm flips-linux.zip
|
||||||
|
|
||||||
RUN mkdir -p /randomizer/data
|
RUN mkdir -p /randomizer/data
|
||||||
RUN touch /randomizer/data/base2current.json
|
RUN touch /randomizer/data/base2current.json
|
||||||
@@ -30,6 +33,9 @@ RUN python3 -m pip install -r requirements.txt
|
|||||||
|
|
||||||
COPY BaseRandomizer/ .
|
COPY BaseRandomizer/ .
|
||||||
|
|
||||||
|
WORKDIR /apr2025_randomizer
|
||||||
|
COPY Apr2025Randomizer/ .
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=build /app/publish .
|
COPY --from=build /app/publish .
|
||||||
COPY ALttPRandomizer/appsettings.Docker.json appsettings.json
|
COPY ALttPRandomizer/appsettings.Docker.json appsettings.json
|
||||||
|
|||||||
Reference in New Issue
Block a user