From bfa6ac8fcb37a7e98e449028a091150682e0f0d6 Mon Sep 17 00:00:00 2001 From: jonko0493 Date: Mon, 11 Nov 2024 19:58:33 -0800 Subject: [PATCH 1/6] Handle nullables in SerialLoops.Lib --- .editorconfig | 1 + src/SerialLoops.Lib/Build.cs | 24 +- src/SerialLoops.Lib/Config.cs | 48 +- .../Factories/ConfigFactory.cs | 22 +- .../Factories/IConfigFactory.cs | 2 +- src/SerialLoops.Lib/Flags.cs | 31 +- src/SerialLoops.Lib/Hacks/AsmHack.cs | 106 ++-- src/SerialLoops.Lib/IO.cs | 8 +- src/SerialLoops.Lib/Items/BackgroundItem.cs | 73 ++- .../Items/BackgroundMusicItem.cs | 20 +- src/SerialLoops.Lib/Items/CharacterItem.cs | 34 +- .../Items/CharacterSpriteItem.cs | 10 +- src/SerialLoops.Lib/Items/ChibiItem.cs | 10 +- src/SerialLoops.Lib/Items/Item.cs | 14 +- src/SerialLoops.Lib/Items/ItemDescription.cs | 40 +- src/SerialLoops.Lib/Items/ItemItem.cs | 17 +- src/SerialLoops.Lib/Items/LayoutItem.cs | 4 +- src/SerialLoops.Lib/Items/MapItem.cs | 30 +- src/SerialLoops.Lib/Items/PlaceItem.cs | 6 +- src/SerialLoops.Lib/Items/PuzzleItem.cs | 6 +- src/SerialLoops.Lib/Items/ScenarioItem.cs | 10 +- src/SerialLoops.Lib/Items/ScriptItem.cs | 481 +++++++++--------- src/SerialLoops.Lib/Items/SfxItem.cs | 4 +- .../Items/SystemTextureItem.cs | 4 +- src/SerialLoops.Lib/Items/TopicItem.cs | 8 +- src/SerialLoops.Lib/Items/VoicedLineItem.cs | 34 +- .../Logging/LoggerNullException.cs | 7 +- src/SerialLoops.Lib/Project.cs | 339 ++++++------ src/SerialLoops.Lib/ProjectSettings.cs | 8 +- src/SerialLoops.Lib/ProjectsCache.cs | 42 +- .../SaveFile/SaveFilePreview.cs | 10 +- .../Script/Parameters/BgScriptParameter.cs | 17 +- .../BgScrollDirectionScriptParameter.cs | 14 +- .../Parameters/BgmModeScriptParameter.cs | 13 +- .../Script/Parameters/BgmScriptParameter.cs | 13 +- .../Script/Parameters/BoolScriptParameter.cs | 4 +- .../Parameters/ChessFileScriptParameter.cs | 14 +- .../Parameters/ChessPieceScriptParameter.cs | 13 +- .../Parameters/ChessSpaceScriptParameter.cs | 13 +- .../Parameters/ChibiEmoteScriptParameter.cs | 13 +- .../ChibiEnterExitScriptParameter.cs | 14 +- .../Script/Parameters/ChibiScriptParameter.cs | 13 +- .../ColorMonochromeScriptParameter.cs | 14 +- .../Script/Parameters/ColorScriptParameter.cs | 13 +- .../Parameters/ConditionalScriptParameter.cs | 13 +- .../DialoguePropertyScriptParameter.cs | 14 +- .../Parameters/DialogueScriptParameter.cs | 69 ++- .../EpisodeHeaderScriptParameter.cs | 8 +- .../Script/Parameters/FlagScriptParameter.cs | 13 +- .../FriendshipLevelScriptParameter.cs | 14 +- .../Parameters/ItemLocationScriptParameter.cs | 4 +- .../Script/Parameters/ItemScriptParameter.cs | 4 +- .../ItemTransitionScriptParameter.cs | 4 +- .../Script/Parameters/MapScriptParameter.cs | 13 +- .../Parameters/OptionScriptParameter.cs | 14 +- .../PaletteEffectScriptParameter.cs | 14 +- .../Script/Parameters/PlaceScriptParameter.cs | 4 +- .../Parameters/ScreenScriptParameter.cs | 13 +- .../Script/Parameters/ScriptParameter.cs | 16 +- .../ScriptSectionScriptParameter.cs | 14 +- .../Parameters/SfxModeScriptParameter.cs | 13 +- .../Script/Parameters/SfxScriptParameter.cs | 13 +- .../Script/Parameters/ShortScriptParameter.cs | 13 +- .../SpriteEntranceScriptParameter.cs | 14 +- .../Parameters/SpriteExitScriptParameter.cs | 14 +- .../Parameters/SpriteScriptParameter.cs | 14 +- .../Parameters/SpriteShakeScriptParameter.cs | 14 +- .../TextEntranceEffectScriptParameter.cs | 14 +- .../Script/Parameters/TopicScriptParameter.cs | 13 +- .../Parameters/TransitionScriptParameter.cs | 13 +- .../Parameters/VoicedLineScriptParameter.cs | 14 +- .../Script/ScriptItemCommand.cs | 62 +-- src/SerialLoops.Lib/Script/ScriptPreview.cs | 22 +- .../Script/ScriptSectionEdge.cs | 8 +- src/SerialLoops.Lib/Script/ScriptTemplate.cs | 68 ++- src/SerialLoops.Lib/SearchQuery.cs | 4 +- src/SerialLoops.Lib/SerialLoops.Lib.csproj | 2 +- src/SerialLoops.Lib/Util/Extensions.cs | 14 +- src/SerialLoops.Lib/Util/GraphicInfo.cs | 8 +- .../Util/WaveformRenderer/MaxPeakProvider.cs | 6 +- .../Util/WaveformRenderer/PeakProvider.cs | 6 +- .../WaveFormRendererSettings.cs | 19 +- src/SerialLoops/Assets/Strings.Designer.cs | 9 + src/SerialLoops/Assets/Strings.resx | 3 + src/SerialLoops/SerialLoops.csproj | 2 +- src/SerialLoops/Utility/LoopyLogger.cs | 4 +- .../Dialogs/AsmHacksDialogViewModel.cs | 4 +- .../Dialogs/PreferencesDialogViewModel.cs | 2 +- .../Dialogs/ProjectCreationDialogViewModel.cs | 12 +- .../Dialogs/ProjectSettingsDialogViewModel.cs | 4 +- .../Dialogs/UpdateAvailableDialogViewModel.cs | 2 +- .../ViewModels/MainWindowViewModel.cs | 2 +- .../ConfigFactoryMock.cs | 6 +- .../NoProjectRequiredTests.cs | 4 +- .../ProjectRequiredTests.cs | 8 +- .../SerialLoops.Tests.Headless.csproj | 2 +- 96 files changed, 1115 insertions(+), 1169 deletions(-) diff --git a/.editorconfig b/.editorconfig index 31f016de..62741cf3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -88,6 +88,7 @@ csharp_prefer_static_local_function = true:suggestion csharp_prefer_simple_using_statement = false:none csharp_style_prefer_switch_expression = true:suggestion dotnet_style_readonly_field = true:suggestion +csharp_object_creation_when_type_evident = target_typed # Expression-level preferences dotnet_style_object_initializer = true:suggestion diff --git a/src/SerialLoops.Lib/Build.cs b/src/SerialLoops.Lib/Build.cs index 0a29fff3..a0c595ea 100644 --- a/src/SerialLoops.Lib/Build.cs +++ b/src/SerialLoops.Lib/Build.cs @@ -20,7 +20,7 @@ namespace SerialLoops.Lib; public static class Build { - public static bool BuildIterative(Project project, Config config, ILogger log, IProgressTracker tracker) + public static bool BuildIterative(Project project, Config? config, ILogger log, IProgressTracker tracker) { bool result = DoBuild(project.IterativeDirectory, project, config, log, tracker); CopyToArchivesToIterativeOriginal(Path.Combine(project.IterativeDirectory, "rom", "data"), @@ -32,7 +32,7 @@ public static bool BuildIterative(Project project, Config config, ILogger log, I return result; } - public static bool BuildBase(Project project, Config config, ILogger log, IProgressTracker tracker) + public static bool BuildBase(Project project, Config? config, ILogger log, IProgressTracker tracker) { bool result = DoBuild(project.BaseDirectory, project, config, log, tracker); CopyToArchivesToIterativeOriginal(Path.Combine(project.BaseDirectory, "rom", "data"), @@ -66,7 +66,7 @@ private static void CleanIterative(Project project, ILogger log, IProgressTracke } } - private static bool DoBuild(string directory, Project project, Config config, ILogger log, IProgressTracker tracker) + private static bool DoBuild(string directory, Project project, Config? config, ILogger log, IProgressTracker tracker) { // Export includes StringBuilder commandsIncSb = new(); @@ -128,7 +128,7 @@ private static bool DoBuild(string directory, Project project, Config config, IL } else if (Path.GetExtension(file).Equals(".s", StringComparison.OrdinalIgnoreCase)) { - if (string.IsNullOrEmpty(config.DevkitArmPath)) + if (string.IsNullOrEmpty(config?.DevkitArmPath)) { log.LogError("DevkitARM must be supplied in order to build!"); return false; @@ -186,8 +186,8 @@ private static bool DoBuild(string directory, Project project, Config config, IL tracker.Focus("Writing NitroPacker Project File", 1); try { - File.WriteAllBytes(ndsProjectFile, project.Settings.File.Write()); - } + File.WriteAllBytes(ndsProjectFile, project.Settings!.File.Write()); + } catch (IOException exc) { log.LogException("Failed to write NitroPacker NDS project file to disk", exc); @@ -238,7 +238,7 @@ private static void ReplaceSingleGraphicsFile(ArchiveFile grp, str grpFile.InitializeFontFile(); } - GraphicInfo graphicInfo = JsonSerializer.Deserialize(File.ReadAllText(Path.Combine(Path.GetDirectoryName(filePath), $"{Path.GetFileNameWithoutExtension(filePath)}.gi"))); + GraphicInfo graphicInfo = JsonSerializer.Deserialize(File.ReadAllText(Path.Combine(Path.GetDirectoryName(filePath)!, $"{Path.GetFileNameWithoutExtension(filePath)}.gi")))!; graphicInfo.Set(grpFile); grpFile.SetImage(filePath, newSize: true); @@ -315,8 +315,8 @@ private static (string, string) CompileSourceFile(string filePath, string devkit { string exeExtension = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty; - string objFile = $"{Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath))}.o"; - string binFile = $"{Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath))}.bin"; + string objFile = $"{Path.Combine(Path.GetDirectoryName(filePath)!, Path.GetFileNameWithoutExtension(filePath))}.o"; + string binFile = $"{Path.Combine(Path.GetDirectoryName(filePath)!, Path.GetFileNameWithoutExtension(filePath))}.bin"; ProcessStartInfo gccStartInfo = new(Path.Combine(devkitArm, "bin", $"arm-none-eabi-gcc{exeExtension}"), $"-c -nostdlib -static \"{filePath}\" -o \"{objFile}") { CreateNoWindow = true, @@ -331,8 +331,8 @@ private static (string, string) CompileSourceFile(string filePath, string devkit } log.Log($"Compiling '{filePath}' to '{objFile}' with '{gccStartInfo.FileName}'..."); Process gcc = new() { StartInfo = gccStartInfo }; - gcc.OutputDataReceived += (object sender, DataReceivedEventArgs e) => log.Log(e.Data); - gcc.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => log.LogWarning(e.Data); + gcc.OutputDataReceived += (_, e) => log.Log(e.Data); + gcc.ErrorDataReceived += (_, e) => log.LogWarning(e.Data); gcc.Start(); gcc.WaitForExit(); Task.Delay(50); // ensures process is actually complete @@ -417,4 +417,4 @@ private static void ReplaceSingleBinaryFile(ArchiveFile archive, s log.LogException(string.Format(localize("Failed replacing animation file {0} in grp.bin with file '{1}'"), index, filePath), ex); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Config.cs b/src/SerialLoops.Lib/Config.cs index 30315092..60f20f2d 100644 --- a/src/SerialLoops.Lib/Config.cs +++ b/src/SerialLoops.Lib/Config.cs @@ -16,8 +16,8 @@ namespace SerialLoops.Lib; public class Config { [JsonIgnore] - public string ConfigPath { get; set; } - public string UserDirectory { get; set; } + public string ConfigPath { get; set; } = string.Empty; + public string UserDirectory { get; set; } = string.Empty; [JsonIgnore] public string ProjectsDirectory => Path.Combine(UserDirectory, "Projects"); [JsonIgnore] @@ -28,22 +28,24 @@ public class Config public string HacksDirectory => Path.Combine(UserDirectory, "Hacks"); [JsonIgnore] public string ScriptTemplatesDirectory => Path.Combine(UserDirectory, "ScriptTemplates"); + [JsonIgnore] - public ObservableCollection Hacks { get; set; } + public ObservableCollection Hacks { get; set; } = []; + [JsonIgnore] - public ObservableCollection ScriptTemplates { get; set; } - public string CurrentCultureName { get; set; } - public string DevkitArmPath { get; set; } + public ObservableCollection ScriptTemplates { get; set; } = []; + public string CurrentCultureName { get; set; } = string.Empty; + public string DevkitArmPath { get; set; } = string.Empty; public bool UseDocker { get; set; } - public string DevkitArmDockerTag { get; set; } - public string EmulatorFlatpak { get; set; } - public string EmulatorPath { get; set; } + public string DevkitArmDockerTag { get; set; } = string.Empty; + public string EmulatorFlatpak { get; set; } = string.Empty; + public string EmulatorPath { get; set; } = string.Empty; public bool AutoReopenLastProject { get; set; } public bool RememberProjectWorkspace { get; set; } public bool RemoveMissingProjects { get; set; } public bool CheckForUpdates { get; set; } public bool PreReleaseChannel { get; set; } - public string DisplayFont { get; set; } + public string DisplayFont { get; set; } = string.Empty; public void Save(ILogger log) { @@ -56,14 +58,8 @@ public void ValidateConfig(Func localize, ILogger log) { log.LogError(localize("devkitARM is not detected at the default or specified install location. Please set devkitARM path.")); } - if (CurrentCultureName is null) - { - CurrentCultureName = CultureInfo.CurrentCulture.Name; - } - else - { - CultureInfo.CurrentCulture = new(CurrentCultureName); - } + + CultureInfo.CurrentCulture = new(CurrentCultureName); } public void InitializeHacks(ILogger log) @@ -75,20 +71,20 @@ public void InitializeHacks(ILogger log) File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sources", "hacks.json"), Path.Combine(HacksDirectory, "hacks.json")); } - Hacks = JsonSerializer.Deserialize>(File.ReadAllText(Path.Combine(HacksDirectory, "hacks.json"))); + Hacks = JsonSerializer.Deserialize>(File.ReadAllText(Path.Combine(HacksDirectory, "hacks.json"))) ?? []; // Pull in new hacks in case we've updated the program with more - List builtinHacks = JsonSerializer.Deserialize>(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sources", "hacks.json"))); - IEnumerable missingHacks = builtinHacks.Where(h => !Hacks.Contains(h)); - if (missingHacks.Any()) + List builtinHacks = JsonSerializer.Deserialize>(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sources", "hacks.json"))) ?? []; + AsmHack[] missingHacks = [.. builtinHacks.Where(h => !Hacks.Contains(h))]; + if (missingHacks.Length != 0) { IO.CopyFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sources", "Hacks"), HacksDirectory, log); Hacks.AddRange(missingHacks); File.WriteAllText(Path.Combine(HacksDirectory, "hacks.json"), JsonSerializer.Serialize(Hacks)); } - IEnumerable updatedHacks = builtinHacks.Where(h => !Hacks.FirstOrDefault(o => h.Name == o.Name)?.DeepEquals(h) ?? false); - if (updatedHacks.Any()) + AsmHack[] updatedHacks = [.. builtinHacks.Where(h => !Hacks.FirstOrDefault(o => h.Name == o.Name)?.DeepEquals(h) ?? false)]; + if (updatedHacks.Length != 0) { IO.CopyFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sources", "Hacks"), HacksDirectory, log); foreach (AsmHack updatedHack in updatedHacks) @@ -123,7 +119,7 @@ internal void InitializeScriptTemplates(Func localize, ILogger l { try { - templates.Add(JsonSerializer.Deserialize(File.ReadAllText(scriptTemplateFile))); + templates.Add(JsonSerializer.Deserialize(File.ReadAllText(scriptTemplateFile))!); } catch (Exception ex) { @@ -132,4 +128,4 @@ internal void InitializeScriptTemplates(Func localize, ILogger l } ScriptTemplates = new(templates); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Factories/ConfigFactory.cs b/src/SerialLoops.Lib/Factories/ConfigFactory.cs index 275c2c28..7784debe 100644 --- a/src/SerialLoops.Lib/Factories/ConfigFactory.cs +++ b/src/SerialLoops.Lib/Factories/ConfigFactory.cs @@ -18,7 +18,7 @@ namespace SerialLoops.Lib.Factories; // "You've forgotten the mocks." public class ConfigFactory : IConfigFactory { - public Config LoadConfig(Func localize, ILogger log) + public Config? LoadConfig(Func localize, ILogger log) { string configJson = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SerialLoops", "config.json"); @@ -39,7 +39,12 @@ public Config LoadConfig(Func localize, ILogger log) try { - Config config = JsonSerializer.Deserialize(File.ReadAllText(configJson)); + Config? config = JsonSerializer.Deserialize(File.ReadAllText(configJson)); + if (config is null) + { + log.LogError(localize("Failed to parse config.json; null value returned!")); + return HandleDefaultConfig(configJson, localize, log); + } config.ValidateConfig(localize, log); config.ConfigPath = configJson; config.InitializeHacks(log); @@ -49,10 +54,7 @@ public Config LoadConfig(Func localize, ILogger log) catch (JsonException exc) { log.LogException(localize("Exception occurred while parsing config.json!"), exc); - Config defaultConfig = GetDefault(log); - defaultConfig.ValidateConfig(localize, log); - IO.WriteStringFile(configJson, JsonSerializer.Serialize(defaultConfig), log); - return defaultConfig; + return HandleDefaultConfig(configJson, localize, log); } } @@ -141,4 +143,12 @@ public static Config GetDefault(ILogger log) PreReleaseChannel = false, }; } + + private Config? HandleDefaultConfig(string configJson, Func localize, ILogger log) + { + Config? defaultConfig = GetDefault(log); + defaultConfig.ValidateConfig(localize, log); + IO.WriteStringFile(configJson, JsonSerializer.Serialize(defaultConfig), log); + return defaultConfig; + } } diff --git a/src/SerialLoops.Lib/Factories/IConfigFactory.cs b/src/SerialLoops.Lib/Factories/IConfigFactory.cs index 4d1238eb..9e6988ea 100644 --- a/src/SerialLoops.Lib/Factories/IConfigFactory.cs +++ b/src/SerialLoops.Lib/Factories/IConfigFactory.cs @@ -5,5 +5,5 @@ namespace SerialLoops.Lib.Factories; public interface IConfigFactory { - public Config LoadConfig(Func localize, ILogger log); + public Config? LoadConfig(Func localize, ILogger log); } \ No newline at end of file diff --git a/src/SerialLoops.Lib/Flags.cs b/src/SerialLoops.Lib/Flags.cs index 3cb315e8..1e90b36b 100644 --- a/src/SerialLoops.Lib/Flags.cs +++ b/src/SerialLoops.Lib/Flags.cs @@ -11,42 +11,47 @@ namespace SerialLoops.Lib; public class Flags { public const int NUM_FLAGS = 5120; - public static readonly Dictionary _names = JsonSerializer.Deserialize>(File.ReadAllText(Extensions.GetLocalizedFilePath(Path.Combine("Defaults", "DefaultFlags"), "json"))); + public static readonly Dictionary? _names = JsonSerializer.Deserialize>(File.ReadAllText(Extensions.GetLocalizedFilePath(Path.Combine("Defaults", "DefaultFlags"), "json"))); public static string GetFlagNickname(int flag, Project project) { - if (_names.TryGetValue(flag, out string value)) + if (_names is null) + { + return string.Empty; + } + + if (_names.TryGetValue(flag, out string? value)) { return value; } - TopicItem topic = (TopicItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry.Id == flag); + TopicItem? topic = (TopicItem?)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry?.Id == flag); if (topic is not null) { return string.Format(project.Localize("{0} Obtained"), topic.DisplayName); } - TopicItem readTopic = (TopicItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic && - ((((TopicItem)i).TopicEntry.Type == TopicType.Main && ((TopicItem)i).HiddenMainTopic is not null && ((TopicItem)i).TopicEntry.Id + 3463 == flag) || - (((TopicItem)i).TopicEntry.Type != TopicType.Main && ((TopicItem)i).TopicEntry.Id + 3451 == flag))); + TopicItem? readTopic = (TopicItem?)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic && + ((((TopicItem)i).TopicEntry?.Type == TopicType.Main && ((TopicItem)i).HiddenMainTopic is not null && ((TopicItem)i).TopicEntry?.Id + 3463 == flag) || + (((TopicItem)i).TopicEntry?.Type != TopicType.Main && ((TopicItem)i).TopicEntry?.Id + 3451 == flag))); if (readTopic is not null) { return string.Format(project.Localize("{0} Watched in Extras"), readTopic.DisplayName); } - BackgroundMusicItem bgm = (BackgroundMusicItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.BGM && ((BackgroundMusicItem)i).Flag == flag); + BackgroundMusicItem? bgm = (BackgroundMusicItem?)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.BGM && ((BackgroundMusicItem)i).Flag == flag); if (bgm is not null) { return string.Format(project.Localize("Listened to {0}"), bgm.DisplayName); } - BackgroundItem bg = (BackgroundItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Flag == flag); + BackgroundItem? bg = (BackgroundItem?)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Flag == flag); if (bg is not null && flag > 0) { return string.Format(project.Localize("{0} ({1}) Seen"), bg.CgName, bg.DisplayName); } - GroupSelectionItem groupSelection = (GroupSelectionItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Group_Selection && + GroupSelectionItem? groupSelection = (GroupSelectionItem?)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Group_Selection && ((GroupSelectionItem)i).Selection.Activities.Any(a => a?.Routes.Any(r => r?.Flag == flag) ?? false)); if (groupSelection is not null) { @@ -54,13 +59,13 @@ public static string GetFlagNickname(int flag, Project project) return string.Format(project.Localize("Route \"{0}\" Completed"), route.Title.GetSubstitutedString(project)); } - ScriptItem script = (ScriptItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Script && - flag >= ((ScriptItem)i).StartReadFlag && flag < ((ScriptItem)i).StartReadFlag + ((ScriptItem)i).Event.ScriptSections.Count); + ScriptItem? script = (ScriptItem?)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Script && + flag >= ((ScriptItem)i).StartReadFlag && flag < ((ScriptItem)i).StartReadFlag + ((ScriptItem)i).Event!.ScriptSections.Count); if (script is not null) { - return string.Format(project.Localize("Script {0} Section {1} Completed"), script.DisplayName, script.Event.ScriptSections[flag - script.StartReadFlag].Name); + return string.Format(project.Localize("Script {0} Section {1} Completed"), script.DisplayName, script.Event?.ScriptSections[flag - script.StartReadFlag].Name); } return $"F{flag:D2}"; } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Hacks/AsmHack.cs b/src/SerialLoops.Lib/Hacks/AsmHack.cs index 6ee9d96e..038a5224 100644 --- a/src/SerialLoops.Lib/Hacks/AsmHack.cs +++ b/src/SerialLoops.Lib/Hacks/AsmHack.cs @@ -10,10 +10,10 @@ namespace SerialLoops.Lib.Hacks; public class AsmHack : ReactiveObject { - public string Name { get; set; } - public string Description { get; set; } - public List InjectionSites { get; set; } - public List Files { get; set; } + public string? Name { get; set; } + public string? Description { get; set; } + public List? InjectionSites { get; set; } + public List? Files { get; set; } [JsonIgnore] public bool ValueChanged { get; set; } [JsonIgnore] @@ -22,9 +22,9 @@ public class AsmHack : ReactiveObject public bool Applied(Project project) { - foreach (InjectionSite site in InjectionSites) + foreach (InjectionSite site in InjectionSites!) { - if (site.Code.Equals("ARM9")) + if (site.Code!.Equals("ARM9")) { using FileStream arm9 = File.OpenRead(Path.Combine(project.IterativeDirectory, "rom", "arm9.bin")); arm9.Seek(site.Offset + 3, SeekOrigin.Begin); @@ -47,7 +47,7 @@ public bool Applied(Project project) return false; } - public void Apply(Project project, Config config, Dictionary selectedParameters, ILogger log, bool forceApplication = false) + public void Apply(Project project, Config? config, Dictionary selectedParameters, ILogger log, bool forceApplication = false) { if (Applied(project) && !forceApplication) { @@ -55,17 +55,17 @@ public void Apply(Project project, Config config, Dictionary Parameter.Values[Selection].Value; + public string Value => Parameter?.Values?[Selection].Value ?? string.Empty; } public class HackParameter { - public string Name { get; set; } - public string DescriptiveName { get; set; } - public HackParameterValue[] Values { get; set; } + public string? Name { get; set; } + public string? DescriptiveName { get; set; } + public HackParameterValue[]? Values { get; set; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { + if (obj is null) + { + return false; + } return (((HackParameter)obj).Name?.Equals(Name) ?? false) && (((HackParameter)obj).DescriptiveName?.Equals(DescriptiveName) ?? false) && (((HackParameter)obj).Values?.Equals(Values) ?? false); } public override int GetHashCode() { - return Name.GetHashCode(); + return Name!.GetHashCode(); } } public class HackParameterValue { - public string Name { get; set; } - public string Value { get; set; } + public string? Name { get; set; } + public string? Value { get; set; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { + if (obj is null) + { + return false; + } return (((HackParameterValue)obj).Name?.Equals(Name) ?? false) && (((HackParameterValue)obj).Value?.Equals(Value) ?? false); } public override int GetHashCode() { - return Name.GetHashCode(); + return Name!.GetHashCode(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/IO.cs b/src/SerialLoops.Lib/IO.cs index 57e94d4f..59bf4fd0 100644 --- a/src/SerialLoops.Lib/IO.cs +++ b/src/SerialLoops.Lib/IO.cs @@ -146,13 +146,13 @@ public static void CopyFileToDirectories(Project project, string sourceFile, str string iterativeFile = Path.Combine(project.IterativeDirectory, relativePath); try { - if (!Directory.Exists(Path.GetDirectoryName(baseFile))) + if (!string.IsNullOrEmpty(baseFile) && !Directory.Exists(Path.GetDirectoryName(baseFile))) { - Directory.CreateDirectory(Path.GetDirectoryName(baseFile)); + Directory.CreateDirectory(Path.GetDirectoryName(baseFile)!); } if (!Directory.Exists(Path.GetDirectoryName(iterativeFile))) { - Directory.CreateDirectory(Path.GetDirectoryName(iterativeFile)); + Directory.CreateDirectory(Path.GetDirectoryName(iterativeFile)!); } File.Copy(sourceFile, baseFile, true); @@ -274,4 +274,4 @@ public static bool WriteBinaryFile(string file, byte[] bytes, ILogger log) return false; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/BackgroundItem.cs b/src/SerialLoops.Lib/Items/BackgroundItem.cs index 0d5e19b4..0e3d5d2d 100644 --- a/src/SerialLoops.Lib/Items/BackgroundItem.cs +++ b/src/SerialLoops.Lib/Items/BackgroundItem.cs @@ -14,24 +14,21 @@ namespace SerialLoops.Lib.Items; public class BackgroundItem : Item, IPreviewableGraphic { public int Id { get; set; } - public GraphicsFile Graphic1 { get; set; } - public GraphicsFile Graphic2 { get; set; } + public GraphicsFile? Graphic1 { get; set; } + public GraphicsFile? Graphic2 { get; set; } public BgType BackgroundType { get; set; } - public string CgName { get; set; } + public string? CgName { get; set; } public int Flag { get; set; } public short ExtrasShort { get; set; } public byte ExtrasByte { get; set; } - public BackgroundItem(string name) : base(name, ItemType.Background) - { - } public BackgroundItem(string name, int id, BgTableEntry entry, Project project) : base(name, ItemType.Background) { Id = id; BackgroundType = entry.Type; - Graphic1 = project.Grp.GetFileByIndex(entry.BgIndex1); + Graphic1 = project.Grp!.GetFileByIndex(entry.BgIndex1); Graphic2 = project.Grp.GetFileByIndex(entry.BgIndex2); // can be null if type is SINGLE_TEX - CgExtraData cgEntry = project.Extra.Cgs.AsParallel().FirstOrDefault(c => c.BgId == Id); + CgExtraData? cgEntry = project.Extra!.Cgs.AsParallel().FirstOrDefault(c => c.BgId == Id); if (cgEntry is not null) { CgName = cgEntry?.Name?.GetSubstitutedString(project); @@ -45,14 +42,19 @@ public override void Refresh(Project project, ILogger log) { } - public SKBitmap GetBackground() + public SKBitmap? GetBackground() { if (BackgroundType == BgType.TEX_CG_SINGLE) { - return Graphic1.GetImage(); + return Graphic1?.GetImage(); } - else if (BackgroundType == BgType.TEX_CG_DUAL_SCREEN) + + if (BackgroundType == BgType.TEX_CG_DUAL_SCREEN) { + if (Graphic1 is null || Graphic2 is null) + { + return null; + } SKBitmap bitmap = new(Graphic1.Width, Graphic1.Height + Graphic2.Height); SKCanvas canvas = new(bitmap); @@ -78,12 +80,18 @@ public SKBitmap GetBackground() return bitmap; } - else if (BackgroundType == BgType.KINETIC_SCREEN) + + if (BackgroundType == BgType.KINETIC_SCREEN) { - return Graphic2.GetScreenImage(Graphic1); + return Graphic2?.GetScreenImage(Graphic1); } else { + if (Graphic1 is null || Graphic2 is null) + { + return null; + } + SKBitmap bitmap = new(Graphic1.Width, Graphic1.Height + Graphic2.Height); SKCanvas canvas = new(bitmap); @@ -102,6 +110,11 @@ public bool SetBackground(SKBitmap image, IProgressTracker tracker, ILogger log, switch (BackgroundType) { case BgType.KINETIC_SCREEN: + if (Graphic2 is null) + { + log.LogError(localize("Failed to replace screen image: graphic 2 was null!")); + return false; + } tracker.Focus(localize("Setting screen image..."), 1); if (Graphic2.SetScreenImage(image, quantizer, Graphic1, suppressErrors: true) < 0) { @@ -112,6 +125,11 @@ public bool SetBackground(SKBitmap image, IProgressTracker tracker, ILogger log, break; case BgType.TEX_CG_SINGLE: + if (Graphic1 is null) + { + log.LogError(localize("Failed to replace CG single image: graphic 1 was null!")); + return false; + } tracker.Focus(localize("Setting CG single image..."), 1); List singlePalette = Helpers.GetPaletteFromImage(image, transparentIndex == 0 ? 255 : 256, log); if (singlePalette.Count == 255) @@ -124,6 +142,11 @@ public bool SetBackground(SKBitmap image, IProgressTracker tracker, ILogger log, break; case BgType.TEX_CG_DUAL_SCREEN: + if (Graphic1 is null || Graphic2 is null) + { + log.LogError(localize("Failed to replace dual screen CG image: graphics were null!")); + return false; + } SKBitmap newTextureBitmap = new(Graphic1.Width, Graphic1.Height); SKBitmap newTileBitmap = new(64, Graphic2.Height * Graphic2.Width / 64); SKBitmap tileSource = new(image.Width, image.Height - Graphic1.Height); @@ -172,6 +195,11 @@ public bool SetBackground(SKBitmap image, IProgressTracker tracker, ILogger log, break; default: + if (Graphic1 is null || Graphic2 is null) + { + log.LogError(localize("Failed to replace background image: graphics were null!")); + return false; + } SKBitmap newGraphic1 = new(Graphic1.Width, Graphic1.Height); SKBitmap newGraphic2 = new(Graphic2.Width, Graphic2.Height); @@ -208,6 +236,11 @@ public bool SetBackground(SKBitmap image, IProgressTracker tracker, ILogger log, public void Write(Project project, ILogger log) { + if (Graphic1 is null) + { + log.LogError("Failed to write BG image to disk: graphic 1 was null!"); + return; + } using MemoryStream grp1Stream = new(); Graphic1.GetImage().Encode(grp1Stream, SKEncodedImageFormat.Png, 1); IO.WriteBinaryFile(Path.Combine("assets", "graphics", $"{Graphic1.Index:X3}.png"), grp1Stream.ToArray(), project, log); @@ -215,6 +248,11 @@ public void Write(Project project, ILogger log) if (BackgroundType != BgType.KINETIC_SCREEN && BackgroundType != BgType.TEX_CG_SINGLE) { + if (Graphic2 is null) + { + log.LogError("Failed to write BG image to disk: graphic 2 was null!"); + return; + } using MemoryStream grp2Stream = new(); Graphic2.GetImage().Encode(grp2Stream, SKEncodedImageFormat.Png, 1); IO.WriteBinaryFile(Path.Combine("assets", "graphics", $"{Graphic2.Index:X3}.png"), grp2Stream.ToArray(), project, log); @@ -222,12 +260,17 @@ public void Write(Project project, ILogger log) } else if (BackgroundType == BgType.KINETIC_SCREEN) { + if (Graphic2 is null) + { + log.LogError("Failed to write KBG image to disk: graphic 2 was null!"); + return; + } IO.WriteStringFile(Path.Combine("assets", "graphics", $"{Graphic2.Index:X3}.scr"), JsonSerializer.Serialize(Graphic2.ScreenData), project, log); } } public SKBitmap GetPreview(Project project) { - return GetBackground(); + return GetBackground() ?? new(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/BackgroundMusicItem.cs b/src/SerialLoops.Lib/Items/BackgroundMusicItem.cs index 7825a19c..e21b6a68 100644 --- a/src/SerialLoops.Lib/Items/BackgroundMusicItem.cs +++ b/src/SerialLoops.Lib/Items/BackgroundMusicItem.cs @@ -21,14 +21,14 @@ public class BackgroundMusicItem : Item, ISoundItem public int Index { get; set; } public string BgmName { get; set; } public short? Flag { get; set; } - public string CachedWaveFile { get; set; } + public string? CachedWaveFile { get; set; } public BackgroundMusicItem(string bgmFile, int index, Project project) : base(Path.GetFileNameWithoutExtension(bgmFile), ItemType.BGM) { BgmFile = Path.GetRelativePath(project.IterativeDirectory, bgmFile); _bgmFile = bgmFile; Index = index; - BgmName = project.Extra.Bgms.FirstOrDefault(b => b.Index == Index)?.Name?.GetSubstitutedString(project) ?? ""; + BgmName = project.Extra!.Bgms.FirstOrDefault(b => b.Index == Index)?.Name?.GetSubstitutedString(project) ?? ""; Flag = project.Extra.Bgms.FirstOrDefault(b => b.Index == Index)?.Flag; DisplayName = string.IsNullOrEmpty(BgmName) ? Name : $"{Name} - {BgmName}"; CanRename = string.IsNullOrEmpty(BgmName); @@ -46,7 +46,7 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire // So we just convert to WAV AOT if (Path.GetExtension(audioFile).Equals(".mp3", StringComparison.OrdinalIgnoreCase)) { - string mp3ConvertedFile = Path.Combine(Path.GetDirectoryName(bgmCachedFile), $"{Path.GetFileNameWithoutExtension(bgmCachedFile)}-converted.wav"); + string mp3ConvertedFile = Path.Combine(Path.GetDirectoryName(bgmCachedFile)!, $"{Path.GetFileNameWithoutExtension(bgmCachedFile)}-converted.wav"); log.Log($"Converting {audioFile} to WAV..."); tracker.Focus("Converting from MP3...", 1); using Mp3FileReaderBase mp3Reader = new(audioFile, new Mp3FileReaderBase.FrameDecompressorBuilder(wf => new Mp3FrameDecompressor(wf))); @@ -57,7 +57,7 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire // Ditto the Vorbis decoder else if (Path.GetExtension(audioFile).Equals(".ogg", StringComparison.OrdinalIgnoreCase)) { - string oggConvertedFile = Path.Combine(Path.GetDirectoryName(bgmCachedFile), $"{Path.GetFileNameWithoutExtension(bgmCachedFile)}-converted.wav"); + string oggConvertedFile = Path.Combine(Path.GetDirectoryName(bgmCachedFile)!, $"{Path.GetFileNameWithoutExtension(bgmCachedFile)}-converted.wav"); log.Log($"Converting {audioFile} to WAV..."); tracker.Focus("Converting from Vorbis...", 1); using VorbisWaveReader vorbisReader = new(audioFile); @@ -79,7 +79,7 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire return; } - using WaveStream audio = Path.GetExtension(audioFile).ToLower() switch + using WaveStream? audio = Path.GetExtension(audioFile).ToLower() switch { ".wav" => new WaveFileReader(audioFile), ".flac" => new FlacReader(audioFile), @@ -94,11 +94,11 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire if (audio.WaveFormat.SampleRate > SoundItem.MAX_SAMPLERATE) { tracker.Focus("Downsampling...", 1); - string newAudioFile = string.Empty; + string newAudioFile; try { log.Log($"Downsampling audio from {audio.WaveFormat.SampleRate} to NDS max sample rate {SoundItem.MAX_SAMPLERATE}..."); - newAudioFile = Path.Combine(Path.GetDirectoryName(bgmCachedFile), $"{Path.GetFileNameWithoutExtension(bgmCachedFile)}-downsampled.wav"); + newAudioFile = Path.Combine(Path.GetDirectoryName(bgmCachedFile)!, $"{Path.GetFileNameWithoutExtension(bgmCachedFile)}-downsampled.wav"); WaveFileWriter.CreateWaveFile(newAudioFile, new WdlResamplingSampleProvider(audio.ToSampleProvider(), SoundItem.MAX_SAMPLERATE).ToWaveProvider16()); } catch (Exception ex) @@ -201,7 +201,7 @@ public IWaveProvider GetWaveProvider(ILogger log, bool loop) catch (Exception nestedException) { log.LogException("Failed restoring BGM file.", nestedException); - return null; + return new BufferedWaveProvider(new(0, 0, 0)); // Avoid returning null to avoid crashes } try { @@ -212,8 +212,8 @@ public IWaveProvider GetWaveProvider(ILogger log, bool loop) catch (Exception nestedException) { log.LogException("Failed to decode original file too, giving up!", nestedException); - return null; + return new BufferedWaveProvider(new(0, 0, 0)); // Avoid returning null to avoid crashes } } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/CharacterItem.cs b/src/SerialLoops.Lib/Items/CharacterItem.cs index 54788ad0..3e2a9ae5 100644 --- a/src/SerialLoops.Lib/Items/CharacterItem.cs +++ b/src/SerialLoops.Lib/Items/CharacterItem.cs @@ -13,7 +13,7 @@ public class CharacterItem : Item public MessageInfo MessageInfo { get; set; } public NameplateProperties NameplateProperties { get; set; } - public CharacterItem(MessageInfo character, NameplateProperties nameplateProperties, Project project) : base($"CHR_{project.Characters[(int)character.Character].Name}", ItemType.Character) + public CharacterItem(MessageInfo character, NameplateProperties nameplateProperties, Project project) : base($"CHR_{project.Characters![(int)character.Character].Name}", ItemType.Character) { CanRename = false; MessageInfo = character; @@ -53,8 +53,8 @@ public SKBitmap GetNewNameplate(SKBitmap blankNameplate, SKBitmap blankNameplate double widthFactor = 1.0; int totalWidth = NameplateProperties.Name.Sum(c => { - project.FontReplacement.TryGetValue(c, out FontReplacement fr); - return fr is not null ? fr.Offset : 15; + project.FontReplacement.TryGetValue(c, out FontReplacement? fr); + return fr?.Offset ?? 15; }); if (totalWidth > 53) { @@ -67,23 +67,22 @@ public SKBitmap GetNewNameplate(SKBitmap blankNameplate, SKBitmap blankNameplate if (NameplateProperties.Name[i] != ' ') // if it's a space, we just skip drawing { int charIndex = project.FontMap.CharMap.IndexOf(NameplateProperties.Name.GetOriginalString(project)[i]); - if ((charIndex + 1) * 16 <= project.FontBitmap.Height) + if ((charIndex + 1) * 16 <= project.FontBitmap!.Height) { newCanvas.DrawBitmap(project.FontBitmap, new SKRect(0, charIndex * 16, 16, (charIndex + 1) * 16), new SKRect(currentX, currentY, currentX + (int)(16 * widthFactor), currentY + 16), new SKPaint() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ NameplateProperties.NameColor.Red / 255.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NameplateProperties.NameColor.Green / 255.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NameplateProperties.NameColor.Blue / 255.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - }) + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f + ]) } ); } } - project.FontReplacement.TryGetValue(NameplateProperties.Name[i], out FontReplacement replacement); + project.FontReplacement.TryGetValue(NameplateProperties.Name[i], out FontReplacement? replacement); if (replacement is not null && project.LangCode != "ja") { currentX += (int)(replacement.Offset * widthFactor); @@ -103,8 +102,8 @@ public SKBitmap GetNewNameplate(SKBitmap blankNameplate, SKBitmap blankNameplate for (int x = 0; x < newNameplate.Width; x++) { SKColor pixel = newNameplate.GetPixel(x, y); - SKColor[] neighborPixels = new SKColor[] - { + SKColor[] neighborPixels = + [ newNameplate.GetPixel(x + 1, y), newNameplate.GetPixel(x - 1, y), newNameplate.GetPixel(x, y + 1), @@ -112,8 +111,8 @@ public SKBitmap GetNewNameplate(SKBitmap blankNameplate, SKBitmap blankNameplate newNameplate.GetPixel(x + 1, y + 1), newNameplate.GetPixel(x - 1, y + 1), newNameplate.GetPixel(x + 1, y - 1), - newNameplate.GetPixel(x - 1, y - 1), - }; + newNameplate.GetPixel(x - 1, y - 1) + ]; if (Helpers.ColorDistance(pixel, NameplateProperties.NameColor) > 50 && neighborPixels.Any(p => Helpers.ColorDistance(p, NameplateProperties.NameColor) < 50)) { newNameplate.SetPixel(x, y, NameplateProperties.OutlineColor); @@ -130,13 +129,12 @@ public SKBitmap GetNewNameplate(SKBitmap blankNameplate, SKBitmap blankNameplate newCanvas.DrawBitmap(blankNameplateBaseArrow, new SKPoint(0, 3), new SKPaint() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ NameplateProperties.PlateColor.Red / 255.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NameplateProperties.PlateColor.Green / 255.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, NameplateProperties.PlateColor.Blue / 255.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - }) + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f + ]) }); newCanvas.DrawLine(new(0, 15), new(59, 15), new() { Color = NameplateProperties.PlateColor }); newCanvas.Flush(); @@ -151,4 +149,4 @@ public class NameplateProperties(string name, SKColor nameColor, SKColor plateCo public SKColor PlateColor { get; set; } = plateColor; public SKColor OutlineColor { get; set; } = outlineColor; public bool HasOutline { get; set; } = hasOutline; -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/CharacterSpriteItem.cs b/src/SerialLoops.Lib/Items/CharacterSpriteItem.cs index 83ee2884..a43626f5 100644 --- a/src/SerialLoops.Lib/Items/CharacterSpriteItem.cs +++ b/src/SerialLoops.Lib/Items/CharacterSpriteItem.cs @@ -10,13 +10,13 @@ namespace SerialLoops.Lib.Items; -public class CharacterSpriteItem(CharacterSprite sprite, CharacterDataFile chrdata, Project project, ILogger log) : Item($"SPR_{project.Characters[(int)sprite.Character].Name}_{chrdata.Sprites.IndexOf(sprite):D3}{(sprite.IsLarge ? "_L" : "")}", ItemType.Character_Sprite), IPreviewableGraphic +public class CharacterSpriteItem(CharacterSprite sprite, CharacterDataFile? chrdata, Project project, ILogger log) : Item($"SPR_{project.Characters![(int)sprite.Character].Name}_{chrdata.Sprites.IndexOf(sprite):D3}{(sprite.IsLarge ? "_L" : "")}", ItemType.Character_Sprite), IPreviewableGraphic { private readonly ILogger _log = log; public CharacterSprite Sprite { get; set; } = sprite; - public CharacterSpriteGraphics Graphics { get; set; } = new(sprite, project.Grp); - public int Index { get; set; } = chrdata.Sprites.IndexOf(sprite); + public CharacterSpriteGraphics Graphics { get; set; } = new(sprite, project.Grp!); + public int Index { get; set; } = chrdata!.Sprites.IndexOf(sprite); public override void Refresh(Project project, ILogger log) { @@ -57,7 +57,7 @@ public void SetSprite(SKBitmap layoutBitmap, List<(SKBitmap Frame, short Time)> Graphics.MouthAnimation.AnimationX = mouthX; Graphics.MouthAnimation.AnimationY = mouthY; } - + public SKBitmap GetPreview(Project project) { return GetClosedMouthAnimation(project).First().Frame; @@ -208,4 +208,4 @@ public void Write(Project project, ILogger log) IO.WriteBinaryFile(Path.Combine("assets", "graphics", $"{MouthTexture.Index:X3}.png"), mouthTextureStream.ToArray(), project, log); IO.WriteStringFile(Path.Combine("assets", "graphics", $"{MouthTexture.Index:X3}.gi"), MouthTexture.GetGraphicInfoFile(), project, log); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/ChibiItem.cs b/src/SerialLoops.Lib/Items/ChibiItem.cs index d826bdab..44e927f6 100644 --- a/src/SerialLoops.Lib/Items/ChibiItem.cs +++ b/src/SerialLoops.Lib/Items/ChibiItem.cs @@ -15,7 +15,7 @@ public class ChibiItem : Item, IPreviewableGraphic public Chibi Chibi { get; set; } public int TopScreenIndex { get; set; } public int ChibiIndex { get; set; } - public List<(string Name, ChibiGraphics Chibi)> ChibiEntries { get; set; } = new(); + public List<(string Name, ChibiGraphics Chibi)> ChibiEntries { get; set; } = []; public Dictionary ChibiEntryModifications { get; set; } = new(); public Dictionary> ChibiAnimations { get; set; } = new(); @@ -25,7 +25,7 @@ public ChibiItem(Chibi chibi, int chibiIndex, Project project) : base($"CHIBI{ch Chibi = chibi; ChibiIndex = chibiIndex + 1; - string firstAnimationName = project.Grp.GetFileByIndex(Chibi.ChibiEntries[0].Animation).Name; + string firstAnimationName = project.Grp!.GetFileByIndex(Chibi.ChibiEntries[0].Animation).Name; Name = $"CHIBI_{firstAnimationName[0..firstAnimationName.IndexOf('_')]}"; DisplayName = $"CHIBI_{firstAnimationName[0..firstAnimationName.IndexOf('_')]}"; TopScreenIndex = chibiIndices.IndexOf(firstAnimationName[0..3]); @@ -44,7 +44,7 @@ public void SetChibiAnimation(string entryName, List<(SKBitmap, short)> framesAn chibiGraphics.Texture = texture; } - public List<(SKBitmap Frame, short Timing)> GetChibiAnimation(string entryName, ArchiveFile grp) + public List<(SKBitmap Frame, short Timing)> GetChibiAnimation(string entryName, ArchiveFile? grp) { ChibiGraphics chibiGraphics = ChibiEntries.First(c => c.Name == entryName).Chibi; GraphicsFile animation = chibiGraphics.Animation; @@ -87,7 +87,7 @@ public static Direction CodeToDirection(string code) public class ChibiGraphics(ChibiEntry entry, Project project) { - public GraphicsFile Texture { get; set; } = project.Grp.GetFileByIndex(entry.Texture); + public GraphicsFile Texture { get; set; } = project.Grp!.GetFileByIndex(entry.Texture); public GraphicsFile Animation { get; set; } = project.Grp.GetFileByIndex(entry.Animation); public void Write(Project project, ILogger log) @@ -100,4 +100,4 @@ public void Write(Project project, ILogger log) IO.WriteBinaryFile(Path.Combine("assets", "graphics", $"{Animation.Index:X3}.bna"), Animation.GetBytes(), project, log); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/Item.cs b/src/SerialLoops.Lib/Items/Item.cs index 5bd22717..9f072539 100644 --- a/src/SerialLoops.Lib/Items/Item.cs +++ b/src/SerialLoops.Lib/Items/Item.cs @@ -2,25 +2,17 @@ namespace SerialLoops.Lib.Items; -public abstract class Item : ItemDescription +public abstract class Item(string name, ItemDescription.ItemType type, string displayName = "") + : ItemDescription(name, type, displayName) { - - public Item(string name, ItemType type, string displayName = "") : base(name, type, displayName) - { - } - public abstract void Refresh(Project project, ILogger log); } -public class NoneItem : Item +public class NoneItem(ItemDescription.ItemType type) : Item("NONE", type) { public static readonly NoneItem VOICE = new(ItemType.Voice); public static readonly NoneItem SCRIPT = new(ItemType.Script); - public NoneItem(ItemType type) : base("NONE", type) - { - } - public override void Refresh(Project project, ILogger log) { } diff --git a/src/SerialLoops.Lib/Items/ItemDescription.cs b/src/SerialLoops.Lib/Items/ItemDescription.cs index db243c53..a101981e 100644 --- a/src/SerialLoops.Lib/Items/ItemDescription.cs +++ b/src/SerialLoops.Lib/Items/ItemDescription.cs @@ -79,7 +79,7 @@ public List GetReferencesTo(Project project) EventFile.CommandVerb.BG_DISPCG.ToString(), EventFile.CommandVerb.BG_FADE.ToString(), ]; - (string ScriptName, ScriptCommandInvocation command)[] bgScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] bgScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => bgCommands.Contains(c.Command.Mnemonic)).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[0] == bg.Id || t.c.Command.Mnemonic == EventFile.CommandVerb.BG_FADE.ToString() && t.c.Parameters[1] == bg.Id).ToArray(); @@ -87,7 +87,7 @@ public List GetReferencesTo(Project project) case ItemType.BGM: BackgroundMusicItem bgm = (BackgroundMusicItem)this; - (string ScriptName, ScriptCommandInvocation comamnd)[] bgmScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation comamnd)[] bgmScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.BGM_PLAY.ToString()).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[0] == bgm.Index).ToArray(); @@ -95,11 +95,11 @@ public List GetReferencesTo(Project project) case ItemType.Character: CharacterItem character = (CharacterItem)this; - return project.Items.Where(i => i.Type == ItemType.Script && ((ScriptItem)i).Event.DialogueSection.Objects.Any(l => l.Speaker == character.MessageInfo.Character)).ToList(); + return project.Items.Where(i => i.Type == ItemType.Script && ((ScriptItem)i).Event!.DialogueSection.Objects.Any(l => l.Speaker == character.MessageInfo.Character)).ToList(); case ItemType.Character_Sprite: CharacterSpriteItem sprite = (CharacterSpriteItem)this; - (string ScriptName, ScriptCommandInvocation command)[] spriteScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] spriteScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.DIALOGUE.ToString()).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[1] == sprite.Index).ToArray(); @@ -107,9 +107,9 @@ public List GetReferencesTo(Project project) case ItemType.Chibi: ChibiItem chibi = (ChibiItem)this; - references.AddRange(project.Items.Where(i => i.Type == ItemType.Script && project.Evt.Files.Where(e => - e.MapCharactersSection?.Objects?.Any(t => t.CharacterIndex == chibi.ChibiIndex) ?? false).Select(e => e.Index).Contains(((ScriptItem)i).Event.Index))); - (string ScriptName, ScriptCommandInvocation command)[] chibiScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + references.AddRange(project.Items.Where(i => i.Type == ItemType.Script && project.Evt!.Files.Where(e => + e.MapCharactersSection?.Objects?.Any(t => t.CharacterIndex == chibi.ChibiIndex) ?? false).Select(e => e.Index).Contains(((ScriptItem)i).Event!.Index))); + (string ScriptName, ScriptCommandInvocation command)[] chibiScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.CHIBI_ENTEREXIT.ToString()).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[0] == chibi.TopScreenIndex).ToArray(); @@ -126,16 +126,16 @@ public List GetReferencesTo(Project project) case ItemType.Map: MapItem map = (MapItem)this; - (string ScriptName, ScriptCommandInvocation command)[] mapScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] mapScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.LOAD_ISOMAP.ToString()).Select(c => (e.Name[0..^1], c)))) - .Where(t => t.c.Parameters[0] == map.Map.Index).ToArray(); + .Where(t => t.c.Parameters[0] == map.Map?.Index).ToArray(); return project.Items.Where(i => i.Type == ItemType.Puzzle && ((PuzzleItem)i).Puzzle.Settings.MapId == map.QmapIndex) .Concat(project.Items.Where(i => mapScriptUses.Select(s => s.ScriptName).Contains(i.Name))).ToList(); case ItemType.Place: PlaceItem place = (PlaceItem)this; - (string ScriptName, ScriptCommandInvocation command)[] placeScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] placeScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.SET_PLACE.ToString()).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[1] == place.Index).ToArray(); @@ -151,20 +151,20 @@ public List GetReferencesTo(Project project) case ItemType.Script: ScriptItem script = (ScriptItem)this; - if (scenario.Scenario.Commands.Any(c => c.Verb == ScenarioCommand.ScenarioVerb.LOAD_SCENE && c.Parameter == script.Event.Index)) + if (scenario.Scenario.Commands.Any(c => c.Verb == ScenarioCommand.ScenarioVerb.LOAD_SCENE && c.Parameter == script.Event?.Index)) { references.Add(scenario); } - references.AddRange(project.Items.Where(i => i.Type == ItemType.Group_Selection && ((GroupSelectionItem)i).Selection.Activities.Where(s => s is not null).Any(s => s.Routes.Any(r => r.ScriptIndex == script.Event.Index)))); + references.AddRange(project.Items.Where(i => i.Type == ItemType.Group_Selection && ((GroupSelectionItem)i).Selection.Activities.Where(s => s is not null).Any(s => s.Routes.Any(r => r.ScriptIndex == script.Event?.Index)))); references.AddRange(project.Items.Where(i => i.Type == ItemType.Topic && - (((TopicItem)i).TopicEntry.CardType != TopicCardType.Main && ((TopicItem)i).TopicEntry.EventIndex == script.Event.Index || - (((TopicItem)i).HiddenMainTopic?.EventIndex ?? -1) == script.Event.Index))); - references.AddRange(project.Items.Where(i => i.Type == ItemType.Script && ((ScriptItem)i).Event.ConditionalsSection.Objects.Contains(Name))); + (((TopicItem)i).TopicEntry?.CardType != TopicCardType.Main && ((TopicItem)i).TopicEntry?.EventIndex == script.Event?.Index || + (((TopicItem)i).HiddenMainTopic?.EventIndex ?? -1) == script.Event?.Index))); + references.AddRange(project.Items.Where(i => i.Type == ItemType.Script && ((ScriptItem)i).Event!.ConditionalsSection.Objects.Contains(Name))); return references; case ItemType.SFX: SfxItem sfx = (SfxItem)this; - (string ScriptName, ScriptCommandInvocation command)[] sfxScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] sfxScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.SND_PLAY.ToString()).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[0] == sfx.Index).ToArray(); @@ -174,15 +174,15 @@ public List GetReferencesTo(Project project) case ItemType.Topic: TopicItem topic = (TopicItem)this; - (string ScriptName, ScriptCommandInvocation command)[] topicScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] topicScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.TOPIC_GET.ToString()).Select(c => (e.Name[0..^1], c)))) - .Where(t => t.c.Parameters[0] == topic.TopicEntry.Id).ToArray(); + .Where(t => t.c.Parameters[0] == topic.TopicEntry?.Id).ToArray(); return project.Items.Where(i => topicScriptUses.Select(s => s.ScriptName).Contains(i.Name)).ToList(); case ItemType.Voice: VoicedLineItem voicedLine = (VoicedLineItem)this; - (string ScriptName, ScriptCommandInvocation command)[] vceScriptUses = project.Evt.Files.AsParallel().SelectMany(e => + (string ScriptName, ScriptCommandInvocation command)[] vceScriptUses = project.Evt!.Files.AsParallel().SelectMany(e => e.ScriptSections.SelectMany(sec => sec.Objects.Where(c => c.Command.Mnemonic == EventFile.CommandVerb.DIALOGUE.ToString()).Select(c => (e.Name[0..^1], c)))) .Where(t => t.c.Parameters[5] == voicedLine.Index) @@ -197,4 +197,4 @@ public List GetReferencesTo(Project project) return references; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/ItemItem.cs b/src/SerialLoops.Lib/Items/ItemItem.cs index 7a6cd9f5..23394aec 100644 --- a/src/SerialLoops.Lib/Items/ItemItem.cs +++ b/src/SerialLoops.Lib/Items/ItemItem.cs @@ -9,7 +9,7 @@ namespace SerialLoops.Lib.Items; public class ItemItem : Item, IPreviewableGraphic { - public GraphicsFile ItemGraphic { get; set; } + public GraphicsFile? ItemGraphic { get; set; } public int ItemIndex { get; set; } public ItemItem(string name) : base(name, ItemType.Item) @@ -17,26 +17,31 @@ public ItemItem(string name) : base(name, ItemType.Item) } public ItemItem(string name, int itemIndex, short grpIndex, Project project) : base(name, ItemType.Item) { - ItemGraphic = project.Grp.GetFileByIndex(grpIndex); + ItemGraphic = project.Grp!.GetFileByIndex(grpIndex); ItemIndex = itemIndex; } public SKBitmap GetImage() { - return ItemGraphic.GetImage(transparentIndex: 0); + return ItemGraphic?.GetImage(transparentIndex: 0) ?? new(); } public void SetImage(SKBitmap image, IProgressTracker tracker, ILogger log) { tracker.Focus("Setting item image...", 1); List palette = Helpers.GetPaletteFromImage(image, 255, log); - ItemGraphic.SetPalette(palette, 0); - ItemGraphic.SetImage(image); + ItemGraphic?.SetPalette(palette, 0); + ItemGraphic?.SetImage(image); tracker.Finished++; } public void Write(Project project, ILogger log) { + if (ItemGraphic is null) + { + log.LogError($"Failed to write item {ItemIndex} to disk: ItemGraphic is null!"); + return; + } using MemoryStream grp1Stream = new(); ItemGraphic.GetImage().Encode(grp1Stream, SKEncodedImageFormat.Png, 1); IO.WriteBinaryFile(Path.Combine("assets", "graphics", $"{ItemGraphic.Index:X3}.png"), grp1Stream.ToArray(), project, log); @@ -65,4 +70,4 @@ public enum ItemTransition Slide = 225, Fade = 226, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/LayoutItem.cs b/src/SerialLoops.Lib/Items/LayoutItem.cs index 9fa1bbdf..d4dc0c31 100644 --- a/src/SerialLoops.Lib/Items/LayoutItem.cs +++ b/src/SerialLoops.Lib/Items/LayoutItem.cs @@ -24,7 +24,7 @@ public SKBitmap GetLayoutImage() return Layout.GetLayout(GraphicsFiles, Layout.LayoutEntries.Skip(StartEntry).Take(NumEntries).ToList(), darkMode: false, preprocessedList: true).bitmap; } - public (SKBitmap tile, SKRect dest) GetLayoutEntryRender(int index) + public (SKBitmap? tile, SKRect? dest) GetLayoutEntryRender(int index) { if (index < 0 || Layout.LayoutEntries[index].RelativeShtxIndex < 0) { @@ -40,4 +40,4 @@ SKBitmap IPreviewableGraphic.GetPreview(Project project) { return GetLayoutImage(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/MapItem.cs b/src/SerialLoops.Lib/Items/MapItem.cs index 36955d65..ca0bda43 100644 --- a/src/SerialLoops.Lib/Items/MapItem.cs +++ b/src/SerialLoops.Lib/Items/MapItem.cs @@ -8,7 +8,7 @@ namespace SerialLoops.Lib.Items; public class MapItem : Item { - public MapFile Map { get; set; } + public MapFile? Map { get; set; } public int QmapIndex { get; set; } public MapItem(string name) : base(name, ItemType.Map) @@ -20,14 +20,22 @@ public MapItem(MapFile map, int qmapIndex, Project project) : base(map.Name[0..^ QmapIndex = qmapIndex; } - public SKPoint GetOrigin(ArchiveFile grp) + public SKPoint? GetOrigin(ArchiveFile grp) { + if (Map is null) + { + return null; + } GraphicsFile layout = grp.GetFileByIndex(Map.Settings.LayoutFileIndex); return new SKPoint(layout.LayoutEntries[Map.Settings.LayoutSizeDefinitionIndex].ScreenX, layout.LayoutEntries[Map.Settings.LayoutSizeDefinitionIndex].ScreenY); } - public SKBitmap GetMapImage(ArchiveFile grp, bool displayPathingMap, bool displayMapStart) + public SKBitmap? GetMapImage(ArchiveFile grp, bool displayPathingMap, bool displayMapStart) { + if (Map is null) + { + return null; + } SKBitmap map; if (Map.Settings.BackgroundLayoutStartIndex > 0) { @@ -41,7 +49,7 @@ public SKBitmap GetMapImage(ArchiveFile grp, bool displayPathingMa SKCanvas canvas = new(mapWithGrid); canvas.DrawBitmap(map, new SKPoint(0, 0)); - SKPoint gridZero = GetOrigin(grp); + SKPoint gridZero = GetOrigin(grp) ?? SKPoint.Empty; if (displayPathingMap) { if (Map.Settings.SlgMode) @@ -59,7 +67,7 @@ public SKBitmap GetMapImage(ArchiveFile grp, bool displayPathingMa new(origin.X, origin.Y + 32), new(origin.X + 32, origin.Y + 16) ]); - canvas.DrawRegion(new SKRegion(diamond), GetPathingCellPaint(x, y)); + canvas.DrawRegion(new(diamond), GetPathingCellPaint(x, y)); } } } @@ -78,7 +86,7 @@ public SKBitmap GetMapImage(ArchiveFile grp, bool displayPathingMa new(origin.X, origin.Y + 16), new(origin.X + 16, origin.Y + 8), ]); - canvas.DrawRegion(new SKRegion(diamond), GetPathingCellPaint(x, y)); + canvas.DrawRegion(new(diamond), GetPathingCellPaint(x, y)); } } } @@ -107,11 +115,11 @@ public SKBitmap GetMapImage(ArchiveFile grp, bool displayPathingMa private SKPaint GetPathingCellPaint(int x, int y) { - return Map.PathingMap[x][y] switch + return Map?.PathingMap[x][y] switch { - 1 => new() { Color = new SKColor(0, 128, 0, 186) }, // walkable - 2 => new() { Color = new SKColor(0, 200, 200, 186) }, // spawnable - _ => new() { Color = new SKColor(255, 0, 0, 186) }, // unwalkable + 1 => new() { Color = new(0, 128, 0, 186) }, // walkable + 2 => new() { Color = new(0, 200, 200, 186) }, // spawnable + _ => new() { Color = new(255, 0, 0, 186) }, // unwalkable }; } @@ -126,4 +134,4 @@ private static SKBitmap GetMapIcon(string name, int size) public override void Refresh(Project project, ILogger log) { } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/PlaceItem.cs b/src/SerialLoops.Lib/Items/PlaceItem.cs index c87fbb02..d76edd6c 100644 --- a/src/SerialLoops.Lib/Items/PlaceItem.cs +++ b/src/SerialLoops.Lib/Items/PlaceItem.cs @@ -10,7 +10,7 @@ public class PlaceItem : Item, IPreviewableGraphic { public int Index { get; set; } public GraphicsFile PlaceGraphic { get; set; } - public string PlaceName { get; set; } + public string PlaceName { get; set; } = string.Empty; public PlaceItem(int index, GraphicsFile placeGrp) : base(placeGrp.Name[0..^3], ItemType.Place) { @@ -34,8 +34,10 @@ public static SKBitmap Unscramble(SKBitmap placeGraphic) for (int x = 0; x < 2; x++) { canvas.DrawBitmap(placeGraphic, + // ReSharper disable PossibleLossOfFraction new SKRect(x * placeGraphic.Width / 2, y * placeGraphic.Height / 4, (x + 1) * placeGraphic.Width / 2, (y + 1) * placeGraphic.Height / 4), new SKRect(col * placeGraphic.Width / 2, row * placeGraphic.Height / 4, (col + 1) * placeGraphic.Width / 2, (row + 1) * placeGraphic.Height / 4)); + // ReSharper restore PossibleLossOfFraction row++; if (row >= 4) { @@ -134,4 +136,4 @@ public override SKTypeface TypefaceFromStyle(IStyle style, bool ignoreFontVarian return _fonts[style.FontFamily]; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/PuzzleItem.cs b/src/SerialLoops.Lib/Items/PuzzleItem.cs index f85d3e49..93d8961d 100644 --- a/src/SerialLoops.Lib/Items/PuzzleItem.cs +++ b/src/SerialLoops.Lib/Items/PuzzleItem.cs @@ -9,7 +9,7 @@ namespace SerialLoops.Lib.Items; public class PuzzleItem : Item { public PuzzleFile Puzzle { get; set; } - public SKBitmap SingularityImage { get; set; } + public SKBitmap? SingularityImage { get; set; } public PuzzleItem(PuzzleFile puzzleFile, Project project, ILogger log) : base(puzzleFile.Name[0..^1], ItemType.Puzzle) { @@ -19,7 +19,7 @@ public PuzzleItem(PuzzleFile puzzleFile, Project project, ILogger log) : base(pu public override void Refresh(Project project, ILogger log) { - GraphicsFile singularityLayout = project.Grp.GetFileByIndex(Puzzle.Settings.SingularityLayout); + GraphicsFile singularityLayout = project.Grp!.GetFileByIndex(Puzzle.Settings.SingularityLayout); GraphicsFile singularityTexture = project.Grp.GetFileByIndex(Puzzle.Settings.SingularityTexture); SingularityImage = singularityLayout.GetLayout( [singularityTexture], @@ -39,4 +39,4 @@ public override void Refresh(Project project, ILogger log) "KOIZUMI", "ANY", ]; -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/ScenarioItem.cs b/src/SerialLoops.Lib/Items/ScenarioItem.cs index e0523530..abf11604 100644 --- a/src/SerialLoops.Lib/Items/ScenarioItem.cs +++ b/src/SerialLoops.Lib/Items/ScenarioItem.cs @@ -10,9 +10,9 @@ public class ScenarioItem : Item public ScenarioStruct Scenario { get; set; } public List<(ScenarioCommand.ScenarioVerb Command, string Parameter)> ScenarioCommands { get; set; } = []; - private IEnumerable _puzzleItems; - private IEnumerable _scriptItems; - private IEnumerable _groupSelectionItems; + private IEnumerable _puzzleItems = []; + private IEnumerable _scriptItems = []; + private IEnumerable _groupSelectionItems = []; public ScenarioItem(ScenarioStruct scenario, Project project, ILogger log) : base("Scenario", ItemType.Scenario) { @@ -41,7 +41,7 @@ public override void Refresh(Project project, ILogger log) switch (command.Verb) { case ScenarioCommand.ScenarioVerb.LOAD_SCENE: - ScriptItem script = _scriptItems.First(s => s.Event.Index == command.Parameter); + ScriptItem script = _scriptItems.First(s => s.Event?.Index == command.Parameter); return (command.Verb, script.DisplayName); case ScenarioCommand.ScenarioVerb.PUZZLE_PHASE: @@ -56,4 +56,4 @@ public override void Refresh(Project project, ILogger log) return (command.Verb, command.Parameter.ToString()); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/ScriptItem.cs b/src/SerialLoops.Lib/Items/ScriptItem.cs index d5bc505a..516196cf 100644 --- a/src/SerialLoops.Lib/Items/ScriptItem.cs +++ b/src/SerialLoops.Lib/Items/ScriptItem.cs @@ -16,11 +16,11 @@ namespace SerialLoops.Lib.Items; public class ScriptItem : Item { - public EventFile Event { get; set; } + public EventFile? Event { get; set; } public short StartReadFlag { get; set; } public short SfxGroupIndex { get; set; } public AdjacencyGraph Graph { get; set; } = new(); - private readonly Func _localize; + private readonly Func _localize = (s) => s; public ScriptItem(string name) : base(name, ItemType.Script) { @@ -37,10 +37,14 @@ public ScriptItem(EventFile evt, EventTable evtTbl, Func localiz Graph.AddVertexRange(Event.ScriptSections); } - public Dictionary> GetScriptCommandTree(Project project, ILogger log) + public Dictionary>? GetScriptCommandTree(Project project, ILogger log) { try { + if (Event is null) + { + throw new NullReferenceException("Event is null"); + } Dictionary> commands = []; foreach (ScriptSection section in Event.ScriptSections) { @@ -67,6 +71,10 @@ public void CalculateGraphEdges(Dictionary Event.LabelsSection.Objects.Where(l => @@ -100,7 +108,7 @@ public void CalculateGraphEdges(Dictionary() .Where(p => p.Section is not null).Select(p => - new ScriptSectionEdge() { Source = section, Target = p.Section })); + new ScriptSectionEdge() { Source = section, Target = p.Section! })); ScriptSection miss2Section = - Event.ScriptSections.FirstOrDefault(s => s.Name == "NONEMiss2"); + Event.ScriptSections.First(s => s.Name == "NONEMiss2"); if (miss2Section is not null) { Graph.AddEdge(new() @@ -196,7 +204,7 @@ public void CalculateGraphEdges(Dictionary> commandTree, - ScriptItemCommand currentCommand, Project project, ILogger log) + ScriptItemCommand? currentCommand, Project project, ILogger log) { ScriptPreview preview = new(); @@ -205,7 +213,7 @@ public ScriptPreview GetScriptPreview(Dictionary commands = currentCommand.WalkCommandGraph(commandTree, Graph); + List? commands = currentCommand.WalkCommandGraph(commandTree, Graph); if (commands is null) { @@ -226,8 +234,7 @@ public ScriptPreview GetScriptPreview(Dictionary= 0; i--) { - if (commands[i].Verb == CommandVerb.KBG_DISP && - ((BgScriptParameter)commands[i].Parameters[0]).Background is not null) + if (commands[i].Verb == CommandVerb.KBG_DISP) { preview.Kbg = ((BgScriptParameter)commands[i].Parameters[0]).Background; break; @@ -239,8 +246,7 @@ public ScriptPreview GetScriptPreview(Dictionary chibis = []; - foreach (StartingChibiEntry chibi in Event.StartingChibisSection?.Objects ?? []) + foreach (StartingChibiEntry chibi in Event?.StartingChibisSection?.Objects ?? []) { if (chibi.ChibiIndex > 0) { @@ -266,8 +272,8 @@ public ScriptPreview GetScriptPreview(Dictionary - i.Type == ItemType.Chibi && ((ChibiItem)i).TopScreenIndex == 1); + ChibiItem chibi = (ChibiItem)project.Items.First(item => + item.Type == ItemType.Chibi && ((ChibiItem)item).TopScreenIndex == 1); if (!chibis.Contains(chibi)) { chibis.Add(chibi); @@ -374,20 +380,19 @@ public ScriptPreview GetScriptPreview(Dictionary c.Verb == CommandVerb.PALEFFECT); - ScriptItemCommand lastBgCommand = commands.LastOrDefault(c => c.Verb == CommandVerb.BG_DISP || + ScriptItemCommand? palCommand = commands.LastOrDefault(c => c.Verb == CommandVerb.PALEFFECT); + ScriptItemCommand? lastBgCommand = commands.LastOrDefault(c => c.Verb == CommandVerb.BG_DISP || c.Verb == CommandVerb.BG_DISP2 || c.Verb == CommandVerb.BG_DISPCG || c.Verb == CommandVerb.BG_FADE || c.Verb == CommandVerb.BG_REVERT); - SKPaint palEffectPaint = PaletteEffectScriptParameter.IdentityPaint; if (palCommand is not null && lastBgCommand is not null && commands.IndexOf(palCommand) > commands.IndexOf(lastBgCommand)) { preview.BgPalEffect = ((PaletteEffectScriptParameter)palCommand.Parameters[0]).Effect; } - ScriptItemCommand bgScrollCommand = null; + ScriptItemCommand? bgScrollCommand = null; for (int i = commands.Count - 1; i >= 0; i--) { if (commands[i].Verb == CommandVerb.BG_REVERT) @@ -404,37 +409,29 @@ public ScriptPreview GetScriptPreview(Dictionary= 2 && + commands[i].Parameters[1].Type == ScriptParameter.ParameterType.BOOL) { - preview.Background = background; - preview.BgScrollCommand = bgScrollCommand; - if (commands[i].Parameters.Count >= 2 && - commands[i].Parameters[1].Type == ScriptParameter.ParameterType.BOOL) - { - preview.BgPositionBool = ((BoolScriptParameter)commands[i].Parameters[1]).Value; - } - - break; + preview.BgPositionBool = ((BoolScriptParameter)commands[i].Parameters[1]).Value; } + + break; } } // Draw items - ScriptItemCommand lastItemCommand = commands.LastOrDefault(c => c.Verb == CommandVerb.ITEM_DISPIMG); + ScriptItemCommand? lastItemCommand = commands.LastOrDefault(c => c.Verb == CommandVerb.ITEM_DISPIMG); if (lastItemCommand is not null) { - ItemItem item = (ItemItem)project.Items.FirstOrDefault(i => + ItemItem? item = (ItemItem?)project.Items.FirstOrDefault(i => i.Type == ItemType.Item && ((ItemScriptParameter)lastItemCommand.Parameters[0]).ItemIndex == ((ItemItem)i).ItemIndex); if (item is not null && ((ItemLocationScriptParameter)lastItemCommand.Parameters[1]).Location != @@ -448,22 +445,21 @@ public ScriptPreview GetScriptPreview(Dictionary sprites = []; Dictionary previousSprites = []; - CharacterItem previousCharacter = null; - ScriptItemCommand previousCommand = null; + CharacterItem? previousCharacter = null; + ScriptItemCommand? previousCommand = null; foreach (ScriptItemCommand command in commands) { if (previousCommand?.Verb == CommandVerb.DIALOGUE) { SpriteExitScriptParameter spriteExitMoveParam = - (SpriteExitScriptParameter)previousCommand - ?.Parameters + (SpriteExitScriptParameter)previousCommand.Parameters [3]; // exits/moves happen _after_ dialogue is advanced, so we check these at this point if (spriteExitMoveParam.ExitTransition != SpriteExitScriptParameter.SpriteExitTransition.NO_EXIT) { CharacterItem prevCharacter = (CharacterItem)project.Items.First(i => i.Type == ItemType.Character && i.Name == - $"CHR_{project.Characters[(int)((DialogueScriptParameter)previousCommand.Parameters[0]).Line.Speaker].Name}"); + $"CHR_{project.Characters![(int)((DialogueScriptParameter)previousCommand.Parameters[0]).Line.Speaker].Name}"); SpriteScriptParameter previousSpriteParam = (SpriteScriptParameter)previousCommand.Parameters[1]; short layer = ((ShortScriptParameter)previousCommand.Parameters[9]).Value; @@ -476,7 +472,7 @@ public ScriptPreview GetScriptPreview(Dictionary commands.IndexOf(command)) + if (palCommand is not null && commands.IndexOf(palCommand) > commands.IndexOf(command)) { spritePaint = ((PaletteEffectScriptParameter)palCommand.Parameters[0]).Effect switch { @@ -531,50 +527,64 @@ public ScriptPreview GetScriptPreview(Dictionary - i.Type == ItemDescription.ItemType.Character && - i.DisplayName == - $"CHR_{project.Characters[(int)((DialogueScriptParameter)command.Parameters[0]).Line.Speaker].Name}"); - } - catch (InvalidOperationException) - { - log.LogWarning( - $"Unable to determine speaking character in DIALOGUE command in {DisplayName}."); - preview.ErrorImage = "SerialLoops.Graphics.ScriptPreviewError.png"; - return preview; - } + character = (CharacterItem)project.Items.First(i => + i.Type == ItemType.Character && + i.DisplayName == + $"CHR_{project.Characters![(int)((DialogueScriptParameter)command.Parameters[0]).Line.Speaker].Name}"); + } + catch (InvalidOperationException) + { + log.LogWarning( + $"Unable to determine speaking character in DIALOGUE command in {DisplayName}."); + preview.ErrorImage = "SerialLoops.Graphics.ScriptPreviewError.png"; + return preview; + } - SpriteEntranceScriptParameter spriteEntranceParam = - (SpriteEntranceScriptParameter)command.Parameters[2]; - SpriteShakeScriptParameter spriteShakeParam = (SpriteShakeScriptParameter)command.Parameters[4]; - short layer = ((ShortScriptParameter)command.Parameters[9]).Value; + SpriteEntranceScriptParameter spriteEntranceParam = + (SpriteEntranceScriptParameter)command.Parameters[2]; + SpriteShakeScriptParameter spriteShakeParam = (SpriteShakeScriptParameter)command.Parameters[4]; + short layer = ((ShortScriptParameter)command.Parameters[9]).Value; - bool spriteIsNew = !sprites.ContainsKey(character); - if (spriteIsNew && spriteEntranceParam.EntranceTransition != - SpriteEntranceScriptParameter.SpriteEntranceTransition.NO_TRANSITION) - { - sprites.Add(character, new()); - previousSprites.Add(character, new()); - } + bool spriteIsNew = !sprites.ContainsKey(character); + if (spriteIsNew && spriteEntranceParam.EntranceTransition != + SpriteEntranceScriptParameter.SpriteEntranceTransition.NO_TRANSITION) + { + sprites.Add(character, new()); + previousSprites.Add(character, new()); + } - if (sprites.ContainsKey(character)) - { - previousSprites[character] = sprites[character]; - } + if (sprites.ContainsKey(character)) + { + previousSprites[character] = sprites[character]; + } - if (spriteEntranceParam.EntranceTransition != - SpriteEntranceScriptParameter.SpriteEntranceTransition.NO_TRANSITION) + if (spriteEntranceParam.EntranceTransition != + SpriteEntranceScriptParameter.SpriteEntranceTransition.NO_TRANSITION) + { + switch (spriteEntranceParam.EntranceTransition) { - switch (spriteEntranceParam.EntranceTransition) - { - // These ones will do their thing no matter what - case SpriteEntranceScriptParameter.SpriteEntranceTransition.SLIDE_LEFT_TO_CENTER: - case SpriteEntranceScriptParameter.SpriteEntranceTransition.SLIDE_RIGHT_TO_CENTER: + // These ones will do their thing no matter what + case SpriteEntranceScriptParameter.SpriteEntranceTransition.SLIDE_LEFT_TO_CENTER: + case SpriteEntranceScriptParameter.SpriteEntranceTransition.SLIDE_RIGHT_TO_CENTER: + sprites[character] = new() + { + Sprite = spriteParam.Sprite, + Positioning = + new() + { + X = SpritePositioning.SpritePosition.CENTER.GetSpriteX(), + Layer = layer + }, + PalEffect = spritePaint + }; + break; + + case SpriteEntranceScriptParameter.SpriteEntranceTransition.FADE_TO_CENTER: + if (spriteIsNew) + { sprites[character] = new() { Sprite = spriteParam.Sprite, @@ -586,117 +596,17 @@ public ScriptPreview GetScriptPreview(Dictionary p.Positioning.Layer)]; // Draw dialogue - ScriptItemCommand lastPinMnlCommand = commands.LastOrDefault(c => - c.Verb == CommandVerb.PIN_MNL && c.Section.Equals(commands.Last().Section)); + ScriptItemCommand? lastPinMnlCommand = commands.LastOrDefault(c => + c.Verb == CommandVerb.PIN_MNL && c.Section is not null && c.Section.Equals(commands.Last().Section)); if (lastPinMnlCommand is not null) { DialogueLine line = ((DialogueScriptParameter)lastPinMnlCommand.Parameters[0]).Line; @@ -770,8 +763,8 @@ public ScriptPreview GetScriptPreview(Dictionary c.Verb == CommandVerb.DIALOGUE); - if (commands.FindLastIndex(c => c.Verb == CommandVerb.TOGGLE_DIALOGUE && + ScriptItemCommand? lastDialogueCommand = commands.LastOrDefault(c => c.Verb == CommandVerb.DIALOGUE); + if (lastDialogueCommand is not null && commands.FindLastIndex(c => c.Verb == CommandVerb.TOGGLE_DIALOGUE && !((BoolScriptParameter)c.Parameters[0]).Value) < commands.IndexOf(lastDialogueCommand)) { @@ -786,15 +779,15 @@ public ScriptPreview GetScriptPreview(Dictionary - i.Type == ItemType.Topic && ((TopicItem)i).TopicEntry.Id == + preview.Topic = (TopicItem?)project.Items.FirstOrDefault(i => + i.Type == ItemType.Topic && ((TopicItem)i).TopicEntry?.Id == ((TopicScriptParameter)currentCommand.Parameters[0]).TopicId); } return preview; } - public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(ScriptPreview preview, + public static (SKBitmap? PreviewImage, string? ErrorImage) GeneratePreviewImage(ScriptPreview preview, Project project) { SKBitmap previewBitmap = new(256, 384); @@ -810,7 +803,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc { canvas.DrawBitmap( EpisodeHeaderScriptParameter - .GetTexture((EpisodeHeaderScriptParameter.Episode)preview.EpisodeHeader, project).GetTexture(), + .GetTexture((EpisodeHeaderScriptParameter.Episode)preview.EpisodeHeader, project)?.GetTexture(), new SKPoint(0, 0)); } else @@ -827,13 +820,13 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc foreach (var chibi in preview.TopScreenChibis) { - SKBitmap chibiFrame = chibi.Chibi.ChibiAnimations.First().Value.ElementAt(0).Frame; + SKBitmap? chibiFrame = chibi.Chibi?.ChibiAnimations.First().Value.ElementAt(0).Frame; canvas.DrawBitmap(chibiFrame, new SKPoint(chibi.X, chibi.Y)); } if (preview.ChibiEmote.EmotingChibi is not null) { - SKBitmap emotes = project.Grp.GetFileByName("SYS_ADV_T08DNX") + SKBitmap emotes = project.Grp!.GetFileByName("SYS_ADV_T08DNX") .GetImage(width: 32, transparentIndex: 0); int chibiY = preview.TopScreenChibis.First(c => c.Chibi == preview.ChibiEmote.EmotingChibi).Y; canvas.DrawBitmap(emotes, @@ -849,8 +842,9 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc switch (preview.Background.BackgroundType) { case BgType.TEX_CG_DUAL_SCREEN: - SKBitmap dualScreenBg = preview.Background.GetBackground(); - if (preview.BgScrollCommand is not null && + SKBitmap? dualScreenBg = preview.Background.GetBackground(); + if (preview.Background.Graphic2 is not null && dualScreenBg is not null && + preview.BgScrollCommand is not null && ((BgScrollDirectionScriptParameter)preview.BgScrollCommand.Parameters[0]).ScrollDirection == BgScrollDirectionScriptParameter.BgScrollDirection.DOWN) { @@ -861,7 +855,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc canvas.DrawBitmap(dualScreenBg, new SKRect(0, bottomScreenX, 256, bottomScreenX + 192), new SKRect(0, 192, 256, 384)); } - else + else if (preview.Background.Graphic2 is not null) { canvas.DrawBitmap(dualScreenBg, new SKRect(0, 0, 256, 192), new SKRect(0, 0, 256, 192)); canvas.DrawBitmap(dualScreenBg, @@ -877,10 +871,13 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc .Parameters[0]).ScrollDirection == BgScrollDirectionScriptParameter.BgScrollDirection.DOWN)) { - SKBitmap bgBitmap = preview.Background.GetBackground(); - canvas.DrawBitmap(bgBitmap, - new SKRect(0, bgBitmap.Height - 192, bgBitmap.Width, bgBitmap.Height), - new SKRect(0, 192, 256, 384)); + SKBitmap? bgBitmap = preview.Background.GetBackground(); + if (bgBitmap is not null) + { + canvas.DrawBitmap(bgBitmap, + new SKRect(0, bgBitmap.Height - 192, bgBitmap.Width, bgBitmap.Height), + new SKRect(0, 192, 256, 384)); + } } else { @@ -894,9 +891,12 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc ((BgScrollDirectionScriptParameter)preview.BgScrollCommand.Parameters[0]).ScrollDirection == BgScrollDirectionScriptParameter.BgScrollDirection.RIGHT) { - SKBitmap bgBitmap = preview.Background.GetBackground(); - canvas.DrawBitmap(bgBitmap, new SKRect(bgBitmap.Width - 256, 0, bgBitmap.Width, 192), - new SKRect(0, 192, 256, 384)); + SKBitmap? bgBitmap = preview.Background.GetBackground(); + if (bgBitmap is not null) + { + canvas.DrawBitmap(bgBitmap, new SKRect(bgBitmap.Width - 256, 0, bgBitmap.Width, 192), + new SKRect(0, 192, 256, 384)); + } } else { @@ -916,7 +916,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc } } - if (preview.Item.Item is not null) + if (preview.Item.Item?.ItemGraphic is not null) { int width = preview.Item.Item.ItemGraphic.Width; switch (preview.Item.Location) @@ -944,12 +944,9 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc // Draw character sprites foreach (PositionedSprite sprite in preview.Sprites) { - if (sprite.Sprite is not null) - { - SKBitmap spriteBitmap = sprite.Sprite.GetClosedMouthAnimation(project)[0].Frame; - canvas.DrawBitmap(spriteBitmap, sprite.Positioning.GetSpritePosition(spriteBitmap), - sprite.PalEffect); - } + SKBitmap spriteBitmap = sprite.Sprite.GetClosedMouthAnimation(project)[0].Frame; + canvas.DrawBitmap(spriteBitmap, sprite.Positioning.GetSpritePosition(spriteBitmap), + sprite.PalEffect); } // Draw dialogue @@ -965,7 +962,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc if (!string.IsNullOrEmpty(line.Text)) { canvas.DrawBitmap(project.DialogueBitmap, new SKRect(0, 24, 32, 36), new SKRect(0, 344, 256, 356)); - SKColor dialogueBoxColor = project.DialogueBitmap.GetPixel(0, 28); + SKColor dialogueBoxColor = project.DialogueBitmap!.GetPixel(0, 28); canvas.DrawRect(0, 356, 224, 384, new() { Color = dialogueBoxColor }); canvas.DrawBitmap(project.DialogueBitmap, new SKRect(0, 37, 32, 64), new SKRect(224, 356, 256, 384)); @@ -980,7 +977,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc // Draw topic obtained flyout if (preview.Topic is not null) { - SKBitmap flyoutSysTex = project.Grp.GetFileByName("SYS_ADV_B01DNX").GetImage(transparentIndex: 0); + SKBitmap flyoutSysTex = project.Grp!.GetFileByName("SYS_ADV_B01DNX").GetImage(transparentIndex: 0); SKBitmap topicFlyout = new(76, 32); SKCanvas flyoutCanvas = new SKCanvas(topicFlyout); @@ -990,7 +987,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc new SKRect(32, 6, 76, 26)); SKBitmap topicCards = project.Grp.GetFileByName("SYS_CMN_B09DNX").GetImage(transparentIndex: 0); - int srcX = preview.Topic.TopicEntry.CardType switch + int srcX = preview.Topic.TopicEntry?.CardType switch { TopicCardType.Haruhi => 0, TopicCardType.Mikuru => 20, @@ -1011,7 +1008,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc return (previewBitmap, null); } - public (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage( + public (SKBitmap? PreviewImage, string? ErrorImage) GeneratePreviewImage( Dictionary> commandTree, ScriptItemCommand currentCommand, Project project, ILogger log) { @@ -1020,7 +1017,7 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc public void UpdateEventTableInfo(EventTable evtTbl) { - EventTableEntry entry = evtTbl.Entries.FirstOrDefault(e => e.EventFileIndex == Event.Index); + EventTableEntry? entry = evtTbl.Entries.FirstOrDefault(e => e.EventFileIndex == Event?.Index); if (entry is not null) { StartReadFlag = entry.FirstReadFlag; @@ -1035,11 +1032,11 @@ public void UpdateEventTableInfo(EventTable evtTbl) private void PruneLabelsSection(ILogger log) { - if ((Event.LabelsSection?.Objects?.Count ?? 0) - 1 > Event.ScriptSections.Count) + if ((Event?.LabelsSection?.Objects?.Count ?? 0) - 1 > Event?.ScriptSections.Count) { try { - for (int i = 0; i < Event.LabelsSection.Objects.Count; i++) + for (int i = 0; i < Event?.LabelsSection?.Objects?.Count; i++) { if (Event.LabelsSection.Objects[i].Id == 0) { @@ -1065,7 +1062,7 @@ private void PruneLabelsSection(ILogger log) public override void Refresh(Project project, ILogger log) { Graph = new(); - Graph.AddVertexRange(Event.ScriptSections); - CalculateGraphEdges(GetScriptCommandTree(project, log), log); + Graph.AddVertexRange(Event?.ScriptSections ?? []); + CalculateGraphEdges(GetScriptCommandTree(project, log) ?? [], log); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/SfxItem.cs b/src/SerialLoops.Lib/Items/SfxItem.cs index ca319149..94c44e9b 100644 --- a/src/SerialLoops.Lib/Items/SfxItem.cs +++ b/src/SerialLoops.Lib/Items/SfxItem.cs @@ -17,11 +17,11 @@ public SfxItem(SfxEntry entry, string name, short index, Project project) : base { Entry = entry; Index = index; - AssociatedBank = project.Snd.SequenceArchives[entry.SequenceArchive].File.Sequences[entry.Index].Bank.Name; + AssociatedBank = project.Snd!.SequenceArchives[entry.SequenceArchive].File.Sequences[entry.Index].Bank.Name; AssociatedGroups = project.Snd.Groups.Where(g => g.Entries.Any(e => e.LoadBank && ((BankInfo)e.Entry).Name.Equals(AssociatedBank))).Select(g => g.Name).ToList(); } public override void Refresh(Project project, ILogger log) { } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/SystemTextureItem.cs b/src/SerialLoops.Lib/Items/SystemTextureItem.cs index c3fb5805..4470c635 100644 --- a/src/SerialLoops.Lib/Items/SystemTextureItem.cs +++ b/src/SerialLoops.Lib/Items/SystemTextureItem.cs @@ -23,7 +23,7 @@ public class SystemTextureItem : Item public SystemTextureItem(SystemTexture sysTex, Project project, string name, int width = -1, int height = -1) : base(name, ItemType.System_Texture) { SysTex = sysTex; - Grp = project.Grp.GetFileByIndex(sysTex.GrpIndex); + Grp = project.Grp!.GetFileByIndex(sysTex.GrpIndex); if (SysTex.Screen == SysTexScreen.BOTTOM_SCREEN) { Grp.ImageForm = GraphicsFile.Form.TEXTURE; @@ -121,4 +121,4 @@ public bool UsesCommonPalette() { return COMMON_PALETTE.Equals(string.Join(',', Grp.Palette.Select(c => c.ToString())), StringComparison.OrdinalIgnoreCase); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/TopicItem.cs b/src/SerialLoops.Lib/Items/TopicItem.cs index 9f8623bf..c3c655f5 100644 --- a/src/SerialLoops.Lib/Items/TopicItem.cs +++ b/src/SerialLoops.Lib/Items/TopicItem.cs @@ -6,9 +6,9 @@ namespace SerialLoops.Lib.Items; public class TopicItem : Item { - public Topic TopicEntry { get; set; } - public Topic HiddenMainTopic { get; set; } - public (string ScriptName, ScriptCommandInvocation command)[] ScriptUses { get; set; } + public Topic? TopicEntry { get; set; } + public Topic? HiddenMainTopic { get; set; } + public (string ScriptName, ScriptCommandInvocation command)[] ScriptUses { get; set; } = []; public TopicItem(Topic topic, Project project) : base($"{topic.Id}", ItemType.Topic) { @@ -20,4 +20,4 @@ public TopicItem(Topic topic, Project project) : base($"{topic.Id}", ItemType.To public override void Refresh(Project project, ILogger log) { } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Items/VoicedLineItem.cs b/src/SerialLoops.Lib/Items/VoicedLineItem.cs index 469bf4be..afadf48c 100644 --- a/src/SerialLoops.Lib/Items/VoicedLineItem.cs +++ b/src/SerialLoops.Lib/Items/VoicedLineItem.cs @@ -10,39 +10,31 @@ namespace SerialLoops.Lib.Items; -public class VoicedLineItem : Item, ISoundItem +public class VoicedLineItem(string voiceFile, int index, Project project) + : Item(Path.GetFileNameWithoutExtension(voiceFile), ItemType.Voice), ISoundItem { - private readonly string _vceFile; - - public string VoiceFile { get; set; } - public int Index { get; set; } + public string VoiceFile { get; set; } = Path.GetRelativePath(project.IterativeDirectory, voiceFile); + public int Index { get; set; } = index; public AdxEncoding AdxType { get; set; } - public VoicedLineItem(string voiceFile, int index, Project project) : base(Path.GetFileNameWithoutExtension(voiceFile), ItemType.Voice) - { - VoiceFile = Path.GetRelativePath(project.IterativeDirectory, voiceFile); - _vceFile = voiceFile; - Index = index; - } - public IWaveProvider GetWaveProvider(ILogger log, bool loop = false) { byte[] adxBytes = []; try { - adxBytes = File.ReadAllBytes(_vceFile); + adxBytes = File.ReadAllBytes(voiceFile); } catch { - if (!File.Exists(_vceFile)) + if (!File.Exists(voiceFile)) { log.LogError("Failed to load voice file: file not found."); - log.LogWarning(_vceFile); + log.LogWarning(voiceFile); } else { log.LogError("Failed to load voice file: file invalid."); - log.LogWarning(_vceFile); + log.LogWarning(voiceFile); } } @@ -78,7 +70,7 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire WaveFileWriter.CreateWaveFile(vceCachedFile, vorbisReader.ToSampleProvider().ToWaveProvider16()); audioFile = vceCachedFile; } - using WaveStream audio = Path.GetExtension(audioFile).ToLower() switch + using WaveStream? audio = Path.GetExtension(audioFile).ToLower() switch { ".wav" => new WaveFileReader(audioFile), ".flac" => new FlacReader(audioFile), @@ -96,14 +88,14 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire if (audio.WaveFormat.Channels > 1) { log.Log("Downmixing audio from stereo to mono for AHX conversion..."); - newAudioFile = Path.Combine(Path.GetDirectoryName(vceCachedFile), $"{Path.GetFileNameWithoutExtension(vceCachedFile)}-downmixed.wav"); + newAudioFile = Path.Combine(Path.GetDirectoryName(vceCachedFile)!, $"{Path.GetFileNameWithoutExtension(vceCachedFile)}-downmixed.wav"); WaveFileWriter.CreateWaveFile(newAudioFile, audio.ToSampleProvider().ToMono().ToWaveProvider16()); } if (audio.WaveFormat.SampleRate > SoundItem.MAX_SAMPLERATE) { log.Log($"Downsampling audio from {audio.WaveFormat.SampleRate} to NDS max sample rate {SoundItem.MAX_SAMPLERATE}..."); string prevAudioFile = $"{newAudioFile}"; - newAudioFile = Path.Combine(Path.GetDirectoryName(vceCachedFile), $"{Path.GetFileNameWithoutExtension(vceCachedFile)}-downsampled.wav"); + newAudioFile = Path.Combine(Path.GetDirectoryName(vceCachedFile)!, $"{Path.GetFileNameWithoutExtension(vceCachedFile)}-downsampled.wav"); if (!string.IsNullOrEmpty(prevAudioFile)) { using WaveFileReader newAudio = new(prevAudioFile); @@ -129,5 +121,5 @@ public void Replace(string audioFile, string baseDirectory, string iterativeDire public override void Refresh(Project project, ILogger log) { - } -} \ No newline at end of file + } +} diff --git a/src/SerialLoops.Lib/Logging/LoggerNullException.cs b/src/SerialLoops.Lib/Logging/LoggerNullException.cs index e82788b5..dcfc16cc 100644 --- a/src/SerialLoops.Lib/Logging/LoggerNullException.cs +++ b/src/SerialLoops.Lib/Logging/LoggerNullException.cs @@ -2,9 +2,4 @@ namespace SerialLoops.Lib.Logging; -public class LoggerNullException : Exception -{ - public LoggerNullException() : base("No logger provided") - { - } -} \ No newline at end of file +public class LoggerNullException() : Exception("No logger provided"); \ No newline at end of file diff --git a/src/SerialLoops.Lib/Project.cs b/src/SerialLoops.Lib/Project.cs index 43b05a68..5a2450f8 100644 --- a/src/SerialLoops.Lib/Project.cs +++ b/src/SerialLoops.Lib/Project.cs @@ -31,15 +31,15 @@ public partial class Project public const string EXPORT_FORMAT = "slzip"; public static readonly JsonSerializerOptions SERIALIZER_OPTIONS = new() { Converters = { new SKColorJsonConverter() } }; - public string Name { get; set; } - public string LangCode { get; set; } - public string BaseRomHash { get; set; } - public Dictionary ItemNames { get; set; } - public Dictionary Characters { get; set; } + public string? Name { get; set; } + public string? LangCode { get; set; } + public string? BaseRomHash { get; set; } + public Dictionary? ItemNames { get; set; } + public Dictionary? Characters { get; set; } // SL settings [JsonIgnore] - public string MainDirectory => Path.Combine(Config.ProjectsDirectory, Name); + public string MainDirectory => Path.Combine(Config!.ProjectsDirectory, Name!); [JsonIgnore] public string BaseDirectory => Path.Combine(MainDirectory, "base"); [JsonIgnore] @@ -47,21 +47,21 @@ public partial class Project [JsonIgnore] public string ProjectFile => Path.Combine(MainDirectory, $"{Name}.{PROJECT_FORMAT}"); [JsonIgnore] - public Config Config { get; private set; } + public Config? Config { get; private set; } [JsonIgnore] - public ProjectSettings Settings { get; set; } + public ProjectSettings? Settings { get; set; } [JsonIgnore] public List Items { get; set; } = []; // Archives [JsonIgnore] - public ArchiveFile Dat { get; set; } + public ArchiveFile? Dat { get; set; } [JsonIgnore] - public ArchiveFile Grp { get; set; } + public ArchiveFile? Grp { get; set; } [JsonIgnore] - public ArchiveFile Evt { get; set; } + public ArchiveFile? Evt { get; set; } [JsonIgnore] - public SoundArchive Snd { get; set; } + public SoundArchive? Snd { get; set; } // Common graphics [JsonIgnore] @@ -69,37 +69,37 @@ public partial class Project [JsonIgnore] public FontFile FontMap { get; set; } = new(); [JsonIgnore] - public SKBitmap SpeakerBitmap { get; set; } + public SKBitmap? SpeakerBitmap { get; set; } [JsonIgnore] - public SKBitmap NameplateBitmap { get; set; } + public SKBitmap? NameplateBitmap { get; set; } [JsonIgnore] - public GraphicInfo NameplateInfo { get; set; } + public GraphicInfo? NameplateInfo { get; set; } [JsonIgnore] - public SKBitmap DialogueBitmap { get; set; } + public SKBitmap? DialogueBitmap { get; set; } [JsonIgnore] - public SKBitmap FontBitmap { get; set; } + public SKBitmap? FontBitmap { get; set; } // Files shared between items [JsonIgnore] - public CharacterDataFile ChrData { get; set; } + public CharacterDataFile? ChrData { get; set; } [JsonIgnore] - public EventFile EventTableFile { get; set; } + public EventFile? EventTableFile { get; set; } [JsonIgnore] - public ExtraFile Extra { get; set; } + public ExtraFile? Extra { get; set; } [JsonIgnore] - public ScenarioStruct Scenario { get; set; } + public ScenarioStruct? Scenario { get; set; } [JsonIgnore] - public SoundDSFile SoundDS { get; set; } + public SoundDSFile? SoundDS { get; set; } [JsonIgnore] - public EventFile TopicFile { get; set; } + public EventFile? TopicFile { get; set; } [JsonIgnore] - public EventFile TutorialFile { get; set; } + public EventFile? TutorialFile { get; set; } [JsonIgnore] - public MessageFile UiText { get; set; } + public MessageFile? UiText { get; set; } [JsonIgnore] - public MessageInfoFile MessInfo { get; set; } + public MessageInfoFile? MessInfo { get; set; } [JsonIgnore] - public VoiceMapFile VoiceMap { get; set; } + public VoiceMapFile? VoiceMap { get; set; } [JsonIgnore] public Dictionary LayoutFiles { get; set; } = []; @@ -111,9 +111,10 @@ public partial class Project public Project() { + Localize = s => s; } - public Project(string name, string langCode, Config config, Func localize, ILogger log) + public Project(string? name, string? langCode, Config? config, Func localize, ILogger log) { Name = name; LangCode = langCode; @@ -144,28 +145,25 @@ public enum LoadProjectState FAILED, } - public struct LoadProjectResult + public struct LoadProjectResult(LoadProjectState state, string badArchive, int badFileIndex) { - public LoadProjectState State { get; set; } - public string BadArchive { get; set; } - public int BadFileIndex { get; set; } + public LoadProjectState State { get; set; } = state; + public string BadArchive { get; set; } = badArchive; + public int BadFileIndex { get; set; } = badFileIndex; - public LoadProjectResult(LoadProjectState state, string badArchive, int badFileIndex) + public LoadProjectResult(LoadProjectState state) : this(state, string.Empty, -1) { - State = state; - BadArchive = badArchive; - BadFileIndex = badFileIndex; - } - public LoadProjectResult(LoadProjectState state) - { - State = state; - BadArchive = string.Empty; - BadFileIndex = -1; } } - public LoadProjectResult Load(Config config, ILogger log, IProgressTracker tracker) + public LoadProjectResult Load(Config? config, ILogger log, IProgressTracker tracker) { + if (config is null) + { + log.LogError("Failed to load project: config was null!"); + return new(LoadProjectState.FAILED); + } + Config = config; LoadProjectSettings(log, tracker); ClearOrCreateCaches(config.CachesDirectory, log); @@ -212,13 +210,11 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in dat.bin was detected as corrupt."); return new(LoadProjectState.CORRUPTED_FILE, "dat.bin", ex.Index); } - else - { - // If it's not a file they've modified, then they're using a bad base ROM - log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in dat.bin was detected as corrupt. " + - $"Please use a different base ROM as this one is corrupted."); - return new(LoadProjectState.CORRUPTED_FILE, "dat.bin", -1); - } + + // If it's not a file they've modified, then they're using a bad base ROM + log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in dat.bin was detected as corrupt. " + + $"Please use a different base ROM as this one is corrupted."); + return new(LoadProjectState.CORRUPTED_FILE, "dat.bin", -1); } catch (Exception ex) { @@ -239,13 +235,11 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in grp.bin was detected as corrupt."); return new(LoadProjectState.CORRUPTED_FILE, "grp.bin", ex.Index); } - else - { - // If it's not a file they've modified, then they're using a bad base ROM - log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in grp.bin was detected as corrupt. " + - $"Please use a different base ROM as this one is corrupted."); - return new(LoadProjectState.CORRUPTED_FILE, "grp.bin", -1); - } + + // If it's not a file they've modified, then they're using a bad base ROM + log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in grp.bin was detected as corrupt. " + + $"Please use a different base ROM as this one is corrupted."); + return new(LoadProjectState.CORRUPTED_FILE, "grp.bin", -1); } catch (Exception ex) { @@ -266,13 +260,11 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in evt.bin was detected as corrupt."); return new(LoadProjectState.CORRUPTED_FILE, "evt.bin", ex.Index); } - else - { - // If it's not a file they've modified, then they're using a bad base ROM - log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in evt.bin was detected as corrupt. " + - $"Please use a different base ROM as this one is corrupted."); - return new(LoadProjectState.CORRUPTED_FILE, "evt.bin", -1); - } + + // If it's not a file they've modified, then they're using a bad base ROM + log.LogError($"File {ex.Index:4} (0x{ex.Index:X3}) '{ex.Filename}' in evt.bin was detected as corrupt. " + + $"Please use a different base ROM as this one is corrupted."); + return new(LoadProjectState.CORRUPTED_FILE, "evt.bin", -1); } catch (Exception ex) { @@ -305,7 +297,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load DefaultCharacters file", ex); + log.LogException("Failed to load DefaultCharacters file", ex); return new(LoadProjectState.FAILED); } @@ -325,7 +317,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load font map", ex); + log.LogException("Failed to load font map", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -335,7 +327,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load speaker bitmap", ex); + log.LogException("Failed to load speaker bitmap", ex); return new(LoadProjectState.FAILED); } try @@ -346,7 +338,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load nameplate bitmap", ex); + log.LogException("Failed to load nameplate bitmap", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -356,7 +348,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load dialogue bitmap", ex); + log.LogException("Failed to load dialogue bitmap", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -368,7 +360,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load font bitmap", ex); + log.LogException("Failed to load font bitmap", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -381,7 +373,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load event table file", ex); + log.LogException("Failed to load event table file", ex); } tracker.Finished++; try @@ -400,7 +392,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load extra file", ex); + log.LogException("Failed to load extra file", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -412,7 +404,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load scenario file", ex); + log.LogException("Failed to load scenario file", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -422,7 +414,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load message info file", ex); + log.LogException("Failed to load message info file", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -432,7 +424,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load UI text file", ex); + log.LogException("Failed to load UI text file", ex); return new(LoadProjectState.FAILED); } tracker.Finished++; @@ -447,7 +439,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) if (entry.BgIndex1 > 0) { GraphicsFile nameGraphic = Grp.GetFileByIndex(entry.BgIndex1); - string name = $"BG_{nameGraphic.Name[0..nameGraphic.Name.LastIndexOf('_')]}"; + string name = $"BG_{nameGraphic.Name[..nameGraphic.Name.LastIndexOf('_')]}"; string bgNameBackup = name; for (int j = 1; names.Contains(name); j++) { @@ -457,11 +449,9 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) names.Add(name); return new BackgroundItem(name, i, entry, this); } - else - { - return null; - } - }).Where(b => b is not null)); + + return null; + }).Where(b => b is not null)!); } catch (Exception ex) { @@ -492,7 +482,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) try { - string[] bgmFiles = SoundDS.BgmSection.AsParallel().Where(bgm => bgm is not null).Select(bgm => Path.Combine(IterativeDirectory, "rom", "data", bgm)).ToArray(); + string[] bgmFiles = SoundDS!.BgmSection.AsParallel().Where(bgm => bgm is not null).Select(bgm => Path.Combine(IterativeDirectory, "rom", "data", bgm)).ToArray(); tracker.Focus("BGM Tracks", bgmFiles.Length); Items.AddRange(bgmFiles.AsParallel().Select((bgm, i) => { @@ -502,7 +492,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load BGM tracks", ex); + log.LogException("Failed to load BGM tracks", ex); return new(LoadProjectState.FAILED); } try @@ -517,7 +507,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load voiced lines", ex); + log.LogException("Failed to load voiced lines", ex); return new(LoadProjectState.FAILED); } @@ -555,13 +545,18 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load item file", ex); + log.LogException("Failed to load item file", ex); return new(LoadProjectState.FAILED); } try { tracker.Focus("Characters", MessInfo.MessageInfos.Count); + if (Characters is null) + { + log.LogError("Project creation failed: characters list was null!"); + return new LoadProjectResult(LoadProjectState.FAILED); + } Items.AddRange(MessInfo.MessageInfos.AsParallel().Where(m => (int)m.Character > 0).Select(m => { tracker.Finished++; @@ -570,7 +565,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load characters", ex); + log.LogException("Failed to load characters", ex); return new(LoadProjectState.FAILED); } @@ -585,7 +580,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load character sprites", ex); + log.LogException("Failed to load character sprites", ex); return new(LoadProjectState.FAILED); } @@ -601,7 +596,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load chibis", ex); + log.LogException("Failed to load chibis", ex); return new(LoadProjectState.FAILED); } @@ -613,12 +608,12 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) .Select(e => { tracker.Finished++; - return new ScriptItem(e, EventTableFile.EvtTbl, Localize, log); + return new ScriptItem(e, EventTableFile!.EvtTbl, Localize, log); })); } catch (Exception ex) { - log.LogException($"Failed to load scripts", ex); + log.LogException("Failed to load scripts", ex); return new(LoadProjectState.FAILED); } @@ -647,7 +642,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load maps", ex); + log.LogException("Failed to load maps", ex); return new(LoadProjectState.FAILED); } @@ -664,7 +659,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load place items", ex); + log.LogException("Failed to load place items", ex); return new(LoadProjectState.FAILED); } @@ -680,7 +675,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load puzzle items", ex); + log.LogException("Failed to load puzzle items", ex); return new(LoadProjectState.FAILED); } @@ -694,9 +689,9 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) // Main topics have shadow topics that are located at ID + 40 (this is actually how the game finds them) // So if we're a main topic and we see another topic 40 back, we know we're one of these shadow topics and should really be // rolled into the original main topic - if (topic.Type == TopicType.Main && Items.AsParallel().Any(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry.Id == topic.Id - 40)) + if (topic.Type == TopicType.Main && Items.AsParallel().Any(i => i.Type == ItemType.Topic && ((TopicItem)i).TopicEntry?.Id == topic.Id - 40)) { - ((TopicItem)Items.AsParallel().First(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry.Id == topic.Id - 40)).HiddenMainTopic = topic; + ((TopicItem)Items.AsParallel().First(i => i.Type == ItemType.Topic && ((TopicItem)i).TopicEntry?.Id == topic.Id - 40)).HiddenMainTopic = topic; } else { @@ -707,7 +702,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load topics", ex); + log.LogException("Failed to load topics", ex); return new(LoadProjectState.FAILED); } @@ -732,28 +727,28 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) tracker.Finished++; foreach (SystemTexture extraSysTex in systemTextureFile.SystemTextures.Where(s => Grp.Files.AsParallel().Where(g => g.Name.StartsWith("XTR")).Distinct().Select(g => g.Index).Contains(s.GrpIndex))) { - Items.Add(new SystemTextureItem(extraSysTex, this, $"SYSTEX_{Grp.GetFileByIndex(extraSysTex.GrpIndex).Name[0..^3]}")); + Items.Add(new SystemTextureItem(extraSysTex, this, $"SYSTEX_{Grp.GetFileByIndex(extraSysTex.GrpIndex).Name[..^3]}")); tracker.Finished++; } // Exclude B12 as that's the nameplates we replace in the character items and PPT_001 as that's the puzzle phase singularity we'll be replacing in the puzzle items // We also exclude the "special" graphics as they do not include all of them in the SYSTEX file (should be made to be edited manually) foreach (SystemTexture sysSysTex in systemTextureFile.SystemTextures.Where(s => Grp.Files.AsParallel().Where(g => g.Name.StartsWith("SYS") && !g.Name.Contains("_SPC_") && g.Name != "SYS_CMN_B12DNX" && g.Name != "SYS_PPT_001DNX").Select(g => g.Index).Contains(s.GrpIndex)).DistinctBy(s => s.GrpIndex)) { - if (Grp.GetFileByIndex(sysSysTex.GrpIndex).Name[0..^4].EndsWith("T6")) + if (Grp.GetFileByIndex(sysSysTex.GrpIndex).Name[..^4].EndsWith("T6")) { // special case the ep headers - Items.Add(new SystemTextureItem(sysSysTex, this, $"SYSTEX_{Grp.GetFileByIndex(sysSysTex.GrpIndex).Name[0..^3]}", height: 192)); + Items.Add(new SystemTextureItem(sysSysTex, this, $"SYSTEX_{Grp.GetFileByIndex(sysSysTex.GrpIndex).Name[..^3]}", height: 192)); } else { - Items.Add(new SystemTextureItem(sysSysTex, this, $"SYSTEX_{Grp.GetFileByIndex(sysSysTex.GrpIndex).Name[0..^3]}")); + Items.Add(new SystemTextureItem(sysSysTex, this, $"SYSTEX_{Grp.GetFileByIndex(sysSysTex.GrpIndex).Name[..^3]}")); } tracker.Finished++; } } catch (Exception ex) { - log.LogException($"Failed to load system textures", ex); + log.LogException("Failed to load system textures", ex); return new(LoadProjectState.FAILED); } @@ -833,7 +828,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load layouts", ex); + log.LogException("Failed to load layouts", ex); return new(LoadProjectState.FAILED); } @@ -849,7 +844,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load scenario", ex); + log.LogException("Failed to load scenario", ex); return new(LoadProjectState.FAILED); } @@ -865,7 +860,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load group selections", ex); + log.LogException("Failed to load group selections", ex); return new(LoadProjectState.FAILED); } @@ -874,6 +869,11 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) try { ItemNames = JsonSerializer.Deserialize>(File.ReadAllText(Extensions.GetLocalizedFilePath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Defaults", "DefaultNames"), "json"))); + if (ItemNames is null) + { + log.LogError("Failed to deserialize default item names JSON!"); + return new(LoadProjectState.FAILED); + } foreach (ItemDescription item in Items) { if (!ItemNames.ContainsKey(item.Name) && item.CanRename) @@ -884,7 +884,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) } catch (Exception ex) { - log.LogException($"Failed to load item names", ex); + log.LogException("Failed to load item names", ex); return new(LoadProjectState.FAILED); } } @@ -893,7 +893,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) { if (Items[i].CanRename || Items[i].Type == ItemType.Place) // We don't want to manually rename places, but they do use the display name pattern { - if (ItemNames.TryGetValue(Items[i].Name, out string value)) + if (ItemNames!.TryGetValue(Items[i].Name, out string? value)) { Items[i].Rename(value); } @@ -911,14 +911,14 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker) public bool VoiceMapIsV06OrHigher() { - return Evt.Files.AsParallel().Any(f => f.Name == "VOICEMAPS") && Encoding.ASCII.GetString(Evt.GetFileByName("VOICEMAPS").Data.Skip(0x08).Take(4).ToArray()) == "SUBS"; + return Evt!.Files.AsParallel().Any(f => f.Name == "VOICEMAPS") && Encoding.ASCII.GetString(Evt.GetFileByName("VOICEMAPS").Data.Skip(0x08).Take(4).ToArray()) == "SUBS"; } public void RecalculateEventTable() { short currentFlag = 0; int prevScriptIndex = 0; - foreach (EventTableEntry entry in EventTableFile.EvtTbl.Entries) + foreach (EventTableEntry entry in EventTableFile!.EvtTbl.Entries) { if (currentFlag == 0 && entry.FirstReadFlag > 0) { @@ -927,12 +927,12 @@ public void RecalculateEventTable() } else if (entry.FirstReadFlag > 0) { - currentFlag += (short)(Evt.GetFileByIndex(prevScriptIndex).ScriptSections.Count + 1); + currentFlag += (short)(Evt!.GetFileByIndex(prevScriptIndex).ScriptSections.Count + 1); entry.FirstReadFlag = currentFlag; prevScriptIndex = entry.EventFileIndex; } } - Items.Where(i => i.Type == ItemDescription.ItemType.Script).Cast().ToList().ForEach(s => s.UpdateEventTableInfo(EventTableFile.EvtTbl)); + Items.Where(i => i.Type == ItemType.Script).Cast().ToList().ForEach(s => s.UpdateEventTableInfo(EventTableFile.EvtTbl)); } public void MigrateProject(string newRom, ILogger log, IProgressTracker tracker) @@ -969,7 +969,7 @@ public static void ClearOrCreateCaches(string cachesDirectory, ILogger log) Directory.CreateDirectory(vceCache); } - public ItemDescription FindItem(string name) + public ItemDescription? FindItem(string name) { if (string.IsNullOrEmpty(name)) { @@ -978,7 +978,7 @@ public ItemDescription FindItem(string name) return Items.FirstOrDefault(i => i.DisplayName == name); } - public static (Project Project, LoadProjectResult Result) OpenProject(string projFile, Config config, Func localize, ILogger log, IProgressTracker tracker) + public static (Project? Project, LoadProjectResult Result) OpenProject(string projFile, Config? config, Func localize, ILogger log, IProgressTracker tracker) { log.Log($"Loading project from '{projFile}'..."); if (!File.Exists(projFile)) @@ -989,7 +989,12 @@ public static (Project Project, LoadProjectResult Result) OpenProject(string pro try { tracker.Focus($"{Path.GetFileNameWithoutExtension(projFile)} Project Data", 1); - Project project = JsonSerializer.Deserialize(File.ReadAllText(projFile), SERIALIZER_OPTIONS); + Project? project = JsonSerializer.Deserialize(File.ReadAllText(projFile), SERIALIZER_OPTIONS); + if (project is null) + { + log.LogError($"Project file {projFile} is not a valid JSON file -- returned null!"); + return (null, new(LoadProjectState.CORRUPTED_FILE)); + } project.Localize = localize; tracker.Finished++; LoadProjectResult result = project.Load(config, log, tracker); @@ -1072,24 +1077,29 @@ public void Export(string slzipFile, ILogger log) } } - public static (Project Project, LoadProjectResult LoadResult) Import(string slzipFile, string romPath, Config config, Func localize, ILogger log, IProgressTracker tracker) + public static (Project? Project, LoadProjectResult LoadResult) Import(string slzipFile, string romPath, Config? config, Func localize, ILogger log, IProgressTracker tracker) { try { using FileStream slzipFs = File.OpenRead(slzipFile); using ZipArchive slzip = new(slzipFs, ZipArchiveMode.Read); string slprojTemp = Path.GetTempFileName(); - slzip.Entries.FirstOrDefault(f => f.Name.EndsWith(".slproj")).ExtractToFile(slprojTemp, overwrite: true); - Project project = JsonSerializer.Deserialize(File.ReadAllText(slprojTemp), SERIALIZER_OPTIONS); + slzip.Entries.FirstOrDefault(f => f.Name.EndsWith(".slproj"))?.ExtractToFile(slprojTemp, overwrite: true); + Project? project = JsonSerializer.Deserialize(File.ReadAllText(slprojTemp), SERIALIZER_OPTIONS); + if (project is null) + { + log.LogError("Failed to import project: deserialized slproj was null!"); + return (null, new(LoadProjectState.FAILED)); + } project.Config = config; File.Delete(slprojTemp); - string oldProjectName = project.Name; + string? oldProjectName = project.Name; while (Directory.Exists(project.MainDirectory)) { - Match numEnding = ProjectNameAppendedNumber().Match(project.Name); + Match numEnding = ProjectNameAppendedNumber().Match(project.Name!); if (numEnding.Success) { - project.Name = project.Name.Replace(numEnding.Value, $"({int.Parse(numEnding.Groups["num"].Value) + 1})"); + project.Name = project.Name!.Replace(numEnding.Value, $"({int.Parse(numEnding.Groups["num"].Value) + 1})"); } else { @@ -1100,7 +1110,7 @@ public static (Project Project, LoadProjectResult LoadResult) Import(string slzi IO.OpenRom(project, romPath, log, tracker); slzip.ExtractToDirectory(project.MainDirectory, overwriteFiles: true); string newNdsProjFile = Path.Combine("rom", $"{project.Name}.xml"); - if (!project.Name.Equals(oldProjectName)) + if (!project.Name!.Equals(oldProjectName)) { string oldNdsProjFile = Path.Combine("rom", $"{oldProjectName}.xml"); File.Move(Path.Combine(project.BaseDirectory, oldNdsProjFile), Path.Combine(project.BaseDirectory, newNdsProjFile), overwrite: true); @@ -1131,7 +1141,7 @@ public List GetSearchResults(string query, ILogger logger) public List GetSearchResults(SearchQuery query, ILogger log, IProgressTracker? tracker = null) { - var term = query.Term.Trim(); + string term = query.Term?.Trim() ?? string.Empty; var searchable = Items.Where(i => query.Types.Contains(i.Type)).ToList(); tracker?.Focus($"{searchable.Count} Items", searchable.Count); @@ -1157,7 +1167,7 @@ public List GetSearchResults(SearchQuery query, ILogger log, IP public CharacterItem GetCharacterBySpeaker(Speaker speaker) { - return (CharacterItem)Items.First(i => i.Type == ItemType.Character && i.DisplayName == $"CHR_{Characters[(int)speaker].Name}"); + return (CharacterItem)Items.First(i => i.Type == ItemType.Character && i.DisplayName == $"CHR_{Characters![(int)speaker].Name}"); } private bool ItemMatches(ItemDescription item, string term, SearchQuery.DataHolder scope, ILogger logger) @@ -1171,60 +1181,63 @@ private bool ItemMatches(ItemDescription item, string term, SearchQuery.DataHold case SearchQuery.DataHolder.Background_ID: if (int.TryParse(term, out int backgroundId)) { - return item.Type == ItemDescription.ItemType.Background && ((BackgroundItem)item).Id == backgroundId; + return item.Type == ItemType.Background && ((BackgroundItem)item).Id == backgroundId; } return false; case SearchQuery.DataHolder.Dialogue_Text: if (item is ScriptItem dialogueScript) { - if (LangCode.Equals("ja", StringComparison.OrdinalIgnoreCase)) + if (LangCode!.Equals("ja", StringComparison.OrdinalIgnoreCase)) { - return dialogueScript.GetScriptCommandTree(this, logger) - .Any(s => s.Value.Any(c => c.Parameters + return dialogueScript.GetScriptCommandTree(this, logger)? + .Any(s => s.Value.Any(c => c.Parameters! .Where(p => p.Type == ScriptParameter.ParameterType.DIALOGUE) .Any(p => ((DialogueScriptParameter)p).Line.Text - .Contains(term, StringComparison.OrdinalIgnoreCase)))); - } - else - { - return dialogueScript.GetScriptCommandTree(this, logger) - .Any(s => s.Value.Any(c => c.Parameters - .Where(p => p.Type == ScriptParameter.ParameterType.DIALOGUE) - .Any(p => ((DialogueScriptParameter)p).Line.Text - .GetSubstitutedString(this).Contains(term, StringComparison.OrdinalIgnoreCase)))); + .Contains(term, StringComparison.OrdinalIgnoreCase)))) ?? false; } + + return dialogueScript.GetScriptCommandTree(this, logger)? + .Any(s => s.Value.Any(c => c.Parameters! + .Where(p => p.Type == ScriptParameter.ParameterType.DIALOGUE) + .Any(p => ((DialogueScriptParameter)p).Line.Text + .GetSubstitutedString(this).Contains(term, StringComparison.OrdinalIgnoreCase)))) ?? false; } return false; case SearchQuery.DataHolder.Flag: if (item is ScriptItem flagScript) { - return flagScript.GetScriptCommandTree(this, logger) - .Any(s => s.Value.Any(c => c.Parameters + return flagScript.GetScriptCommandTree(this, logger)? + .Any(s => s.Value.Any(c => c.Parameters! .Where(p => p.Type == ScriptParameter.ParameterType.FLAG) .Any(p => ((FlagScriptParameter)p).FlagName - .Contains(term, StringComparison.OrdinalIgnoreCase)))); + .Contains(term, StringComparison.OrdinalIgnoreCase)))) ?? false; } - else if (short.TryParse(term, out short flagTerm)) + + if (short.TryParse(term, out short flagTerm)) { if (item is BackgroundMusicItem flagBgm) { return flagBgm.Flag == flagTerm; } - else if (item is BackgroundItem flagBg) + + if (item is BackgroundItem flagBg) { return flagBg.Flag == flagTerm; } - else if (item is TopicItem flagTopic) + + if (item is TopicItem flagTopic) { - return flagTopic.TopicEntry.Id == flagTerm; + return flagTopic.TopicEntry?.Id == flagTerm; } - else if (item is PuzzleItem flagPuzzle) + + if (item is PuzzleItem flagPuzzle) { return flagPuzzle.Puzzle.Settings.Unknown15 == flagTerm || flagPuzzle.Puzzle.Settings.Unknown16 == flagTerm; } - else if (item is GroupSelectionItem flagGroupSelection) + + if (item is GroupSelectionItem flagGroupSelection) { return flagGroupSelection.Selection.Activities.Any(a => a?.Routes.Any(r => r?.Flag == flagTerm) ?? false); } @@ -1234,7 +1247,7 @@ private bool ItemMatches(ItemDescription item, string term, SearchQuery.DataHold case SearchQuery.DataHolder.Conditional: if (item is ScriptItem conditionalScript) { - return conditionalScript.Event.ConditionalsSection?.Objects? + return conditionalScript.Event?.ConditionalsSection?.Objects? .Any(c => !string.IsNullOrEmpty(c) && c.Contains(term, StringComparison.OrdinalIgnoreCase)) ?? false; } return false; @@ -1242,11 +1255,11 @@ private bool ItemMatches(ItemDescription item, string term, SearchQuery.DataHold case SearchQuery.DataHolder.Speaker_Name: if (item is ScriptItem speakerScript) { - return speakerScript.GetScriptCommandTree(this, logger) - .Any(s => s.Value.Any(c => c.Parameters + return speakerScript.GetScriptCommandTree(this, logger)? + .Any(s => s.Value.Any(c => c.Parameters! .Where(p => p.Type == ScriptParameter.ParameterType.DIALOGUE) - .Any(p => Characters[(int)((DialogueScriptParameter)p).Line.Speaker].Name - .Contains(term, StringComparison.OrdinalIgnoreCase)))); + .Any(p => Characters![(int)((DialogueScriptParameter)p).Line.Speaker].Name + .Contains(term, StringComparison.OrdinalIgnoreCase)))) ?? false; } return false; @@ -1279,7 +1292,7 @@ private bool ItemMatches(ItemDescription item, string term, SearchQuery.DataHold private bool ItemIsInEpisode(ItemDescription item, int episodeNum, bool unique) { - int scenarioEpIndex = Scenario.Commands.FindIndex(c => c.Verb == ScenarioCommand.ScenarioVerb.NEW_GAME && c.Parameter == episodeNum); + int scenarioEpIndex = Scenario!.Commands.FindIndex(c => c.Verb == ScenarioCommand.ScenarioVerb.NEW_GAME && c.Parameter == episodeNum); if (scenarioEpIndex >= 0) { int scenarioNextEpIndex = Scenario.Commands.FindIndex(c => c.Verb == ScenarioCommand.ScenarioVerb.NEW_GAME && c.Parameter == episodeNum + 1); @@ -1287,32 +1300,28 @@ private bool ItemIsInEpisode(ItemDescription item, int episodeNum, bool unique) { return ScriptIsInEpisode(script, scenarioEpIndex, scenarioNextEpIndex); } - else + + List references = item.GetReferencesTo(this); + if (unique) { - List references = item.GetReferencesTo(this); - if (unique) - { - return references.Where(r => r.Type == ItemDescription.ItemType.Script).Any() && - references.Where(r => r.Type == ItemDescription.ItemType.Script) - .All(r => ScriptIsInEpisode((ScriptItem)r, scenarioEpIndex, scenarioNextEpIndex)); - } - else - { - return references.Any(r => r.Type == ItemDescription.ItemType.Script && ScriptIsInEpisode((ScriptItem)r, scenarioEpIndex, scenarioNextEpIndex)); - } + return references.Where(r => r.Type == ItemType.Script).Any() && + references.Where(r => r.Type == ItemType.Script) + .All(r => ScriptIsInEpisode((ScriptItem)r, scenarioEpIndex, scenarioNextEpIndex)); } + + return references.Any(r => r.Type == ItemType.Script && ScriptIsInEpisode((ScriptItem)r, scenarioEpIndex, scenarioNextEpIndex)); } return false; } private bool ScriptIsInEpisode(ScriptItem script, int scenarioEpIndex, int scenarioNextEpIndex) { - int scriptFileScenarioIndex = Scenario.Commands.FindIndex(c => c.Verb == ScenarioCommand.ScenarioVerb.LOAD_SCENE && c.Parameter == script.Event.Index); + int scriptFileScenarioIndex = Scenario!.Commands.FindIndex(c => c.Verb == ScenarioCommand.ScenarioVerb.LOAD_SCENE && c.Parameter == script.Event?.Index); if (scriptFileScenarioIndex < 0) { List references = script.GetReferencesTo(this); - ItemDescription groupSelection = references.Find(r => r.Type == ItemDescription.ItemType.Group_Selection); + ItemDescription? groupSelection = references.Find(r => r.Type == ItemType.Group_Selection); if (groupSelection is not null) { scriptFileScenarioIndex = Scenario.Commands.FindIndex(c => c.Verb == ScenarioCommand.ScenarioVerb.ROUTE_SELECT && c.Parameter == ((GroupSelectionItem)groupSelection).Index); @@ -1328,4 +1337,4 @@ private bool ScriptIsInEpisode(ScriptItem script, int scenarioEpIndex, int scena [GeneratedRegex(@"\((?\d+)\)")] private static partial Regex ProjectNameAppendedNumber(); -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/ProjectSettings.cs b/src/SerialLoops.Lib/ProjectSettings.cs index 2c5f29ea..c26c8abf 100644 --- a/src/SerialLoops.Lib/ProjectSettings.cs +++ b/src/SerialLoops.Lib/ProjectSettings.cs @@ -42,16 +42,16 @@ public SKBitmap Icon GraphicsFile grp = new() { Name = "ICON", - PixelData = new(), - PaletteData = new(), + PixelData = [], + PaletteData = [], }; - grp.Initialize(Array.Empty(), 0, _log); + grp.Initialize([], 0, _log); grp.FileFunction = GraphicsFile.Function.SHTX; grp.ImageForm = GraphicsFile.Form.TILE; grp.ImageTileForm = GraphicsFile.TileForm.GBA_4BPP; grp.Width = 32; grp.Height = 32; - grp.Palette = new(new SKColor[16]); + grp.Palette = [..new SKColor[16]]; grp.SetImage(value, setPalette: true, transparentIndex: 0, newSize: true); Banner.Image = grp.PixelData.ToArray(); diff --git a/src/SerialLoops.Lib/ProjectsCache.cs b/src/SerialLoops.Lib/ProjectsCache.cs index 0f715681..29246cd7 100644 --- a/src/SerialLoops.Lib/ProjectsCache.cs +++ b/src/SerialLoops.Lib/ProjectsCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text.Json; @@ -10,19 +11,28 @@ public class ProjectsCache { private const int MAX_RECENT_PROJECTS = 10; [JsonIgnore] - public string CacheFilePath { get; set; } - public List RecentProjects { get; set; } - public Dictionary> RecentWorkspaces { get; set; } + public string? CacheFilePath { get; set; } + public List? RecentProjects { get; set; } + public Dictionary>? RecentWorkspaces { get; set; } public bool HadProjectOpenOnLastClose { get; set; } public void Save(ILogger log) { + if (CacheFilePath is null) + { + log.LogError("Cache file path is null!"); + return; + } log.Log($"Caching recent projects and workspaces to '{CacheFilePath}'..."); IO.WriteStringFile(CacheFilePath, JsonSerializer.Serialize(this), log); } - - public static ProjectsCache LoadCache(Config config, ILogger log) + + public static ProjectsCache? LoadCache(Config? config, ILogger log) { + if (config is null) + { + return null; + } string recentProjectsJson = Path.Combine(config.UserDirectory, "projects_cache.json"); if (!File.Exists(recentProjectsJson)) { @@ -35,7 +45,11 @@ public static ProjectsCache LoadCache(Config config, ILogger log) try { - ProjectsCache recentProjects = JsonSerializer.Deserialize(File.ReadAllText(recentProjectsJson)); + ProjectsCache? recentProjects = JsonSerializer.Deserialize(File.ReadAllText(recentProjectsJson)); + if (recentProjects is null) + { + throw new NullReferenceException("Failed to parse project cache -- value was null!"); + } recentProjects.CacheFilePath = recentProjectsJson; return recentProjects; } @@ -47,7 +61,7 @@ public static ProjectsCache LoadCache(Config config, ILogger log) return defaultRecentProjects; } } - + private static ProjectsCache GetDefault() { return new() @@ -59,19 +73,19 @@ private static ProjectsCache GetDefault() public void CacheRecentProject(string projectPath, List workspaceItems) { - if (RecentProjects.Contains(projectPath)) + if (RecentProjects!.Contains(projectPath)) { RecentProjects.Remove(projectPath); - RecentWorkspaces.Remove(projectPath); + RecentWorkspaces!.Remove(projectPath); } if (RecentProjects.Count >= MAX_RECENT_PROJECTS) { - string lastProject = RecentProjects[RecentProjects.Count - 1]; + string lastProject = RecentProjects[^1]; RecentProjects.Remove(lastProject); - RecentWorkspaces.Remove(lastProject); + RecentWorkspaces!.Remove(lastProject); } RecentProjects.Insert(0, projectPath); - RecentWorkspaces.Add(projectPath, workspaceItems); + RecentWorkspaces!.Add(projectPath, workspaceItems); } - -} \ No newline at end of file + +} diff --git a/src/SerialLoops.Lib/SaveFile/SaveFilePreview.cs b/src/SerialLoops.Lib/SaveFile/SaveFilePreview.cs index 449adc2b..fed6787a 100644 --- a/src/SerialLoops.Lib/SaveFile/SaveFilePreview.cs +++ b/src/SerialLoops.Lib/SaveFile/SaveFilePreview.cs @@ -24,7 +24,7 @@ public SKBitmap DrawPreview() DrawBox(canvas); if (_slotData.EpisodeNumber == 0) { - DrawText(canvas, _project.UiText.Messages[27]); + DrawText(canvas, _project.UiText!.Messages[27]); } else { @@ -43,7 +43,7 @@ public SKBitmap DrawPreview() ); } - private void DrawText(SKCanvas canvas, string text, int x = 10, int y = 5, SKPaint paint = null) + private void DrawText(SKCanvas canvas, string text, int x = 10, int y = 5, SKPaint? paint = null) { canvas.DrawHaroohieText( _project.LangCode != "ja" ? text.GetOriginalString(_project) : text, @@ -88,7 +88,7 @@ private void DrawEpisodeNumber(SKCanvas canvas, int number) SKCanvas episodeCanvas = new(episodeNumber); // Draw "EPISODE: (number)" - var numberXOffSet = 8 * (number - 1); + int numberXOffSet = 8 * (number - 1); episodeCanvas.DrawBitmap(bitmap, 0, 0); episodeCanvas.DrawBitmap( bitmap, @@ -155,6 +155,6 @@ private static void DrawLargeGlyph(char glyph, SKCanvas canvas, SKBitmap bitmap, private string GetEpisodeTitle(int number) { - return _project.UiText.Messages[16 + number]; + return _project.UiText!.Messages[16 + number]; } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs index 3e25e450..9c185533 100644 --- a/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs @@ -3,20 +3,15 @@ namespace SerialLoops.Lib.Script.Parameters; -public class BgScriptParameter : ScriptParameter +public class BgScriptParameter(string name, BackgroundItem background, bool kinetic) + : ScriptParameter(name, ParameterType.BG) { - public BackgroundItem Background { get; set; } - public bool Kinetic { get; set; } - public override short[] GetValues(object obj = null) => [(short)(Background?.Id ?? 0)]; - - public BgScriptParameter(string name, BackgroundItem background, bool kinetic) : base(name, ParameterType.BG) - { - Background = background; - Kinetic = kinetic; - } + public BackgroundItem Background { get; set; } = background; + public bool Kinetic { get; set; } = kinetic; + public override short[] GetValues(object? obj = null) => [(short)(Background?.Id ?? 0)]; public override BgScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Background, Kinetic); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/BgScrollDirectionScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/BgScrollDirectionScriptParameter.cs index 1e9ec42e..c784f8a5 100644 --- a/src/SerialLoops.Lib/Script/Parameters/BgScrollDirectionScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/BgScrollDirectionScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class BgScrollDirectionScriptParameter : ScriptParameter +public class BgScrollDirectionScriptParameter(string name, short scrollDirection) + : ScriptParameter(name, ParameterType.BG_SCROLL_DIRECTION) { - public BgScrollDirection ScrollDirection { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)ScrollDirection }; - - public BgScrollDirectionScriptParameter(string name, short scrollDirection) : base(name, ParameterType.BG_SCROLL_DIRECTION) - { - ScrollDirection = (BgScrollDirection)scrollDirection; - } + public BgScrollDirection ScrollDirection { get; set; } = (BgScrollDirection)scrollDirection; + public override short[] GetValues(object? obj = null) => [(short)ScrollDirection]; public override BgScrollDirectionScriptParameter Clone(Project project, EventFile eventFile) { @@ -27,4 +23,4 @@ public enum BgScrollDirection : short DIAGONAL_LEFT_UP = 6, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/BgmModeScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/BgmModeScriptParameter.cs index 501f6af7..a20af3e9 100644 --- a/src/SerialLoops.Lib/Script/Parameters/BgmModeScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/BgmModeScriptParameter.cs @@ -2,15 +2,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class BgmModeScriptParameter : ScriptParameter +public class BgmModeScriptParameter(string name, short mode) : ScriptParameter(name, ParameterType.BGM_MODE) { - public BgmMode Mode { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Mode }; - - public BgmModeScriptParameter(string name, short mode) : base(name, ParameterType.BGM_MODE) - { - Mode = (BgmMode)mode; - } + public BgmMode Mode { get; set; } = (BgmMode)mode; + public override short[] GetValues(object? obj = null) => [(short)Mode]; public enum BgmMode : short { @@ -22,4 +17,4 @@ public override BgmModeScriptParameter Clone(Project project, EventFile eventFil { return new(Name, (short)Mode); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/BgmScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/BgmScriptParameter.cs index 4951282d..187abfbf 100644 --- a/src/SerialLoops.Lib/Script/Parameters/BgmScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/BgmScriptParameter.cs @@ -3,18 +3,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class BgmScriptParameter : ScriptParameter +public class BgmScriptParameter(string name, BackgroundMusicItem bgm) : ScriptParameter(name, ParameterType.BGM) { - public BackgroundMusicItem Bgm { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Bgm.Index }; - - public BgmScriptParameter(string name, BackgroundMusicItem bgm) : base(name, ParameterType.BGM) - { - Bgm = bgm; - } + public BackgroundMusicItem Bgm { get; set; } = bgm; + public override short[] GetValues(object? obj = null) => [(short)Bgm.Index]; public override BgmScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Bgm); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/BoolScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/BoolScriptParameter.cs index f56186eb..9df20a78 100644 --- a/src/SerialLoops.Lib/Script/Parameters/BoolScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/BoolScriptParameter.cs @@ -7,10 +7,10 @@ public class BoolScriptParameter(string name, bool value, short trueValue = 1, s public bool Value { get; set; } = value; public short TrueValue { get; set; } = trueValue; public short FalseValue { get; set; } = falseValue; - public override short[] GetValues(object obj = null) => [Value ? TrueValue : FalseValue]; + public override short[] GetValues(object? obj = null) => [Value ? TrueValue : FalseValue]; public override BoolScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Value); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ChessFileScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ChessFileScriptParameter.cs index 6d29ce4e..d3da4b8a 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ChessFileScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ChessFileScriptParameter.cs @@ -2,18 +2,14 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ChessFileScriptParameter : ScriptParameter +public class ChessFileScriptParameter(string name, short chessFileIndex) + : ScriptParameter(name, ParameterType.CHESS_FILE) { - public short ChessFileIndex { get; set; } - public override short[] GetValues(object obj = null) => new short[] { ChessFileIndex }; - - public ChessFileScriptParameter(string name, short chessFileIndex) : base(name, ParameterType.CHESS_FILE) - { - ChessFileIndex = chessFileIndex; - } + public short ChessFileIndex { get; set; } = chessFileIndex; + public override short[] GetValues(object? obj = null) => [ChessFileIndex]; public override ChessFileScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, ChessFileIndex); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ChessPieceScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ChessPieceScriptParameter.cs index e9cf55ee..3549db17 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ChessPieceScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ChessPieceScriptParameter.cs @@ -2,18 +2,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ChessPieceScriptParameter : ScriptParameter +public class ChessPieceScriptParameter(string name, short chessPiece) : ScriptParameter(name, ParameterType.CHESS_PIECE) { - public short ChessPiece { get; set; } - public override short[] GetValues(object obj = null) => new short[] { ChessPiece }; - - public ChessPieceScriptParameter(string name, short chessPiece) : base(name, ParameterType.CHESS_PIECE) - { - ChessPiece = chessPiece; - } + public short ChessPiece { get; set; } = chessPiece; + public override short[] GetValues(object? obj = null) => [ChessPiece]; public override ChessPieceScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, ChessPiece); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ChessSpaceScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ChessSpaceScriptParameter.cs index f5fd71f7..9d87be85 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ChessSpaceScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ChessSpaceScriptParameter.cs @@ -2,19 +2,14 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ChessSpaceScriptParameter : ScriptParameter +public class ChessSpaceScriptParameter(string name, short spaceIndex) : ScriptParameter(name, ParameterType.CHESS_SPACE) { - public short SpaceIndex { get; set; } - public override short[] GetValues(object obj = null) => new short[] { SpaceIndex }; - - public ChessSpaceScriptParameter(string name, short spaceIndex) : base(name, ParameterType.CHESS_SPACE) - { - SpaceIndex = spaceIndex; - } + public short SpaceIndex { get; set; } = spaceIndex; + public override short[] GetValues(object? obj = null) => [SpaceIndex]; public override ChessSpaceScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, SpaceIndex); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ChibiEmoteScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ChibiEmoteScriptParameter.cs index 05ff2bf2..dca6a308 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ChibiEmoteScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ChibiEmoteScriptParameter.cs @@ -2,15 +2,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ChibiEmoteScriptParameter : ScriptParameter +public class ChibiEmoteScriptParameter(string name, short emote) : ScriptParameter(name, ParameterType.CHIBI_EMOTE) { - public ChibiEmote Emote { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Emote }; - - public ChibiEmoteScriptParameter(string name, short emote) : base(name, ParameterType.CHIBI_EMOTE) - { - Emote = (ChibiEmote)emote; - } + public ChibiEmote Emote { get; set; } = (ChibiEmote)emote; + public override short[] GetValues(object? obj = null) => [(short)Emote]; public override ChibiEmoteScriptParameter Clone(Project project, EventFile eventFile) { @@ -25,4 +20,4 @@ public enum ChibiEmote : short MUSIC_NOTE = 4, SWEAT_DROP = 5, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ChibiEnterExitScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ChibiEnterExitScriptParameter.cs index 468c4699..2f594047 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ChibiEnterExitScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ChibiEnterExitScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ChibiEnterExitScriptParameter : ScriptParameter +public class ChibiEnterExitScriptParameter(string name, short mode) + : ScriptParameter(name, ParameterType.CHIBI_ENTER_EXIT) { - public ChibiEnterExitType Mode { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Mode }; - - public ChibiEnterExitScriptParameter(string name, short mode) : base(name, ParameterType.CHIBI_ENTER_EXIT) - { - Mode = (ChibiEnterExitType)mode; - } + public ChibiEnterExitType Mode { get; set; } = (ChibiEnterExitType)mode; + public override short[] GetValues(object? obj = null) => [(short)Mode]; public override ChibiEnterExitScriptParameter Clone(Project project, EventFile eventFile) { @@ -22,4 +18,4 @@ public enum ChibiEnterExitType ENTER = 0, EXIT = 1, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ChibiScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ChibiScriptParameter.cs index 70063e86..95aee45d 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ChibiScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ChibiScriptParameter.cs @@ -3,18 +3,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ChibiScriptParameter : ScriptParameter +public class ChibiScriptParameter(string name, ChibiItem chibi) : ScriptParameter(name, ParameterType.CHIBI) { - public ChibiItem Chibi { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Chibi.TopScreenIndex }; - - public ChibiScriptParameter(string name, ChibiItem chibi) : base(name, ParameterType.CHIBI) - { - Chibi = chibi; - } + public ChibiItem Chibi { get; set; } = chibi; + public override short[] GetValues(object? obj = null) => [(short)Chibi.TopScreenIndex]; public override ChibiScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Chibi); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ColorMonochromeScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ColorMonochromeScriptParameter.cs index c5fbc675..812b4802 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ColorMonochromeScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ColorMonochromeScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ColorMonochromeScriptParameter : ScriptParameter +public class ColorMonochromeScriptParameter(string name, short colorType) + : ScriptParameter(name, ParameterType.COLOR_MONOCHROME) { - public ColorMonochrome ColorType { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)ColorType }; - - public ColorMonochromeScriptParameter(string name, short colorType) : base(name, ParameterType.COLOR_MONOCHROME) - { - ColorType = (ColorMonochrome)colorType; - } + public ColorMonochrome ColorType { get; set; } = (ColorMonochrome)colorType; + public override short[] GetValues(object? obj = null) => [(short)ColorType]; public override ColorMonochromeScriptParameter Clone(Project project, EventFile eventFile) { @@ -23,4 +19,4 @@ public enum ColorMonochrome : short BLACK = 1, WHITE = 2, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ColorScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ColorScriptParameter.cs index f29af59d..22e45796 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ColorScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ColorScriptParameter.cs @@ -3,19 +3,14 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ColorScriptParameter : ScriptParameter +public class ColorScriptParameter(string name, short red) : ScriptParameter(name, ParameterType.COLOR) { - private byte _red; + private byte _red = (byte)red; private byte _green; private byte _blue; public SKColor Color { get; set; } - public override short[] GetValues(object obj = null) => new short[] { _red, _green, _blue }; - - public ColorScriptParameter(string name, short red) : base(name, ParameterType.COLOR) - { - _red = (byte)red; - } + public override short[] GetValues(object? obj = null) => [_red, _green, _blue]; public override ColorScriptParameter Clone(Project project, EventFile eventFile) { @@ -33,4 +28,4 @@ public void SetBlue(short blue) Color = new(_red, _green, _blue); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ConditionalScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ConditionalScriptParameter.cs index 5c9026bd..68244db1 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ConditionalScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ConditionalScriptParameter.cs @@ -2,15 +2,12 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ConditionalScriptParameter : ScriptParameter +public class ConditionalScriptParameter(string name, string value) : ScriptParameter(name, ParameterType.CONDITIONAL) { - public string Conditional { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)((EventFile)obj).ConditionalsSection.Objects.FindIndex(c => c.Equals(Conditional)) }; + public string Conditional { get; set; } = value; - public ConditionalScriptParameter(string name, string value) : base(name, ParameterType.CONDITIONAL) - { - Conditional = value; - } + public override short[] GetValues(object? obj = null) => [(short)((EventFile)obj!).ConditionalsSection.Objects.FindIndex(c => c.Equals(Conditional)) + ]; public override ConditionalScriptParameter Clone(Project project, EventFile eventFile) { @@ -18,4 +15,4 @@ public override ConditionalScriptParameter Clone(Project project, EventFile even eventFile.ConditionalsSection.Objects.Add(Conditional); return new(Name, eventFile.ConditionalsSection.Objects[newIndex]); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/DialoguePropertyScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/DialoguePropertyScriptParameter.cs index cb81460d..aaced06a 100644 --- a/src/SerialLoops.Lib/Script/Parameters/DialoguePropertyScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/DialoguePropertyScriptParameter.cs @@ -4,18 +4,16 @@ namespace SerialLoops.Lib.Script.Parameters; -public class DialoguePropertyScriptParameter : ScriptParameter +public class DialoguePropertyScriptParameter(string name, CharacterItem character) + : ScriptParameter(name, ParameterType.CHARACTER) { - public CharacterItem Character { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)((MessageInfoFile)obj).MessageInfos.FindIndex(m => m.Character == Character.MessageInfo.Character) }; + public CharacterItem Character { get; set; } = character; - public DialoguePropertyScriptParameter(string name, CharacterItem character) : base(name, ParameterType.CHARACTER) - { - Character = character; - } + public override short[] GetValues(object? obj = null) => [(short)((MessageInfoFile)obj!).MessageInfos.FindIndex(m => m.Character == Character.MessageInfo.Character) + ]; public override DialoguePropertyScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Character); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/DialogueScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/DialogueScriptParameter.cs index fbdd89ba..31759f11 100644 --- a/src/SerialLoops.Lib/Script/Parameters/DialogueScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/DialogueScriptParameter.cs @@ -4,15 +4,12 @@ namespace SerialLoops.Lib.Script.Parameters; -public class DialogueScriptParameter : ScriptParameter +public class DialogueScriptParameter(string name, DialogueLine line) : ScriptParameter(name, ParameterType.DIALOGUE) { - public DialogueLine Line { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)((EventFile)obj).DialogueSection.Objects.FindIndex(l => l == Line) }; + public DialogueLine Line { get; set; } = line; - public DialogueScriptParameter(string name, DialogueLine line) : base(name, ParameterType.DIALOGUE) - { - Line = line; - } + public override short[] GetValues(object? obj = null) => [(short)((EventFile)obj!).DialogueSection.Objects.FindIndex(l => l == Line) + ]; public override DialogueScriptParameter Clone(Project project, EventFile eventFile) { @@ -23,82 +20,74 @@ public override DialogueScriptParameter Clone(Project project, EventFile eventFi public static SKPaint Paint00 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 1.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint01 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.69f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.69f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.38f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint02 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.96f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.96f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.96f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint03 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.65f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.67f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.75f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint04 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.55f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.48f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.65f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint05 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.75f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.14f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.23f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint06 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.36f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.36f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.36f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; public static SKPaint Paint07 { get; } = new() { - ColorFilter = SKColorFilter.CreateColorMatrix(new float[] - { + ColorFilter = SKColorFilter.CreateColorMatrix([ 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, - 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, - }), + 0.00f, 0.00f, 0.00f, 1.00f, 0.00f + ]), }; -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/EpisodeHeaderScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/EpisodeHeaderScriptParameter.cs index 9c1234d1..2f7600c5 100644 --- a/src/SerialLoops.Lib/Script/Parameters/EpisodeHeaderScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/EpisodeHeaderScriptParameter.cs @@ -7,19 +7,19 @@ namespace SerialLoops.Lib.Script.Parameters; public class EpisodeHeaderScriptParameter(string name, short epHeaderIndex) : ScriptParameter(name, ParameterType.EPISODE_HEADER) { public Episode EpisodeHeaderIndex { get; set; } = (Episode)epHeaderIndex; - public override short[] GetValues(object obj = null) => new short[] { (short)EpisodeHeaderIndex }; + public override short[] GetValues(object? obj = null) => [(short)EpisodeHeaderIndex]; public override EpisodeHeaderScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, (short)EpisodeHeaderIndex); } - public SystemTextureItem GetTexture(Project project) + public SystemTextureItem? GetTexture(Project project) { return GetTexture(EpisodeHeaderIndex, project); } - public static SystemTextureItem GetTexture(Episode episode, Project project) + public static SystemTextureItem? GetTexture(Episode episode, Project project) { // We use names here because display names can change but names cannot return episode switch @@ -50,4 +50,4 @@ public enum Episode EPISODE_5 = 5, EPILOGUE = 6, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/FlagScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/FlagScriptParameter.cs index 8b681519..f908568c 100644 --- a/src/SerialLoops.Lib/Script/Parameters/FlagScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/FlagScriptParameter.cs @@ -2,21 +2,16 @@ namespace SerialLoops.Lib.Script.Parameters; -public class FlagScriptParameter : ScriptParameter +public class FlagScriptParameter(string name, short id) : ScriptParameter(name, ParameterType.FLAG) { - private short _internalFlagId; + private short _internalFlagId = id; public short Id { get => (short)(_internalFlagId - 1); set => _internalFlagId = (short)(value + 1); } public string FlagName => Id > 100 && Id < 121 ? $"G{Id - 100:D2}" : $"F{Id:D2}"; - public override short[] GetValues(object obj = null) => new short[] { Id }; - - public FlagScriptParameter(string name, short id) : base(name, ParameterType.FLAG) - { - _internalFlagId = id; - } + public override short[] GetValues(object? obj = null) => [Id]; public override FlagScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Id); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/FriendshipLevelScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/FriendshipLevelScriptParameter.cs index 63447bee..38d2e6d8 100644 --- a/src/SerialLoops.Lib/Script/Parameters/FriendshipLevelScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/FriendshipLevelScriptParameter.cs @@ -2,7 +2,8 @@ namespace SerialLoops.Lib.Script.Parameters; -public class FriendshipLevelScriptParameter : ScriptParameter +public class FriendshipLevelScriptParameter(string name, short character) + : ScriptParameter(name, ParameterType.FRIENDSHIP_LEVEL) { public enum FriendshipCharacter : short { @@ -14,17 +15,12 @@ public enum FriendshipCharacter : short Tsuruya = 7, } - public FriendshipCharacter Character { get; set; } + public FriendshipCharacter Character { get; set; } = (FriendshipCharacter)character; - public override short[] GetValues(object obj = null) => new short[] { (short)Character }; - - public FriendshipLevelScriptParameter(string name, short character) : base(name, ParameterType.FRIENDSHIP_LEVEL) - { - Character = (FriendshipCharacter)character; - } + public override short[] GetValues(object? obj = null) => [(short)Character]; public override FriendshipLevelScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, (short)Character); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ItemLocationScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ItemLocationScriptParameter.cs index a115185c..396c8d39 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ItemLocationScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ItemLocationScriptParameter.cs @@ -6,10 +6,10 @@ namespace SerialLoops.Lib.Script.Parameters; public class ItemLocationScriptParameter(string name, short itemLocation) : ScriptParameter(name, ParameterType.ITEM_LOCATION) { public ItemItem.ItemLocation Location { get; set; } = (ItemItem.ItemLocation)itemLocation; - public override short[] GetValues(object obj = null) => [(short)Location]; + public override short[] GetValues(object? obj = null) => [(short)Location]; public override ItemLocationScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, (short)Location); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ItemScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ItemScriptParameter.cs index 730eda01..b47448c8 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ItemScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ItemScriptParameter.cs @@ -5,10 +5,10 @@ namespace SerialLoops.Lib.Script.Parameters; public class ItemScriptParameter(string name, short itemIndex) : ScriptParameter(name, ParameterType.ITEM) { public short ItemIndex { get; set; } = itemIndex; - public override short[] GetValues(object obj = null) => new short[] { ItemIndex }; + public override short[] GetValues(object? obj = null) => [ItemIndex]; public override ItemScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, ItemIndex); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ItemTransitionScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ItemTransitionScriptParameter.cs index d8b8a1c7..21935987 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ItemTransitionScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ItemTransitionScriptParameter.cs @@ -6,10 +6,10 @@ namespace SerialLoops.Lib.Script.Parameters; public class ItemTransitionScriptParameter(string name, short itemTransition) : ScriptParameter(name, ParameterType.ITEM_TRANSITION) { public ItemItem.ItemTransition Transition { get; set; } = (ItemItem.ItemTransition)itemTransition; - public override short[] GetValues(object obj = null) => [(short)Transition]; + public override short[] GetValues(object? obj = null) => [(short)Transition]; public override ItemTransitionScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, (short)Transition); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/MapScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/MapScriptParameter.cs index 4bbd80a1..d8fa2725 100644 --- a/src/SerialLoops.Lib/Script/Parameters/MapScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/MapScriptParameter.cs @@ -3,18 +3,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class MapScriptParameter : ScriptParameter +public class MapScriptParameter(string name, MapItem map) : ScriptParameter(name, ParameterType.MAP) { - public MapItem Map { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Map.Map.Index }; - - public MapScriptParameter(string name, MapItem map) : base(name, ParameterType.MAP) - { - Map = map; - } + public MapItem Map { get; set; } = map; + public override short[] GetValues(object? obj = null) => [(short)(Map.Map?.Index ?? 0)]; public override MapScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Map); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/OptionScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/OptionScriptParameter.cs index 567c14e4..89be7d9c 100644 --- a/src/SerialLoops.Lib/Script/Parameters/OptionScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/OptionScriptParameter.cs @@ -2,18 +2,16 @@ namespace SerialLoops.Lib.Script.Parameters; -public class OptionScriptParameter : ScriptParameter +public class OptionScriptParameter(string name, ChoicesSectionEntry option) + : ScriptParameter(name, ParameterType.OPTION) { - public ChoicesSectionEntry Option { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)((EventFile)obj).ChoicesSection.Objects.IndexOf(Option) }; + public ChoicesSectionEntry Option { get; set; } = option; - public OptionScriptParameter(string name, ChoicesSectionEntry option) : base(name, ParameterType.OPTION) - { - Option = option; - } + public override short[] GetValues(object? obj = null) => [(short)((EventFile)obj!).ChoicesSection.Objects.IndexOf(Option) + ]; public override OptionScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Option); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/PaletteEffectScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/PaletteEffectScriptParameter.cs index 036e1e31..c664c117 100644 --- a/src/SerialLoops.Lib/Script/Parameters/PaletteEffectScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/PaletteEffectScriptParameter.cs @@ -3,15 +3,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class PaletteEffectScriptParameter : ScriptParameter +public class PaletteEffectScriptParameter(string name, short effect) + : ScriptParameter(name, ParameterType.PALETTE_EFFECT) { - public PaletteEffect Effect { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Effect }; - - public PaletteEffectScriptParameter(string name, short effect) : base(name, ParameterType.PALETTE_EFFECT) - { - Effect = (PaletteEffect)effect; - } + public PaletteEffect Effect { get; set; } = (PaletteEffect)effect; + public override short[] GetValues(object? obj = null) => [(short)Effect]; public override PaletteEffectScriptParameter Clone(Project project, EventFile eventFile) { @@ -89,4 +85,4 @@ public static SKPaint GetPaletteEffectPaint(PaletteEffect effect) 0.00f, 0.00f, 0.00f, 1.00f, 0.00f, ]), }; -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/PlaceScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/PlaceScriptParameter.cs index 1d313a53..b87a0242 100644 --- a/src/SerialLoops.Lib/Script/Parameters/PlaceScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/PlaceScriptParameter.cs @@ -6,10 +6,10 @@ namespace SerialLoops.Lib.Script.Parameters; public class PlaceScriptParameter(string name, PlaceItem place) : ScriptParameter(name, ParameterType.PLACE) { public PlaceItem Place { get; set; } = place; - public override short[] GetValues(object obj = null) => new short[] { (short)Place.Index }; + public override short[] GetValues(object? obj = null) => [(short)Place.Index]; public override PlaceScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Place); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ScreenScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ScreenScriptParameter.cs index f2038333..d566448b 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ScreenScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ScreenScriptParameter.cs @@ -2,15 +2,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ScreenScriptParameter : ScriptParameter +public class ScreenScriptParameter(string name, short screen) : ScriptParameter(name, ParameterType.SCREEN) { - public DsScreen Screen { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Screen }; - - public ScreenScriptParameter(string name, short screen) : base(name, ParameterType.SCREEN) - { - Screen = (DsScreen)screen; - } + public DsScreen Screen { get; set; } = (DsScreen)screen; + public override short[] GetValues(object? obj = null) => [(short)Screen]; public override ScreenScriptParameter Clone(Project project, EventFile eventFile) { @@ -23,4 +18,4 @@ public enum DsScreen : short TOP = 1, BOTH = 2, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ScriptParameter.cs index 90567acf..259d7677 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ScriptParameter.cs @@ -2,17 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public abstract class ScriptParameter +public abstract class ScriptParameter(string name, ScriptParameter.ParameterType type) { - public ParameterType Type { get; protected set; } - public string Name { get; protected set; } - public abstract short[] GetValues(object obj = null); - - protected ScriptParameter(string name, ParameterType type) - { - Name = name; - Type = type; - } + public ParameterType Type { get; protected set; } = type; + public string Name { get; protected set; } = name; + public abstract short[] GetValues(object? obj = null); public abstract ScriptParameter Clone(Project project, EventFile eventFile); @@ -59,4 +53,4 @@ public enum ParameterType VOICE_LINE, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ScriptSectionScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ScriptSectionScriptParameter.cs index 9049c5b8..e3e5e7cb 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ScriptSectionScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ScriptSectionScriptParameter.cs @@ -3,18 +3,16 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ScriptSectionScriptParameter : ScriptParameter +public class ScriptSectionScriptParameter(string name, ScriptSection? section) + : ScriptParameter(name, ParameterType.SCRIPT_SECTION) { - public ScriptSection Section { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)(Section is not null ? ((EventFile)obj).LabelsSection.Objects.First(l => l.Name.Replace("/", "") == Section.Name).Id : 0) }; + public ScriptSection? Section { get; set; } = section; - public ScriptSectionScriptParameter(string name, ScriptSection section) : base(name, ParameterType.SCRIPT_SECTION) - { - Section = section; - } + public override short[] GetValues(object? obj = null) => [(short)(Section is not null ? ((EventFile)obj!).LabelsSection.Objects.First(l => l.Name.Replace("/", "") == Section.Name).Id : 0) + ]; public override ScriptSectionScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Section); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/SfxModeScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SfxModeScriptParameter.cs index 9420308b..a6ce9601 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SfxModeScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SfxModeScriptParameter.cs @@ -2,15 +2,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SfxModeScriptParameter : ScriptParameter +public class SfxModeScriptParameter(string name, short mode) : ScriptParameter(name, ParameterType.SFX_MODE) { - public SfxMode Mode { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Mode }; - - public SfxModeScriptParameter(string name, short mode) : base(name, ParameterType.SFX_MODE) - { - Mode = (SfxMode)mode; - } + public SfxMode Mode { get; set; } = (SfxMode)mode; + public override short[] GetValues(object? obj = null) => [(short)Mode]; public override SfxModeScriptParameter Clone(Project project, EventFile eventFile) { @@ -22,4 +17,4 @@ public enum SfxMode : short START = 6, STOP = 7, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/SfxScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SfxScriptParameter.cs index 35803372..68888896 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SfxScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SfxScriptParameter.cs @@ -3,18 +3,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SfxScriptParameter : ScriptParameter +public class SfxScriptParameter(string name, SfxItem sfx) : ScriptParameter(name, ParameterType.SFX) { - public SfxItem Sfx { get; set; } - public override short[] GetValues(object obj = null) => new short[] { Sfx.Index }; - - public SfxScriptParameter(string name, SfxItem sfx) : base(name, ParameterType.SFX) - { - Sfx = sfx; - } + public SfxItem Sfx { get; set; } = sfx; + public override short[] GetValues(object? obj = null) => [Sfx.Index]; public override SfxScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Sfx); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/ShortScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/ShortScriptParameter.cs index a5a4de80..e0f3c9fd 100644 --- a/src/SerialLoops.Lib/Script/Parameters/ShortScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/ShortScriptParameter.cs @@ -2,18 +2,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class ShortScriptParameter : ScriptParameter +public class ShortScriptParameter(string name, short value) : ScriptParameter(name, ParameterType.SHORT) { - public short Value { get; set; } - public override short[] GetValues(object obj = null) => new short[] { Value }; - - public ShortScriptParameter(string name, short value) : base(name, ParameterType.SHORT) - { - Value = value; - } + public short Value { get; set; } = value; + public override short[] GetValues(object? obj = null) => [Value]; public override ShortScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Value); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/SpriteEntranceScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SpriteEntranceScriptParameter.cs index 7fcd6735..1aa073ab 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SpriteEntranceScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SpriteEntranceScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SpriteEntranceScriptParameter : ScriptParameter +public class SpriteEntranceScriptParameter(string name, short entranceTransition) + : ScriptParameter(name, ParameterType.SPRITE_ENTRANCE) { - public SpriteEntranceTransition EntranceTransition { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)EntranceTransition }; - - public SpriteEntranceScriptParameter(string name, short entranceTransition) : base(name, ParameterType.SPRITE_ENTRANCE) - { - EntranceTransition = (SpriteEntranceTransition)entranceTransition; - } + public SpriteEntranceTransition EntranceTransition { get; set; } = (SpriteEntranceTransition)entranceTransition; + public override short[] GetValues(object? obj = null) => [(short)EntranceTransition]; public override SpriteEntranceScriptParameter Clone(Project project, EventFile eventFile) { @@ -32,4 +28,4 @@ public enum SpriteEntranceTransition : short PEEK_RIGHT_TO_LEFT = 10, FADE_IN_LEFT = 11, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/SpriteExitScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SpriteExitScriptParameter.cs index 729f3b0b..1ee0ab68 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SpriteExitScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SpriteExitScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SpriteExitScriptParameter : ScriptParameter +public class SpriteExitScriptParameter(string name, short exitTransition) + : ScriptParameter(name, ParameterType.SPRITE_EXIT) { - public SpriteExitTransition ExitTransition { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)ExitTransition }; - - public SpriteExitScriptParameter(string name, short exitTransition) : base(name, ParameterType.SPRITE_EXIT) - { - ExitTransition = (SpriteExitTransition)exitTransition; - } + public SpriteExitTransition ExitTransition { get; set; } = (SpriteExitTransition)exitTransition; + public override short[] GetValues(object? obj = null) => [(short)ExitTransition]; public override SpriteExitScriptParameter Clone(Project project, EventFile eventFile) { @@ -31,4 +27,4 @@ public enum SpriteExitTransition : short SLIDE_LEFT_TO_RIGHT_AND_STAY = 9, SLIDE_RIGHT_TO_LEFT_AND_STAY = 10, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs index 6523327c..3c017500 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs @@ -3,18 +3,14 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SpriteScriptParameter : ScriptParameter +public class SpriteScriptParameter(string name, CharacterSpriteItem sprite) + : ScriptParameter(name, ParameterType.SPRITE) { - public CharacterSpriteItem Sprite { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)(Sprite?.Index ?? 0) }; - - public SpriteScriptParameter(string name, CharacterSpriteItem sprite) : base(name, ParameterType.SPRITE) - { - Sprite = sprite; - } + public CharacterSpriteItem Sprite { get; set; } = sprite; + public override short[] GetValues(object? obj = null) => [(short)(Sprite?.Index ?? 0)]; public override SpriteScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, Sprite); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/SpriteShakeScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SpriteShakeScriptParameter.cs index 34e1befc..7938ec6f 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SpriteShakeScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SpriteShakeScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SpriteShakeScriptParameter : ScriptParameter +public class SpriteShakeScriptParameter(string name, short shakeEffect) + : ScriptParameter(name, ParameterType.SPRITE_SHAKE) { - public SpriteShakeEffect ShakeEffect { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)ShakeEffect }; - - public SpriteShakeScriptParameter(string name, short shakeEffect) : base(name, ParameterType.SPRITE_SHAKE) - { - ShakeEffect = (SpriteShakeEffect)shakeEffect; - } + public SpriteShakeEffect ShakeEffect { get; set; } = (SpriteShakeEffect)shakeEffect; + public override short[] GetValues(object? obj = null) => [(short)ShakeEffect]; public override SpriteShakeScriptParameter Clone(Project project, EventFile eventFile) { @@ -26,4 +22,4 @@ public enum SpriteShakeEffect : short SHAKE_RIGHT = 4, SHAKE_LEFT = 5, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/TextEntranceEffectScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/TextEntranceEffectScriptParameter.cs index a03f2c6e..fdf06914 100644 --- a/src/SerialLoops.Lib/Script/Parameters/TextEntranceEffectScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/TextEntranceEffectScriptParameter.cs @@ -2,15 +2,11 @@ namespace SerialLoops.Lib.Script.Parameters; -public class TextEntranceEffectScriptParameter : ScriptParameter +public class TextEntranceEffectScriptParameter(string name, short entranceEffect) + : ScriptParameter(name, ParameterType.TEXT_ENTRANCE_EFFECT) { - public TextEntranceEffect EntranceEffect { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)EntranceEffect }; - - public TextEntranceEffectScriptParameter(string name, short entranceEffect) : base(name, ParameterType.TEXT_ENTRANCE_EFFECT) - { - EntranceEffect = (TextEntranceEffect)entranceEffect; - } + public TextEntranceEffect EntranceEffect { get; set; } = (TextEntranceEffect)entranceEffect; + public override short[] GetValues(object? obj = null) => [(short)EntranceEffect]; public override TextEntranceEffectScriptParameter Clone(Project project, EventFile eventFile) { @@ -23,4 +19,4 @@ public enum TextEntranceEffect : short SHRINK_IN = 1, TERMINAL_TYPING = 2, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/TopicScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/TopicScriptParameter.cs index eac44ac3..13ccf3cf 100644 --- a/src/SerialLoops.Lib/Script/Parameters/TopicScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/TopicScriptParameter.cs @@ -2,18 +2,13 @@ namespace SerialLoops.Lib.Script.Parameters; -public class TopicScriptParameter : ScriptParameter +public class TopicScriptParameter(string name, short topic) : ScriptParameter(name, ParameterType.TOPIC) { - public short TopicId { get; set; } - public override short[] GetValues(object obj = null) => new short[] { TopicId }; - - public TopicScriptParameter(string name, short topic) : base(name, ParameterType.TOPIC) - { - TopicId = topic; - } + public short TopicId { get; set; } = topic; + public override short[] GetValues(object? obj = null) => [TopicId]; public override TopicScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, TopicId); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/TransitionScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/TransitionScriptParameter.cs index 34c6b25a..c84ffe16 100644 --- a/src/SerialLoops.Lib/Script/Parameters/TransitionScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/TransitionScriptParameter.cs @@ -2,15 +2,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class TransitionScriptParameter : ScriptParameter +public class TransitionScriptParameter(string name, short transition) : ScriptParameter(name, ParameterType.TRANSITION) { - public TransitionEffect Transition { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)Transition }; - - public TransitionScriptParameter(string name, short transition) : base(name, ParameterType.TRANSITION) - { - Transition = (TransitionEffect)transition; - } + public TransitionEffect Transition { get; set; } = (TransitionEffect)transition; + public override short[] GetValues(object? obj = null) => [(short)Transition]; public override TransitionScriptParameter Clone(Project project, EventFile eventFile) { @@ -28,4 +23,4 @@ public enum TransitionEffect WIPE_UP = 6, WIPE_DIAGONAL_LEFT_UP = 7, } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/Parameters/VoicedLineScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/VoicedLineScriptParameter.cs index 239f85a0..d90d8f01 100644 --- a/src/SerialLoops.Lib/Script/Parameters/VoicedLineScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/VoicedLineScriptParameter.cs @@ -3,18 +3,14 @@ namespace SerialLoops.Lib.Script.Parameters; -public class VoicedLineScriptParameter : ScriptParameter +public class VoicedLineScriptParameter(string name, VoicedLineItem vce) + : ScriptParameter(name, ParameterType.VOICE_LINE) { - public VoicedLineItem VoiceLine { get; set; } - public override short[] GetValues(object obj = null) => new short[] { (short)(VoiceLine?.Index ?? 0) }; - - public VoicedLineScriptParameter(string name, VoicedLineItem vce) : base(name, ParameterType.VOICE_LINE) - { - VoiceLine = vce; - } + public VoicedLineItem VoiceLine { get; set; } = vce; + public override short[] GetValues(object? obj = null) => [(short)(VoiceLine?.Index ?? 0)]; public override VoicedLineScriptParameter Clone(Project project, EventFile eventFile) { return new(Name, VoiceLine); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/ScriptItemCommand.cs b/src/SerialLoops.Lib/Script/ScriptItemCommand.cs index d2da1837..5c0d793f 100644 --- a/src/SerialLoops.Lib/Script/ScriptItemCommand.cs +++ b/src/SerialLoops.Lib/Script/ScriptItemCommand.cs @@ -17,13 +17,16 @@ namespace SerialLoops.Lib.Script; public class ScriptItemCommand : ReactiveObject { - public ScriptCommandInvocation Invocation { get; set; } + public ScriptCommandInvocation? Invocation { get; set; } public CommandVerb Verb { get; set; } - public List Parameters { get; set; } - public ScriptSection Section { get; set; } - public EventFile Script { get; set; } + public List Parameters { get; set; } = []; + public ScriptSection? Section { get; set; } + public EventFile? Script { get; set; } public int Index { get; set; } - public Project Project { get; set; } + public Project? Project { get; set; } + + [Reactive] + public string? Display { get; set; } public static ScriptItemCommand FromInvocation(ScriptCommandInvocation invocation, ScriptSection section, int index, EventFile eventFile, Project project, Func localize, ILogger log) { @@ -44,7 +47,7 @@ public static ScriptItemCommand FromInvocation(ScriptCommandInvocation invocatio public ScriptItemCommand() { } - public ScriptItemCommand(ScriptSection section, EventFile script, int index, Project project, CommandVerb verb, params ScriptParameter[] parameters) + public ScriptItemCommand(ScriptSection? section, EventFile? script, int index, Project project, CommandVerb verb, params ScriptParameter[] parameters) { Section = section; Script = script; @@ -73,14 +76,16 @@ public ScriptItemCommand(CommandVerb verb, params ScriptParameter[] parameters) UpdateDisplay(); } - public List WalkCommandGraph(Dictionary> commandTree, AdjacencyGraph graph) + public List? WalkCommandGraph(Dictionary> commandTree, AdjacencyGraph graph) { List commands = []; - Func weightFunction = new((ScriptSectionEdge edge) => + Func weightFunction = new((ScriptSectionEdge edge) => 1); + + if (Section is null) { - return 1; - }); + return null; + } if (Section != commandTree.Keys.First()) { @@ -97,7 +102,7 @@ public List WalkCommandGraph(Dictionary GetScriptParameters(ScriptCommandInvocation parameters.Add(new DialogueScriptParameter(localize("Dialogue"), GetDialogueLine(parameter, eventFile))); break; case 1: - parameters.Add(new SpriteScriptParameter(localize("Sprite"), (CharacterSpriteItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Character_Sprite && parameter == ((CharacterSpriteItem)i).Index))); + parameters.Add(new SpriteScriptParameter(localize("Sprite"), (CharacterSpriteItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Character_Sprite && parameter == ((CharacterSpriteItem)item).Index))); break; case 2: parameters.Add(new SpriteEntranceScriptParameter(localize("Sprite Entrance Transition"), parameter)); @@ -136,13 +141,13 @@ private static List GetScriptParameters(ScriptCommandInvocation parameters.Add(new SpriteShakeScriptParameter(localize("Sprite Shake"), parameter)); break; case 5: - parameters.Add(new VoicedLineScriptParameter(localize("Voice Line"), (VoicedLineItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Voice && parameter == ((VoicedLineItem)i).Index))); + parameters.Add(new VoicedLineScriptParameter(localize("Voice Line"), (VoicedLineItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Voice && parameter == ((VoicedLineItem)item).Index))); break; case 6: - parameters.Add(new DialoguePropertyScriptParameter(localize("Text Voice Font"), (CharacterItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Character && ((CharacterItem)i).MessageInfo.Character == project.MessInfo.MessageInfos[parameter].Character))); + parameters.Add(new DialoguePropertyScriptParameter(localize("Text Voice Font"), (CharacterItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Character && ((CharacterItem)item).MessageInfo.Character == project.MessInfo!.MessageInfos[parameter].Character))); break; case 7: - parameters.Add(new DialoguePropertyScriptParameter(localize("Text Speed"), (CharacterItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Character && ((CharacterItem)i).MessageInfo.Character == project.MessInfo.MessageInfos[parameter].Character))); + parameters.Add(new DialoguePropertyScriptParameter(localize("Text Speed"), (CharacterItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Character && ((CharacterItem)item).MessageInfo.Character == project.MessInfo!.MessageInfos[parameter].Character))); break; case 8: parameters.Add(new TextEntranceEffectScriptParameter(localize("Text Entrance Effect"), parameter)); @@ -162,7 +167,7 @@ private static List GetScriptParameters(ScriptCommandInvocation case CommandVerb.KBG_DISP: if (i == 0) { - parameters.Add(new BgScriptParameter(localize("\"Kinetic\" Background"), (BackgroundItem)project.Items.First(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Id == parameter), kinetic: true)); + parameters.Add(new BgScriptParameter(localize("\"Kinetic\" Background"), (BackgroundItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Background && ((BackgroundItem)item).Id == parameter), kinetic: true)); } break; case CommandVerb.PIN_MNL: @@ -175,8 +180,8 @@ private static List GetScriptParameters(ScriptCommandInvocation case CommandVerb.BG_DISP2: if (i == 0) { - ItemDescription bgItem = project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Id == parameter) - ?? project.Items.First(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).BackgroundType == HaruhiChokuretsuLib.Archive.Data.BgType.TEX_BG); + ItemDescription bgItem = project.Items.FirstOrDefault(item => item.Type == ItemDescription.ItemType.Background && ((BackgroundItem)item).Id == parameter) + ?? project.Items.First(item => item.Type == ItemDescription.ItemType.Background && ((BackgroundItem)item).BackgroundType == HaruhiChokuretsuLib.Archive.Data.BgType.TEX_BG); parameters.Add(new BgScriptParameter(localize("Background"), (BackgroundItem)bgItem, kinetic: false)); } break; @@ -473,10 +478,10 @@ private static List GetScriptParameters(ScriptCommandInvocation switch (i) { case 0: - parameters.Add(new BgScriptParameter(localize("Background"), (BackgroundItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Id == parameter), kinetic: false)); + parameters.Add(new BgScriptParameter(localize("Background"), (BackgroundItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Background && ((BackgroundItem)item).Id == parameter), kinetic: false)); break; case 1: - parameters.Add(new BgScriptParameter(localize("Background (CG)"), (BackgroundItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Id == parameter), kinetic: false)); + parameters.Add(new BgScriptParameter(localize("Background (CG)"), (BackgroundItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Background && ((BackgroundItem)item).Id == parameter), kinetic: false)); break; case 2: parameters.Add(new ShortScriptParameter(localize("Fade Time (Frames)"), parameter)); @@ -497,7 +502,7 @@ private static List GetScriptParameters(ScriptCommandInvocation parameters.Add(new BoolScriptParameter(localize("Display?"), parameter == 1)); break; case 1: - parameters.Add(new PlaceScriptParameter(localize("Place"), (PlaceItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Place && ((PlaceItem)i).Index == parameter))); + parameters.Add(new PlaceScriptParameter(localize("Place"), (PlaceItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Place && ((PlaceItem)item).Index == parameter))); break; } break; @@ -518,7 +523,7 @@ private static List GetScriptParameters(ScriptCommandInvocation case CommandVerb.LOAD_ISOMAP: if (i == 0) { - parameters.Add(new MapScriptParameter(localize("Map"), (MapItem)project.Items.First(i => i.Type == ItemDescription.ItemType.Map && (parameter) == ((MapItem)i).Map.Index))); + parameters.Add(new MapScriptParameter(localize("Map"), (MapItem)project.Items.First(item => item.Type == ItemDescription.ItemType.Map && (parameter) == ((MapItem)item).Map?.Index))); } break; case CommandVerb.INVEST_START: @@ -702,9 +707,6 @@ private static List GetScriptParameters(ScriptCommandInvocation return parameters; } - [Reactive] - public string Display { get; set; } - public void UpdateDisplay() { Display = ToString(); @@ -716,13 +718,13 @@ public override string ToString() switch (Verb) { case CommandVerb.DIALOGUE: - str += $" {((DialogueScriptParameter)Parameters[0]).Line.Text.GetSubstitutedString(Project)[0..Math.Min(((DialogueScriptParameter)Parameters[0]).Line.Text.Length, 10)]}..."; + str += $" {((DialogueScriptParameter)Parameters[0]).Line.Text.GetSubstitutedString(Project!)[0..Math.Min(((DialogueScriptParameter)Parameters[0]).Line.Text.Length, 10)]}..."; break; case CommandVerb.GOTO: - str += $" {((ScriptSectionScriptParameter)Parameters[0]).Section.Name}"; + str += $" {((ScriptSectionScriptParameter)Parameters[0]).Section?.Name}"; break; case CommandVerb.VGOTO: - str += $" {((ConditionalScriptParameter)Parameters[0]).Conditional}, {((ScriptSectionScriptParameter)Parameters[1]).Section.Name}"; + str += $" {((ConditionalScriptParameter)Parameters[0]).Conditional}, {((ScriptSectionScriptParameter)Parameters[1]).Section?.Name}"; break; case CommandVerb.WAIT: str += $" {((ShortScriptParameter)Parameters[0]).Value}"; @@ -742,7 +744,7 @@ public ScriptItemCommand Clone() { Invocation = Invocation, Verb = Verb, - Parameters = Parameters.Select(p => p.Clone(Project, Script)).ToList(), + Parameters = Parameters.Select(p => p.Clone(Project!, Script!)).ToList(), Section = Section, Index = Index, Script = Script, @@ -750,4 +752,4 @@ public ScriptItemCommand Clone() }; } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Script/ScriptPreview.cs b/src/SerialLoops.Lib/Script/ScriptPreview.cs index 38268e39..b0d27cd4 100644 --- a/src/SerialLoops.Lib/Script/ScriptPreview.cs +++ b/src/SerialLoops.Lib/Script/ScriptPreview.cs @@ -7,17 +7,17 @@ namespace SerialLoops.Lib.Script; public class ScriptPreview { public short EpisodeHeader { get; set; } - public BackgroundItem Kbg { get; set; } - public PlaceItem Place { get; set; } - public List<(ChibiItem Chibi, int X, int Y)> TopScreenChibis { get; set; } = []; - public (int InternalYOffset, int ExternalXOffset, ChibiItem EmotingChibi) ChibiEmote { get; set; } - public BackgroundItem Background { get; set; } + public BackgroundItem? Kbg { get; set; } + public PlaceItem? Place { get; set; } + public List<(ChibiItem? Chibi, int X, int Y)> TopScreenChibis { get; set; } = []; + public (int InternalYOffset, int ExternalXOffset, ChibiItem? EmotingChibi) ChibiEmote { get; set; } + public BackgroundItem? Background { get; set; } public PaletteEffectScriptParameter.PaletteEffect BgPalEffect { get; set; } - public ScriptItemCommand BgScrollCommand { get; set; } + public ScriptItemCommand? BgScrollCommand { get; set; } public bool BgPositionBool { get; set; } - public (ItemItem Item, ItemItem.ItemLocation Location) Item { get; set; } + public (ItemItem? Item, ItemItem.ItemLocation Location) Item { get; set; } public List Sprites { get; set; } = []; - public ScriptItemCommand LastDialogueCommand { get; set; } - public TopicItem Topic { get; set; } - public string ErrorImage { get; set; } -} \ No newline at end of file + public ScriptItemCommand? LastDialogueCommand { get; set; } + public TopicItem? Topic { get; set; } + public string? ErrorImage { get; set; } +} diff --git a/src/SerialLoops.Lib/Script/ScriptSectionEdge.cs b/src/SerialLoops.Lib/Script/ScriptSectionEdge.cs index 87df5073..d5b38d92 100644 --- a/src/SerialLoops.Lib/Script/ScriptSectionEdge.cs +++ b/src/SerialLoops.Lib/Script/ScriptSectionEdge.cs @@ -8,4 +8,10 @@ public class ScriptSectionEdge : IEdge public ScriptSection Source { get; set; } public ScriptSection Target { get; set; } -} \ No newline at end of file + + public ScriptSectionEdge() + { + Source = new(); + Target = new(); + } +} diff --git a/src/SerialLoops.Lib/Script/ScriptTemplate.cs b/src/SerialLoops.Lib/Script/ScriptTemplate.cs index 644983b7..69b97fcb 100644 --- a/src/SerialLoops.Lib/Script/ScriptTemplate.cs +++ b/src/SerialLoops.Lib/Script/ScriptTemplate.cs @@ -12,9 +12,9 @@ namespace SerialLoops.Lib.Script; public class ScriptTemplate { - public string Name { get; set; } - public string Description { get; set; } - public TemplateSection[] Sections { get; set; } + public string? Name { get; set; } + public string? Description { get; set; } + public TemplateSection[]? Sections { get; set; } public ScriptTemplate() { @@ -34,9 +34,9 @@ public ScriptTemplate(string templateName, string templateDescription, Dictionar public void Apply(ScriptItem script, Project project, ILogger log) { - foreach (TemplateSection section in Sections) + foreach (TemplateSection section in Sections!) { - int sectionIndex = script.Event.ScriptSections.FindIndex(s => s.Name == section.Name); + int sectionIndex = script.Event!.ScriptSections.FindIndex(s => s.Name == section.Name); if (sectionIndex < 0) { sectionIndex = script.Event.ScriptSections.Count; @@ -47,11 +47,11 @@ public void Apply(ScriptItem script, Project project, ILogger log) // We add the sections first and then do it a second time in order to allow ScriptSectionParameters to be able to find their sections foreach (TemplateSection section in Sections) { - int sectionIndex = script.Event.ScriptSections.FindIndex(s => s.Name == section.Name); - for (int i = 0; i < section.Commands.Length; i++) + int sectionIndex = script.Event!.ScriptSections.FindIndex(s => s.Name == section.Name); + for (int i = 0; i < section.Commands?.Length; i++) { script.Event.ScriptSections[sectionIndex].Objects.Insert(i, - new ScriptItemCommand(script.Event.ScriptSections[sectionIndex], script.Event, i, project, section.Commands[i].Verb, [.. section.Commands[i].Parameters.Select(p => p.ParseAndApply(project, script.Event, log))]).Invocation); + new ScriptItemCommand(script.Event.ScriptSections[sectionIndex], script.Event, i, project, section.Commands[i].Verb, [.. section.Commands[i].Parameters.Select(p => p.ParseAndApply(project, script.Event, log))!]).Invocation); } } } @@ -59,8 +59,8 @@ public void Apply(ScriptItem script, Project project, ILogger log) public class TemplateSection { - public string Name { get; set; } - public TemplateScriptCommand[] Commands { get; set; } + public string? Name { get; set; } + public TemplateScriptCommand[]? Commands { get; set; } public TemplateSection() { @@ -83,7 +83,8 @@ public class TemplateScriptCommand { [JsonConverter(typeof(JsonStringEnumConverter))] public EventFile.CommandVerb Verb { get; set; } - public TemplateScriptParameter[] Parameters { get; set; } + + public TemplateScriptParameter[] Parameters { get; set; } = []; public TemplateScriptCommand() { @@ -98,7 +99,7 @@ public TemplateScriptCommand(EventFile.CommandVerb commandVerb, params TemplateS public TemplateScriptCommand(ScriptItemCommand command, Project project) { Verb = command.Verb; - Parameters = [.. command.Parameters.Select(p => new TemplateScriptParameter(p, project))]; + Parameters = [.. command.Parameters!.Select(p => new TemplateScriptParameter(p, project))]; } } @@ -107,18 +108,7 @@ public class TemplateScriptParameter [JsonConverter(typeof(JsonStringEnumConverter))] public ScriptParameter.ParameterType ParameterType { get; set; } public string ParameterName { get; set; } - public string Value { get; set; } - - public TemplateScriptParameter() - { - } - - public TemplateScriptParameter(ScriptParameter.ParameterType type, string name, string value) - { - ParameterType = type; - ParameterName = name; - Value = value; - } + public string? Value { get; set; } public TemplateScriptParameter(ScriptParameter parameter, Project project) { @@ -190,7 +180,7 @@ private void EncodeValue(ScriptParameter parameter, Project project) break; case ScriptParameter.ParameterType.CHARACTER: - Value = $"{(short)((DialoguePropertyScriptParameter)parameter).Character.MessageInfo.Character}"; + Value = $"{(short)(((DialoguePropertyScriptParameter)parameter).Character?.MessageInfo.Character ?? 0)}"; break; case ScriptParameter.ParameterType.DIALOGUE: @@ -296,11 +286,15 @@ private void EncodeValue(ScriptParameter parameter, Project project) } } - public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log) + public ScriptParameter? ParseAndApply(Project project, EventFile evt, ILogger log) { try { - string value = Value; + string? value = Value; + if (string.IsNullOrEmpty(value)) + { + return null; + } string localizedName = project.Localize(ParameterName); switch (ParameterType) { @@ -308,10 +302,10 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return new BgmModeScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.BGM: - return new BgmScriptParameter(localizedName, (BackgroundMusicItem)project.Items.FirstOrDefault(i => i.Name == value)); + return new BgmScriptParameter(localizedName, (BackgroundMusicItem)project.Items.First(i => i.Name == value)); case ScriptParameter.ParameterType.BG: - return new BgScriptParameter(localizedName, (BackgroundItem)project.Items.FirstOrDefault(i => i.Name == value), value.Contains("KBG")); + return new BgScriptParameter(localizedName, (BackgroundItem)project.Items.First(i => i.Name == value), value.Contains("KBG")); case ScriptParameter.ParameterType.BG_SCROLL_DIRECTION: return new BgScrollDirectionScriptParameter(localizedName, short.Parse(value)); @@ -336,7 +330,7 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return new ChibiEnterExitScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.CHIBI: - return new ChibiScriptParameter(localizedName, (ChibiItem)project.Items.FirstOrDefault(i => i.Name == value)); + return new ChibiScriptParameter(localizedName, (ChibiItem)project.Items.First(i => i.Name == value)); case ScriptParameter.ParameterType.COLOR_MONOCHROME: return new ColorMonochromeScriptParameter(localizedName, short.Parse(value)); @@ -383,7 +377,7 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return new ItemTransitionScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.MAP: - return new MapScriptParameter(localizedName, (MapItem)project.Items.FirstOrDefault(i => i.Name == value)); + return new MapScriptParameter(localizedName, (MapItem)project.Items.First(i => i.Name == value)); case ScriptParameter.ParameterType.OPTION: if (evt.ChoicesSection.Objects.Any(c => c.Text == value)) @@ -401,19 +395,19 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return new PaletteEffectScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.PLACE: - return new PlaceScriptParameter(localizedName, (PlaceItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Place && ((PlaceItem)i).Index == short.Parse(value))); + return new PlaceScriptParameter(localizedName, (PlaceItem)project.Items.First(i => i.Type == ItemDescription.ItemType.Place && ((PlaceItem)i).Index == short.Parse(value))); case ScriptParameter.ParameterType.SCREEN: return new ScreenScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.SCRIPT_SECTION: - return new ScriptSectionScriptParameter(localizedName, evt.ScriptSections.FirstOrDefault(s => s.Name == value)); + return new ScriptSectionScriptParameter(localizedName, evt.ScriptSections.First(s => s.Name == value)); case ScriptParameter.ParameterType.SFX_MODE: return new SfxModeScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.SFX: - return new SfxScriptParameter(localizedName, (SfxItem)project.Items.FirstOrDefault(s => s.Name == value)); + return new SfxScriptParameter(localizedName, (SfxItem)project.Items.First(s => s.Name == value)); case ScriptParameter.ParameterType.SHORT: return new ShortScriptParameter(localizedName, short.Parse(value)); @@ -425,7 +419,7 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return new SpriteExitScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.SPRITE: - return new SpriteScriptParameter(localizedName, (CharacterSpriteItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Character_Sprite && ((CharacterSpriteItem)i).Index == short.Parse(value))); + return new SpriteScriptParameter(localizedName, (CharacterSpriteItem)project.Items.First(i => i.Type == ItemDescription.ItemType.Character_Sprite && ((CharacterSpriteItem)i).Index == short.Parse(value))); case ScriptParameter.ParameterType.SPRITE_SHAKE: return new SpriteShakeScriptParameter(localizedName, short.Parse(value)); @@ -440,7 +434,7 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return new TransitionScriptParameter(localizedName, short.Parse(value)); case ScriptParameter.ParameterType.VOICE_LINE: - return new VoicedLineScriptParameter(localizedName, (VoicedLineItem)project.Items.FirstOrDefault(i => i.Name == value)); + return new VoicedLineScriptParameter(localizedName, (VoicedLineItem)project.Items.First(i => i.Name == value)); default: return null; @@ -452,4 +446,4 @@ public ScriptParameter ParseAndApply(Project project, EventFile evt, ILogger log return null; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/SearchQuery.cs b/src/SerialLoops.Lib/SearchQuery.cs index c7afbeac..fe2901c7 100644 --- a/src/SerialLoops.Lib/SearchQuery.cs +++ b/src/SerialLoops.Lib/SearchQuery.cs @@ -7,7 +7,7 @@ namespace SerialLoops.Lib; public class SearchQuery { - public string Term { get; set; } + public string? Term { get; set; } public HashSet Scopes { get; set; } = [DataHolder.Title]; public HashSet Types { get; set; } = [.. Enum.GetValues()]; public bool QuickSearch => !Scopes.Any(scope => (int)scope > 10); @@ -32,4 +32,4 @@ public static SearchQuery Create(string text) { return new() { Term = text }; } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/SerialLoops.Lib.csproj b/src/SerialLoops.Lib/SerialLoops.Lib.csproj index b4e850a0..af12d29d 100644 --- a/src/SerialLoops.Lib/SerialLoops.Lib.csproj +++ b/src/SerialLoops.Lib/SerialLoops.Lib.csproj @@ -3,7 +3,7 @@ net8.0 disable - disable + enable $(SLAssemblyVersion) $(SLVersion) diff --git a/src/SerialLoops.Lib/Util/Extensions.cs b/src/SerialLoops.Lib/Util/Extensions.cs index bc0c5e2e..9006c865 100644 --- a/src/SerialLoops.Lib/Util/Extensions.cs +++ b/src/SerialLoops.Lib/Util/Extensions.cs @@ -98,7 +98,7 @@ public static void CollectGarbage(this EventFile evt) { if (conditionalUsedIndices[j].Index >= i) { - conditionalUsedIndices[j].Command.Parameters[0]--; + conditionalUsedIndices[j].Command!.Parameters[0]--; conditionalUsedIndices[j].Index--; } } @@ -128,7 +128,7 @@ public static void CollectGarbage(this EventFile evt) { if (dialogueUsedIndices[j].Index >= i) { - dialogueUsedIndices[j].Command.Parameters[0]--; + dialogueUsedIndices[j].Command!.Parameters[0]--; dialogueUsedIndices[j].Index--; } } @@ -139,7 +139,7 @@ public static void CollectGarbage(this EventFile evt) private class UsedIndex { - public ScriptCommandInvocation Command { get; set; } + public ScriptCommandInvocation? Command { get; set; } public short Index { get; set; } } @@ -216,7 +216,7 @@ public static void DrawHaroohieText(this SKCanvas canvas, string text, SKPaint c if (text[i] != ' ') // if it's a space, we just skip drawing { int charIndex = project.FontMap.CharMap.IndexOf(text[i]); - if ((charIndex + 1) * 16 <= project.FontBitmap.Height) + if ((charIndex + 1) * 16 <= project.FontBitmap!.Height) { canvas.DrawBitmap(project.FontBitmap, new SKRect(0, charIndex * 16, 16, (charIndex + 1) * 16), new SKRect(currentX, currentY, currentX + 16, currentY + 16), color); @@ -284,9 +284,9 @@ public class SKColorJsonConverter : JsonConverter { public override SKColor Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - string html = reader.GetString(); + string? html = reader.GetString(); return new( - byte.Parse(html[2..4], NumberStyles.HexNumber), + byte.Parse(html![2..4], NumberStyles.HexNumber), byte.Parse(html[4..6], NumberStyles.HexNumber), byte.Parse(html[6..8], NumberStyles.HexNumber), byte.Parse(html[0..2], NumberStyles.HexNumber) @@ -294,4 +294,4 @@ public override SKColor Read(ref Utf8JsonReader reader, Type typeToConvert, Json } public override void Write(Utf8JsonWriter writer, SKColor value, JsonSerializerOptions options) => writer.WriteStringValue($"{value.Alpha:X2}{value.Red:X2}{value.Green:X2}{value.Blue:X2}"); -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Util/GraphicInfo.cs b/src/SerialLoops.Lib/Util/GraphicInfo.cs index 5286e803..fe750cd3 100644 --- a/src/SerialLoops.Lib/Util/GraphicInfo.cs +++ b/src/SerialLoops.Lib/Util/GraphicInfo.cs @@ -8,15 +8,15 @@ namespace SerialLoops.Lib.Util; public class GraphicInfo { - public string Determinant { get; set; } + public string? Determinant { get; set; } public GraphicsFile.TileForm TileForm { get; set; } public short Unknown08 { get; set; } public short RenderWidth { get; set; } public short RenderHeight { get; set; } - public string PaletteString { get; set; } + public string? PaletteString { get; set; } [JsonIgnore] - public List Palette => PaletteString.Split(',').Select(SKColor.Parse).ToList(); + public List? Palette => PaletteString?.Split(',').Select(SKColor.Parse).ToList(); public GraphicInfo() { @@ -46,4 +46,4 @@ public void SetWithoutPalette(GraphicsFile file) file.RenderWidth = RenderWidth; file.RenderHeight = RenderHeight; } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Util/WaveformRenderer/MaxPeakProvider.cs b/src/SerialLoops.Lib/Util/WaveformRenderer/MaxPeakProvider.cs index 5a67b339..ad853ff7 100644 --- a/src/SerialLoops.Lib/Util/WaveformRenderer/MaxPeakProvider.cs +++ b/src/SerialLoops.Lib/Util/WaveformRenderer/MaxPeakProvider.cs @@ -16,9 +16,13 @@ public class MaxPeakProvider : PeakProvider { public override PeakInfo GetNextPeak() { + if (Provider is null || ReadBuffer is null) + { + return new(0, 0); + } var samplesRead = Provider.Read(ReadBuffer, 0, ReadBuffer.Length - (ReadBuffer.Length % Provider.WaveFormat.BlockAlign)); var max = (samplesRead == 0) ? 0 : ReadBuffer.Take(samplesRead).Max(); var min = (samplesRead == 0) ? 0 : ReadBuffer.Take(samplesRead).Min(); return new PeakInfo(min, max); } -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Util/WaveformRenderer/PeakProvider.cs b/src/SerialLoops.Lib/Util/WaveformRenderer/PeakProvider.cs index 5216ed8f..7f412c2a 100644 --- a/src/SerialLoops.Lib/Util/WaveformRenderer/PeakProvider.cs +++ b/src/SerialLoops.Lib/Util/WaveformRenderer/PeakProvider.cs @@ -14,9 +14,9 @@ namespace SerialLoops.Lib.Util.WaveformRenderer; public abstract class PeakProvider { - protected ISampleProvider Provider { get; private set; } + protected ISampleProvider? Provider { get; private set; } protected int SamplesPerPeak { get; private set; } - protected float[] ReadBuffer { get; private set; } + protected float[]? ReadBuffer { get; private set; } public void Init(ISampleProvider provider, int samplesPerPeak) { @@ -32,4 +32,4 @@ public class PeakInfo(float min, float max) { public float Min { get; private set; } = min; public float Max { get; private set; } = max; -} \ No newline at end of file +} diff --git a/src/SerialLoops.Lib/Util/WaveformRenderer/WaveFormRendererSettings.cs b/src/SerialLoops.Lib/Util/WaveformRenderer/WaveFormRendererSettings.cs index d40eb54e..08d79a85 100644 --- a/src/SerialLoops.Lib/Util/WaveformRenderer/WaveFormRendererSettings.cs +++ b/src/SerialLoops.Lib/Util/WaveformRenderer/WaveFormRendererSettings.cs @@ -24,13 +24,8 @@ public class WaveFormRendererSettings BottomPeakPaint = new() { Color = new SKColor(179, 0, 64) }, }; - public WaveFormRendererSettings() - { - BackgroundColor = SKColors.Transparent; - } - // for display purposes only - public string Name { get; set; } + public string? Name { get; set; } public int Width { get; set; } @@ -38,10 +33,10 @@ public WaveFormRendererSettings() public int BottomHeight { get; set; } public int PixelsPerPeak { get; set; } public int SpacerPixels { get; set; } - public virtual SKPaint TopPeakPaint { get; set; } - public virtual SKPaint TopSpacerPaint { get; set; } - public virtual SKPaint BottomPeakPaint { get; set; } - public virtual SKPaint BottomSpacerPaint { get; set; } + public virtual SKPaint? TopPeakPaint { get; set; } + public virtual SKPaint? TopSpacerPaint { get; set; } + public virtual SKPaint? BottomPeakPaint { get; set; } + public virtual SKPaint? BottomSpacerPaint { get; set; } public bool DecibelScale { get; set; } - public SKColor BackgroundColor { get; set; } -} \ No newline at end of file + public SKColor BackgroundColor { get; set; } = SKColors.Transparent; +} diff --git a/src/SerialLoops/Assets/Strings.Designer.cs b/src/SerialLoops/Assets/Strings.Designer.cs index 215ba71b..b6629a6f 100644 --- a/src/SerialLoops/Assets/Strings.Designer.cs +++ b/src/SerialLoops/Assets/Strings.Designer.cs @@ -2931,6 +2931,15 @@ public static string Failed_to_load_voice_file__file_not_found_ { } } + /// + /// Looks up a localized string similar to Failed to parse config.json; null value returned!. + /// + public static string Failed_to_parse_config_json__null_value_returned_ { + get { + return ResourceManager.GetString("Failed to parse config.json; null value returned!", resourceCulture); + } + } + /// /// Looks up a localized string similar to Failed to parse script parameter {0} of type {1} with parameter '{2}'!. /// diff --git a/src/SerialLoops/Assets/Strings.resx b/src/SerialLoops/Assets/Strings.resx index 86681524..1c979486 100644 --- a/src/SerialLoops/Assets/Strings.resx +++ b/src/SerialLoops/Assets/Strings.resx @@ -2641,4 +2641,7 @@ No project is currently open. Would you like to create a new project? Load SoundThe name of a parameter for the SND_PLAY command which indicates whether a sound should be loaded or not + + Failed to parse config.json; null value returned! + diff --git a/src/SerialLoops/SerialLoops.csproj b/src/SerialLoops/SerialLoops.csproj index 72b817ac..5ee01300 100644 --- a/src/SerialLoops/SerialLoops.csproj +++ b/src/SerialLoops/SerialLoops.csproj @@ -2,7 +2,7 @@ WinExe net8.0;net8.0-windows - disable + enable true app.manifest true diff --git a/src/SerialLoops/Utility/LoopyLogger.cs b/src/SerialLoops/Utility/LoopyLogger.cs index 8be1f3fb..34e438e0 100644 --- a/src/SerialLoops/Utility/LoopyLogger.cs +++ b/src/SerialLoops/Utility/LoopyLogger.cs @@ -14,7 +14,7 @@ namespace SerialLoops.Utility; public class LoopyLogger : ILogger { private readonly Window _owner; - private Config _config; + private Config? _config; private string _logFile; public LoopyLogger(Window window) @@ -22,7 +22,7 @@ public LoopyLogger(Window window) _owner = window; } - public void Initialize(Config config) + public void Initialize(Config? config) { _config = config; if (!Directory.Exists(_config.LogsDirectory)) diff --git a/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs index 58a6866c..0899c103 100644 --- a/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs @@ -32,7 +32,7 @@ public class AsmHacksDialogViewModel : ViewModelBase private ILogger _log; private Project _project; - public Config Configuration { get; set; } + public Config? Configuration { get; set; } private Dictionary _hackParameters { get; set; } = []; [Reactive] public AsmHack SelectedHack { get; set; } @@ -41,7 +41,7 @@ public class AsmHacksDialogViewModel : ViewModelBase public ICommand SaveCommand { get; set; } public ICommand CancelCommand { get; set; } - public AsmHacksDialogViewModel(Project project, Config config, ILogger log) + public AsmHacksDialogViewModel(Project project, Config? config, ILogger log) { _log = log; _project = project; diff --git a/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs index 8d8905ee..6e7b4c9d 100644 --- a/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs @@ -26,7 +26,7 @@ public class PreferencesDialogViewModel : ViewModelBase public ICommand CancelCommand { get; private set; } private IConfigFactory _configFactory; - public Config Configuration { get; set; } + public Config? Configuration { get; set; } public ILogger Log { get; set; } [Reactive] public bool RequireRestart { get; set; } diff --git a/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs index 8da85cee..a3d93e86 100644 --- a/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs @@ -19,11 +19,11 @@ public partial class ProjectCreationDialogViewModel : ViewModelBase { private ILogger _log; private MainWindowViewModel _mainWindow; - private Config _config; + private Config? _config; - public string ProjectName { get; set; } + public string? ProjectName { get; set; } public ComboBoxItem LanguageTemplateItem { get; set; } - public string LanguageTemplateCode => (string)LanguageTemplateItem?.Tag ?? ""; + public string? LanguageTemplateCode => (string)LanguageTemplateItem?.Tag ?? ""; [Reactive] public string RomPath { get; set; } = Strings.None_Selected; @@ -31,7 +31,7 @@ public partial class ProjectCreationDialogViewModel : ViewModelBase public ICommand CreateCommand { get; set; } public ICommand CancelCommand { get; set; } - public ProjectCreationDialogViewModel(Config config, MainWindowViewModel mainWindow, ILogger log) + public ProjectCreationDialogViewModel(Config? config, MainWindowViewModel mainWindow, ILogger log) { _log = log; _mainWindow = mainWindow; @@ -62,7 +62,7 @@ private async Task CreateProject(ProjectCreationDialog dialog) } else { - Project newProject = new(ProjectName, LanguageTemplateCode, _config, Strings.ResourceManager.GetString, _log); + Project newProject = new(ProjectName, LanguageTemplateCode, _config, Strings.ResourceManager.GetString!, _log); LoopyProgressTracker tracker = new(); await new ProgressDialog(() => { @@ -73,4 +73,4 @@ private async Task CreateProject(ProjectCreationDialog dialog) }, () => dialog.Close(newProject), tracker, Strings.Creating_Project).ShowDialog(_mainWindow.Window); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs index 2ddeaf88..32c03c89 100644 --- a/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs @@ -37,12 +37,12 @@ public SKBitmap Icon set => this.RaiseAndSetIfChanged(ref _icon, value); } - private ProjectSettings _settings; + private ProjectSettings? _settings; public ILogger Log { get; set; } public bool Applied { get; set; } private ProjectSettingsDialog _settingsDialog; - public void Initialize(ProjectSettingsDialog settingsDialog, ProjectSettings settings, ILogger log) + public void Initialize(ProjectSettingsDialog settingsDialog, ProjectSettings? settings, ILogger log) { _settingsDialog = settingsDialog; _settings = settings; diff --git a/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs index d2157e33..74c0051d 100644 --- a/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs @@ -28,7 +28,7 @@ public class UpdateAvailableDialogViewModel : ViewModelBase private JsonArray _assets; private MainWindowViewModel _mainWindowViewModel; private UpdateAvailableDialog _updateDialog; - public Config Config => _mainWindowViewModel.CurrentConfig; + public Config? Config => _mainWindowViewModel.CurrentConfig; public ILogger Log => _mainWindowViewModel.Log; public void Initialize(MainWindowViewModel mainWindowViewModel, UpdateAvailableDialog updateDialog, string version, JsonArray assets, string url, string changelog) diff --git a/src/SerialLoops/ViewModels/MainWindowViewModel.cs b/src/SerialLoops/ViewModels/MainWindowViewModel.cs index d866647f..4caf3bc4 100644 --- a/src/SerialLoops/ViewModels/MainWindowViewModel.cs +++ b/src/SerialLoops/ViewModels/MainWindowViewModel.cs @@ -48,7 +48,7 @@ public partial class MainWindowViewModel : ViewModelBase public MainWindow Window { get; set; } public ProjectsCache ProjectsCache { get; set; } - public Config CurrentConfig { get; set; } + public Config? CurrentConfig { get; set; } public Project OpenProject { get; set; } public OpenProjectPanel ProjectPanel { get; set; } public Dictionary WindowMenu { get; set; } diff --git a/test/SerialLoops.Tests.Headless/ConfigFactoryMock.cs b/test/SerialLoops.Tests.Headless/ConfigFactoryMock.cs index 47c7431b..634b1474 100644 --- a/test/SerialLoops.Tests.Headless/ConfigFactoryMock.cs +++ b/test/SerialLoops.Tests.Headless/ConfigFactoryMock.cs @@ -11,18 +11,18 @@ public class ConfigFactoryMock(string configPath) : IConfigFactory { private string _configPath = configPath; - public Config LoadConfig(Func localize, ILogger log) + public Config? LoadConfig(Func localize, ILogger log) { if (File.Exists(_configPath)) { - Config newConfig = JsonSerializer.Deserialize(File.ReadAllText(_configPath)); + Config? newConfig = JsonSerializer.Deserialize(File.ReadAllText(_configPath)); newConfig.ConfigPath = _configPath; newConfig.InitializeHacks(log); return newConfig; } else { - Config newConfig = ConfigFactory.GetDefault(log); + Config? newConfig = ConfigFactory.GetDefault(log); newConfig.ConfigPath = _configPath; newConfig.CurrentCultureName = "en-US"; // there's a chance that the locale will be something we don't recognize (like Invariant culture) so we force this for tests newConfig.InitializeHacks(log); diff --git a/test/SerialLoops.Tests.Headless/NoProjectRequiredTests.cs b/test/SerialLoops.Tests.Headless/NoProjectRequiredTests.cs index ca2e481d..988e3ebe 100644 --- a/test/SerialLoops.Tests.Headless/NoProjectRequiredTests.cs +++ b/test/SerialLoops.Tests.Headless/NoProjectRequiredTests.cs @@ -64,7 +64,7 @@ public void PreferencesDialogTest(string buttonName) TestConsoleLogger log = new(); string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"config-{buttonName}.json"); ConfigFactoryMock configFactory = new(configPath); - Config config = configFactory.LoadConfig(s => s, log); + Config? config = configFactory.LoadConfig(s => s, log); Strings.Culture = new(config.CurrentCultureName); PreferencesDialogViewModel viewModel = new(); @@ -315,7 +315,7 @@ public void PreferencesDialogTest(string buttonName) button.Focus(); dialog.KeyPressQwerty(PhysicalKey.Enter, RawInputModifiers.None); - Config secondConfig = configFactory.LoadConfig(s => s, log); + Config? secondConfig = configFactory.LoadConfig(s => s, log); if (buttonName.Equals("SaveButton")) { diff --git a/test/SerialLoops.Tests.Headless/ProjectRequiredTests.cs b/test/SerialLoops.Tests.Headless/ProjectRequiredTests.cs index 324e78e8..75b85098 100644 --- a/test/SerialLoops.Tests.Headless/ProjectRequiredTests.cs +++ b/test/SerialLoops.Tests.Headless/ProjectRequiredTests.cs @@ -142,7 +142,7 @@ public async Task ProjectCreationTest() public async Task BackgroundEditor_CanEditCgNames() { ConfigFactoryMock configFactory = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"config-{nameof(BackgroundEditor_CanEditCgNames)}.json")); - string projectName = $"Headless_{nameof(BackgroundEditor_CanEditCgNames)}"; + string? projectName = $"Headless_{nameof(BackgroundEditor_CanEditCgNames)}"; int currentFrame = 0; MainWindowViewModel mainWindowViewModel = new(); MainWindow mainWindow = new() @@ -259,8 +259,8 @@ public async Task AsmHacksDialog_ApplyTest(string buttonName) { ConfigFactoryMock configFactory = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"config-{nameof(AsmHacksDialog_ApplyTest)}_{buttonName}.json")); TestConsoleLogger log = new(); - string projectName = $"Headless_{nameof(AsmHacksDialog_ApplyTest)}_{buttonName}"; - Config config = configFactory.LoadConfig(s => s, log); + string? projectName = $"Headless_{nameof(AsmHacksDialog_ApplyTest)}_{buttonName}"; + Config? config = configFactory.LoadConfig(s => s, log); config.UseDocker = true; int currentFrame = 0; Project project = new(projectName, "en", config, (s) => s, log); @@ -328,7 +328,7 @@ public async Task AsmHacksDialog_ApplyTest(string buttonName) public async Task CharacterSpriteEditor_CanEdit() { ConfigFactoryMock configFactory = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"config-{nameof(CharacterSpriteEditor_CanEdit)}.json")); - string projectName = $"Headless_{nameof(CharacterSpriteEditor_CanEdit)}"; + string? projectName = $"Headless_{nameof(CharacterSpriteEditor_CanEdit)}"; int currentFrame = 0; MainWindowViewModel mainWindowViewModel = new(); MainWindow mainWindow = new() diff --git a/test/SerialLoops.Tests.Headless/SerialLoops.Tests.Headless.csproj b/test/SerialLoops.Tests.Headless/SerialLoops.Tests.Headless.csproj index b5babe7a..b2f4a2e8 100644 --- a/test/SerialLoops.Tests.Headless/SerialLoops.Tests.Headless.csproj +++ b/test/SerialLoops.Tests.Headless/SerialLoops.Tests.Headless.csproj @@ -3,7 +3,7 @@ net8.0;net8.0-windows disable - disable + enable false true From 6449f51e00d0148c4cc09a68fedc31fb0fb3bfbe Mon Sep 17 00:00:00 2001 From: jonko0493 Date: Mon, 11 Nov 2024 22:12:10 -0800 Subject: [PATCH 2/6] Nullable for SerialLoops and test project --- src/SerialLoops.Lib/Items/ScriptItem.cs | 8 +- src/SerialLoops.Lib/Project.cs | 2 +- .../Script/Parameters/BgScriptParameter.cs | 4 +- .../Parameters/SpriteScriptParameter.cs | 4 +- .../Script/SpritePositioning.cs | 8 +- src/SerialLoops/App.axaml.cs | 12 +- .../Controls/LabelWithIcon.axaml.cs | 6 +- src/SerialLoops/Controls/LinkButton.axaml.cs | 10 +- .../Controls/LoopyProgressTracker.cs | 5 +- .../Controls/OptionsGroup.axaml.cs | 47 ++++---- .../Controls/SKCropResizeCanvas.cs | 8 +- src/SerialLoops/Models/ITreeItem.cs | 6 +- .../Models/ItemDescriptionTreeItem.cs | 14 +-- src/SerialLoops/Models/SKAvaloniaImage.cs | 10 +- .../Models/ScriptCommandTreeItem.cs | 12 +- .../Models/ScriptSectionTreeItem.cs | 14 +-- src/SerialLoops/Models/SectionTreeItem.cs | 8 +- src/SerialLoops/SerialLoops.csproj | 2 +- src/SerialLoops/Utility/ALWavePlayer.cs | 3 +- src/SerialLoops/Utility/ControlGenerator.cs | 20 ++-- src/SerialLoops/Utility/GuiExtensions.cs | 16 +-- src/SerialLoops/Utility/LoopyLogger.cs | 16 +-- src/SerialLoops/Utility/SLConverters.cs | 70 ++++-------- src/SerialLoops/Utility/UpdateChecker.cs | 33 ++++-- .../Controls/AnimatedImageViewModel.cs | 17 +-- .../Controls/ScreenSelectorViewModel.cs | 4 +- .../Controls/SoundPlayerPanelViewModel.cs | 14 ++- .../Dialogs/AboutDialogViewModel.cs | 4 +- .../Dialogs/AsmHacksDialogViewModel.cs | 67 ++++++----- .../BgmLoopPropertiesDialogViewModel.cs | 4 +- .../BgmVolumePropertiesDialogViewModel.cs | 4 +- .../GraphicSelectionDialogViewModel.cs | 16 +-- .../Dialogs/PreferencesDialogViewModel.cs | 39 +++---- .../Dialogs/ProjectCreationDialogViewModel.cs | 6 +- .../Dialogs/ProjectSettingsDialogViewModel.cs | 19 ++-- .../Dialogs/UpdateAvailableDialogViewModel.cs | 3 +- .../Editors/BackgroundEditorViewModel.cs | 26 +++-- .../Editors/BackgroundMusicEditorViewModel.cs | 28 ++--- .../Editors/CharacterSpriteEditorViewModel.cs | 16 +-- .../ViewModels/Editors/EditorViewModel.cs | 14 +-- .../Editors/GroupSelectionEditorViewModel.cs | 32 +++--- ...LoadSceneScenarioCommandEditorViewModel.cs | 8 +- ...zzlePhaseScenarioCommandEditorViewModel.cs | 4 +- ...uteSelectScenarioCommandEditorViewModel.cs | 4 +- .../ScenarioCommandEditorViewModel.cs | 2 +- .../Editors/ScenarioEditorViewModel.cs | 36 +++--- .../BgDispScriptCommandEditorViewModel.cs | 39 ++++--- .../BgmPlayScriptCommandEditorViewModel.cs | 16 +-- .../DialogueScriptCommandEditorViewModel.cs | 54 ++++----- .../FlagScriptCommandEditorViewModel.cs | 4 +- .../KbgDispScriptCommandEditorViewModel.cs | 16 +-- .../PinMnlScriptCommandEditorViewModel.cs | 10 +- ...creenFadeInScriptCommandEditorViewModel.cs | 10 +- ...reenFadeOutScriptCommandEditorViewModel.cs | 12 +- ...ScreenFlashScriptCommandEditorViewModel.cs | 10 +- .../SndPlayScriptCommandEditorViewModel.cs | 16 +-- ...gleDialogueScriptCommandEditorViewModel.cs | 2 +- .../TopicGetScriptCommandEditorViewModel.cs | 14 +-- .../VcePlayScriptCommandEditorViewModel.cs | 6 +- .../WaitScriptCommandEditorViewModel.cs | 4 +- .../Editors/ScriptEditorViewModel.cs | 58 +++++++--- .../ViewModels/Editors/SfxEditorViewModel.cs | 6 +- .../Editors/SystemTextureEditorViewModel.cs | 10 +- .../Editors/TopicEditorViewModel.cs | 42 +++---- .../Editors/VoicedLineEditorViewModel.cs | 43 +++---- .../ViewModels/MainWindowViewModel.cs | 81 ++++++------- .../Panels/EditorTabsPanelViewModel.cs | 14 +-- .../ViewModels/Panels/HomePanelViewModel.cs | 11 +- .../Panels/ItemExplorerPanelViewModel.cs | 10 +- .../Dialogs/BgmLoopPropertiesDialog.axaml.cs | 12 +- .../Dialogs/ProjectCreationDialog.axaml.cs | 4 +- .../Dialogs/UpdateAvailableDialog.axaml.cs | 8 +- .../TopicGetScriptCommandEditorView.axaml | 2 +- src/SerialLoops/Views/MainWindow.axaml.cs | 16 +-- .../Views/Panels/EditorTabsPanel.axaml.cs | 4 +- .../Views/Panels/HomePanel.axaml.cs | 14 +-- .../ConfigFactoryMock.cs | 6 +- test/SerialLoops.Tests.Headless/Helpers.cs | 4 +- .../NoProjectRequiredTests.cs | 106 +++++++++--------- .../ProjectRequiredTests.cs | 47 ++++---- 80 files changed, 732 insertions(+), 684 deletions(-) diff --git a/src/SerialLoops.Lib/Items/ScriptItem.cs b/src/SerialLoops.Lib/Items/ScriptItem.cs index 516196cf..440046d9 100644 --- a/src/SerialLoops.Lib/Items/ScriptItem.cs +++ b/src/SerialLoops.Lib/Items/ScriptItem.cs @@ -413,7 +413,7 @@ public ScriptPreview GetScriptPreview(Dictionary> commandTree, ScriptItemCommand currentCommand, + Dictionary> commandTree, ScriptItemCommand? currentCommand, Project project, ILogger log) { return GeneratePreviewImage(GetScriptPreview(commandTree, currentCommand, project, log), project); diff --git a/src/SerialLoops.Lib/Project.cs b/src/SerialLoops.Lib/Project.cs index 5a2450f8..cd327988 100644 --- a/src/SerialLoops.Lib/Project.cs +++ b/src/SerialLoops.Lib/Project.cs @@ -969,7 +969,7 @@ public static void ClearOrCreateCaches(string cachesDirectory, ILogger log) Directory.CreateDirectory(vceCache); } - public ItemDescription? FindItem(string name) + public ItemDescription? FindItem(string? name) { if (string.IsNullOrEmpty(name)) { diff --git a/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs index 9c185533..8f39d008 100644 --- a/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/BgScriptParameter.cs @@ -3,10 +3,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class BgScriptParameter(string name, BackgroundItem background, bool kinetic) +public class BgScriptParameter(string name, BackgroundItem? background, bool kinetic) : ScriptParameter(name, ParameterType.BG) { - public BackgroundItem Background { get; set; } = background; + public BackgroundItem? Background { get; set; } = background; public bool Kinetic { get; set; } = kinetic; public override short[] GetValues(object? obj = null) => [(short)(Background?.Id ?? 0)]; diff --git a/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs b/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs index 3c017500..7c1f53da 100644 --- a/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs +++ b/src/SerialLoops.Lib/Script/Parameters/SpriteScriptParameter.cs @@ -3,10 +3,10 @@ namespace SerialLoops.Lib.Script.Parameters; -public class SpriteScriptParameter(string name, CharacterSpriteItem sprite) +public class SpriteScriptParameter(string name, CharacterSpriteItem? sprite) : ScriptParameter(name, ParameterType.SPRITE) { - public CharacterSpriteItem Sprite { get; set; } = sprite; + public CharacterSpriteItem? Sprite { get; set; } = sprite; public override short[] GetValues(object? obj = null) => [(short)(Sprite?.Index ?? 0)]; public override SpriteScriptParameter Clone(Project project, EventFile eventFile) diff --git a/src/SerialLoops.Lib/Script/SpritePositioning.cs b/src/SerialLoops.Lib/Script/SpritePositioning.cs index c8fce42f..90010810 100644 --- a/src/SerialLoops.Lib/Script/SpritePositioning.cs +++ b/src/SerialLoops.Lib/Script/SpritePositioning.cs @@ -8,9 +8,9 @@ public class SpritePositioning public int X { get; set; } public int Layer { get; set; } - public SKPoint GetSpritePosition(SKBitmap sprite) + public SKPoint GetSpritePosition(SKBitmap? sprite) { - return new SKPoint(X, 384 - sprite.Height); + return sprite is null ? new() : new(X, 384 - sprite.Height); } public enum SpritePosition @@ -23,7 +23,7 @@ public enum SpritePosition public struct PositionedSprite { - public CharacterSpriteItem Sprite { get; set; } + public CharacterSpriteItem? Sprite { get; set; } public SpritePositioning Positioning { get; set; } public SKPaint PalEffect { get; set; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/App.axaml.cs b/src/SerialLoops/App.axaml.cs index 83e95377..3b366667 100644 --- a/src/SerialLoops/App.axaml.cs +++ b/src/SerialLoops/App.axaml.cs @@ -11,7 +11,7 @@ namespace SerialLoops; public partial class App : Application { - private IClassicDesktopStyleApplicationLifetime _desktop; + private IClassicDesktopStyleApplicationLifetime? _desktop; public override void Initialize() { @@ -37,21 +37,21 @@ public override void OnFrameworkInitializationCompleted() private void About_Click(object? sender, EventArgs e) { - ((MainWindow)_desktop.MainWindow).ViewModel.AboutCommand.Execute(Unit.Default); + ((MainWindow)_desktop!.MainWindow!).ViewModel!.AboutCommand.Execute(Unit.Default); } private void Preferences_Click(object? sender, EventArgs e) { - ((MainWindow)_desktop.MainWindow).ViewModel.PreferencesCommand.Execute(Unit.Default); + ((MainWindow)_desktop!.MainWindow!).ViewModel!.PreferencesCommand.Execute(Unit.Default); } private void Updates_Click(object? sender, EventArgs e) { - ((MainWindow)_desktop.MainWindow).ViewModel.CheckForUpdatesCommand.Execute(Unit.Default); + ((MainWindow)_desktop!.MainWindow!).ViewModel!.CheckForUpdatesCommand.Execute(Unit.Default); } private void Logs_Click(object? sender, EventArgs e) { - ((MainWindow)_desktop.MainWindow).ViewModel.ViewLogsCommand.Execute(Unit.Default); + ((MainWindow)_desktop!.MainWindow!).ViewModel!.ViewLogsCommand.Execute(Unit.Default); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Controls/LabelWithIcon.axaml.cs b/src/SerialLoops/Controls/LabelWithIcon.axaml.cs index 79d6918a..7bb0faf2 100644 --- a/src/SerialLoops/Controls/LabelWithIcon.axaml.cs +++ b/src/SerialLoops/Controls/LabelWithIcon.axaml.cs @@ -4,13 +4,13 @@ namespace SerialLoops.Controls; public partial class LabelWithIcon : UserControl { - public string Icon + public string? Icon { get => IconPath.Path; set => IconPath.Path = $"avares://SerialLoops/Assets/Icons/{value}.svg"; } - public string Text + public string? Text { get => LabelText.Text; set => LabelText.Text = value; @@ -21,4 +21,4 @@ public LabelWithIcon() InitializeComponent(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Controls/LinkButton.axaml.cs b/src/SerialLoops/Controls/LinkButton.axaml.cs index c58957eb..81eb815d 100644 --- a/src/SerialLoops/Controls/LinkButton.axaml.cs +++ b/src/SerialLoops/Controls/LinkButton.axaml.cs @@ -6,7 +6,7 @@ namespace SerialLoops.Controls; public partial class LinkButton : UserControl { - public string Icon + public string? Icon { get => IconPath.Path; set @@ -15,13 +15,13 @@ public string Icon IconPath.IsVisible = !string.IsNullOrEmpty(value); } } - public string Text + public string? Text { get => LinkText.Text; set => LinkText.Text = value; } - public delegate void OnClickDelegate(object sender, EventArgs e); - public OnClickDelegate OnClick { get; set; } + public delegate void OnClickDelegate(object? sender, EventArgs e); + public OnClickDelegate? OnClick { get; set; } public LinkButton() { @@ -35,4 +35,4 @@ private void Action_Execute(object? sender, RoutedEventArgs e) OnClick?.Invoke(sender, e); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Controls/LoopyProgressTracker.cs b/src/SerialLoops/Controls/LoopyProgressTracker.cs index acc39f94..3ef52246 100644 --- a/src/SerialLoops/Controls/LoopyProgressTracker.cs +++ b/src/SerialLoops/Controls/LoopyProgressTracker.cs @@ -18,6 +18,7 @@ public LoopyProgressTracker(string processVerb = "") processVerb = Strings.Loading_; } + _processVerb = processVerb; _loadingProgress = new() { Width = 390 }; _loadingItem = new(); Orientation = Avalonia.Layout.Orientation.Vertical; @@ -50,7 +51,7 @@ public int Total } } - private string _currentlyLoading; + private string _currentlyLoading = string.Empty; public string CurrentlyLoading { get => _currentlyLoading; @@ -60,4 +61,4 @@ public string CurrentlyLoading Dispatcher.UIThread.Invoke(() => _loadingItem.Text = _currentlyLoading); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Controls/OptionsGroup.axaml.cs b/src/SerialLoops/Controls/OptionsGroup.axaml.cs index 92d0570c..facbbf1e 100644 --- a/src/SerialLoops/Controls/OptionsGroup.axaml.cs +++ b/src/SerialLoops/Controls/OptionsGroup.axaml.cs @@ -18,7 +18,7 @@ namespace SerialLoops.Controls; public partial class OptionsGroup : UserControl { - public string Text { get; set; } + public string Text { get; set; } = string.Empty; public OptionsGroup() { @@ -57,13 +57,13 @@ public override void Render(DrawingContext context) { base.Render(context); this.TryFindResource("GroupLineColor", ActualThemeVariant, out object? brush); - context.DrawRectangle(new Pen((ImmutableSolidColorBrush)brush), new Rect(RenderTransformOrigin.Point, new Point(RenderTransformOrigin.Point.X + Bounds.Size.Width - 2, RenderTransformOrigin.Point.Y + Bounds.Size.Height - 2)), 5); + context.DrawRectangle(new Pen((ImmutableSolidColorBrush)brush!), new Rect(RenderTransformOrigin.Point, new Point(RenderTransformOrigin.Point.X + Bounds.Size.Width - 2, RenderTransformOrigin.Point.Y + Bounds.Size.Height - 2)), 5); } } public abstract class Option { - public string OptionName { get; set; } + public string OptionName { get; set; } = string.Empty; public bool Enabled { get; set; } = true; @@ -97,13 +97,19 @@ public Grid GetOptionRow() } public class TextOption : Option { - public Action OnChange { get; set; } - protected TextBox _textBox; + public Action? OnChange { get; set; } + protected TextBox? _textBox; - public string Value + public string? Value { - get => _textBox.Text; - set => _textBox.Text = value; + get => _textBox?.Text; + set + { + if (_textBox is not null) + { + _textBox.Text = value; + } + } } public TextOption() @@ -122,25 +128,28 @@ protected override Control GetControl() VerticalAlignment = VerticalAlignment.Center, IsEnabled = Enabled, }; - panel.Children.Add(_textBox); + if (_textBox is not null) + { + panel.Children.Add(_textBox); + } return panel; } } public class ComboBoxOption : Option { - public Action OnChange { get; set; } + public Action? OnChange { get; set; } protected ComboBox _comboBox { get; set; } public string Value { - get => (string)((ComboBoxItem)_comboBox.Items[_comboBox.SelectedIndex]).Tag; - set => _comboBox.SelectedIndex = _comboBox.Items.ToList().FindIndex(i => value.Equals((string)((ComboBoxItem)i).Tag)); + get => (string)((ComboBoxItem)_comboBox.Items[_comboBox.SelectedIndex]!).Tag!; + set => _comboBox.SelectedIndex = _comboBox.Items.ToList().FindIndex(i => value.Equals((string)((ComboBoxItem)i!).Tag!)); } public ComboBoxOption(List<(string Key, string Value)> options) { - _comboBox = new ComboBox(); + _comboBox = new(); _comboBox.Items.AddRange(options.Select(o => new ComboBoxItem { Tag = o.Key, Content = o.Value })); _comboBox.SelectionChanged += (sender, args) => { OnChange?.Invoke(Value); }; } @@ -162,7 +171,7 @@ protected override Control GetControl() public class BooleanOption : Option { - public Action OnChange { get; set; } + public Action? OnChange { get; set; } public bool Value { @@ -239,10 +248,10 @@ protected override Control GetControl() public class FileOption : Option { - public Action OnChange { get; set; } + public Action? OnChange { get; set; } protected Window _window; - public string Path + public string? Path { get => _pathBox.Text; set @@ -281,7 +290,7 @@ protected override Control GetControl() protected virtual async Task SelectButton_OnClick() { - IStorageFile file = await _window.ShowOpenFilePickerAsync(string.Empty, []); + IStorageFile? file = await _window.ShowOpenFilePickerAsync(string.Empty, []); if (file is not null) { _pathBox.Text = file.Path.LocalPath; @@ -297,10 +306,10 @@ public FolderOption(Window window) : base(window) protected override async Task SelectButton_OnClick() { - IStorageFolder folder = await _window.ShowOpenFolderPickerAsync(string.Empty); + IStorageFolder? folder = await _window.ShowOpenFolderPickerAsync(string.Empty); if (folder is not null) { _pathBox.Text = folder.Path.LocalPath; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Controls/SKCropResizeCanvas.cs b/src/SerialLoops/Controls/SKCropResizeCanvas.cs index eaf0e000..5cceefb8 100644 --- a/src/SerialLoops/Controls/SKCropResizeCanvas.cs +++ b/src/SerialLoops/Controls/SKCropResizeCanvas.cs @@ -143,7 +143,7 @@ protected virtual void OnPaintSurface(SKSurface surface) SelectionAreaLocation?.Y ?? 0f, (SelectionAreaLocation?.X ?? 0f) + (FinalBitmap?.Width ?? 0f), (SelectionAreaLocation?.Y ?? 0f) + (FinalBitmap?.Height ?? 0f)); - finalCanvas.DrawImage(surface.Snapshot(), surfaceRect, new SKRect(0, 0, FinalBitmap.Width, FinalBitmap.Height), + finalCanvas.DrawImage(surface.Snapshot(), surfaceRect, new SKRect(0, 0, FinalBitmap?.Width ?? 0, FinalBitmap?.Height ?? 0), new() { FilterQuality = SKFilterQuality.High }); finalCanvas.Flush(); } @@ -154,7 +154,7 @@ protected virtual void OnPaintSurface(SKSurface surface) uiPath.AddRect(areaRect); uiPath.FillType = SKPathFillType.EvenOdd; this.TryFindResource("CropResizeOverlayColor", ActualThemeVariant, out object? color); - canvas.DrawPath(uiPath, new SKPaint { Color = ((Color)color).ToSKColor() }); + canvas.DrawPath(uiPath, new SKPaint { Color = ((Color)(color ?? Colors.White)).ToSKColor() }); canvas.Flush(); } @@ -213,7 +213,7 @@ protected override void OnPointerMoved(PointerEventArgs e) base.OnPointerMoved(e); e.Handled = true; PointerPoint point = e.GetCurrentPoint(this); - + if (!point.Properties.IsLeftButtonPressed) { _lastPointerPosition = point.Position; @@ -239,4 +239,4 @@ protected override void OnPointerMoved(PointerEventArgs e) } _lastPointerPosition = point.Position; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Models/ITreeItem.cs b/src/SerialLoops/Models/ITreeItem.cs index 56ee7e14..ac4098bb 100644 --- a/src/SerialLoops/Models/ITreeItem.cs +++ b/src/SerialLoops/Models/ITreeItem.cs @@ -6,8 +6,8 @@ namespace SerialLoops.Models; public interface ITreeItem { public string Text { get; set; } - public Avalonia.Svg.Svg Icon { get; set; } - public ObservableCollection Children { get; set; } + public Avalonia.Svg.Svg? Icon { get; set; } + public ObservableCollection? Children { get; set; } public bool IsExpanded { get; set; } public Control GetDisplay(); -} \ No newline at end of file +} diff --git a/src/SerialLoops/Models/ItemDescriptionTreeItem.cs b/src/SerialLoops/Models/ItemDescriptionTreeItem.cs index 3477a0fa..0c8500a3 100644 --- a/src/SerialLoops/Models/ItemDescriptionTreeItem.cs +++ b/src/SerialLoops/Models/ItemDescriptionTreeItem.cs @@ -16,9 +16,9 @@ public class ItemDescriptionTreeItem : ITreeItem, IViewFor Margin = new(2), }; - public string Text { get; set; } - public Avalonia.Svg.Svg Icon { get; set; } = null; - public ObservableCollection Children { get; set; } = null; + public string Text { get; set; } = string.Empty; + public Avalonia.Svg.Svg? Icon { get; set; } = null; + public ObservableCollection? Children { get; set; } = null; public bool IsExpanded { get; set; } = false; public ItemDescriptionTreeItem(ItemDescription item) @@ -34,11 +34,11 @@ public Control GetDisplay() return _panel; } - object IViewFor.ViewModel + object? IViewFor.ViewModel { get => ViewModel; - set => ViewModel = (ItemDescription)value; + set => ViewModel = (ItemDescription?)value; } - public ItemDescription ViewModel { get; set; } -} \ No newline at end of file + public ItemDescription? ViewModel { get; set; } +} diff --git a/src/SerialLoops/Models/SKAvaloniaImage.cs b/src/SerialLoops/Models/SKAvaloniaImage.cs index fe7ab24f..454c9657 100644 --- a/src/SerialLoops/Models/SKAvaloniaImage.cs +++ b/src/SerialLoops/Models/SKAvaloniaImage.cs @@ -11,10 +11,10 @@ namespace SerialLoops.Models; public class SKBitmapDrawOperation : ICustomDrawOperation { public Rect Bounds { get; set; } - public SKBitmap Bitmap { get; set; } + public SKBitmap? Bitmap { get; set; } public void Dispose() { } - public bool Equals(ICustomDrawOperation other) => false; + public bool Equals(ICustomDrawOperation? other) => false; public bool HitTest(Point p) => Bounds.Contains(p); public void Render(ImmediateDrawingContext context) { @@ -34,8 +34,8 @@ public void Render(ImmediateDrawingContext context) public class SKAvaloniaImage : IImage, IDisposable { - private readonly SKBitmap _bitmap; - private SKBitmapDrawOperation _drawOperation; + private readonly SKBitmap? _bitmap; + private SKBitmapDrawOperation? _drawOperation; public SKAvaloniaImage(SKBitmap bitmap) { @@ -61,4 +61,4 @@ public void Draw(DrawingContext context, Rect sourceRect, Rect destRect) context.Custom(_drawOperation); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Models/ScriptCommandTreeItem.cs b/src/SerialLoops/Models/ScriptCommandTreeItem.cs index e887a4f0..a18cf337 100644 --- a/src/SerialLoops/Models/ScriptCommandTreeItem.cs +++ b/src/SerialLoops/Models/ScriptCommandTreeItem.cs @@ -17,9 +17,9 @@ public class ScriptCommandTreeItem : ITreeItem, IViewFor Margin = new(2), }; - public string Text { get; set; } - public Avalonia.Svg.Svg Icon { get; set; } = null; - public ObservableCollection Children { get; set; } = null; + public string Text { get; set; } = string.Empty; + public Avalonia.Svg.Svg? Icon { get; set; } = null; + public ObservableCollection? Children { get; set; } = null; public bool IsExpanded { get; set; } = false; public ScriptCommandTreeItem(ScriptItemCommand command) @@ -34,11 +34,11 @@ public Control GetDisplay() return _panel; } - object IViewFor.ViewModel + object? IViewFor.ViewModel { get => ViewModel; - set => ViewModel = (ScriptItemCommand)value; + set => ViewModel = (ScriptItemCommand?)value; } - public ScriptItemCommand ViewModel { get; set; } + public ScriptItemCommand? ViewModel { get; set; } } diff --git a/src/SerialLoops/Models/ScriptSectionTreeItem.cs b/src/SerialLoops/Models/ScriptSectionTreeItem.cs index f9a6d271..1ecae896 100644 --- a/src/SerialLoops/Models/ScriptSectionTreeItem.cs +++ b/src/SerialLoops/Models/ScriptSectionTreeItem.cs @@ -19,9 +19,9 @@ public class ScriptSectionTreeItem : ITreeItem, IViewFor Margin = new(2), }; - public string Text { get; set; } - public Avalonia.Svg.Svg Icon { get; set; } = null; - public ObservableCollection Children { get; set; } + public string Text { get; set; } = string.Empty; + public Avalonia.Svg.Svg? Icon { get; set; } = null; + public ObservableCollection? Children { get; set; } public bool IsExpanded { get; set; } = true; public ScriptSectionTreeItem(ScriptSection section, List commands) @@ -38,11 +38,11 @@ public Control GetDisplay() return _panel; } - object IViewFor.ViewModel + object? IViewFor.ViewModel { get => ViewModel; - set => ViewModel = (ScriptSection)value; + set => ViewModel = (ScriptSection?)value; } - public ScriptSection ViewModel { get; set; } -} \ No newline at end of file + public ScriptSection? ViewModel { get; set; } +} diff --git a/src/SerialLoops/Models/SectionTreeItem.cs b/src/SerialLoops/Models/SectionTreeItem.cs index 28a8d526..99c5abb2 100644 --- a/src/SerialLoops/Models/SectionTreeItem.cs +++ b/src/SerialLoops/Models/SectionTreeItem.cs @@ -7,11 +7,11 @@ namespace SerialLoops.Models; -public class SectionTreeItem(string sectionName, IEnumerable children, Avalonia.Svg.Svg icon) : ReactiveObject, ITreeItem +public class SectionTreeItem(string sectionName, IEnumerable children, Avalonia.Svg.Svg? icon) : ReactiveObject, ITreeItem { public string Text { get; set; } = sectionName; - public Avalonia.Svg.Svg Icon { get; set; } = icon; - public ObservableCollection Children { get; set; } = new(children); + public Avalonia.Svg.Svg? Icon { get; set; } = icon; + public ObservableCollection? Children { get; set; } = new(children); [Reactive] public bool IsExpanded { get; set; } @@ -33,4 +33,4 @@ public Control GetDisplay() panel.Children.Add(new TextBlock { Text = Text }); return panel; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/SerialLoops.csproj b/src/SerialLoops/SerialLoops.csproj index 5ee01300..31fc62de 100644 --- a/src/SerialLoops/SerialLoops.csproj +++ b/src/SerialLoops/SerialLoops.csproj @@ -55,7 +55,7 @@ - + diff --git a/src/SerialLoops/Utility/ALWavePlayer.cs b/src/SerialLoops/Utility/ALWavePlayer.cs index c7e844ba..f26f9974 100644 --- a/src/SerialLoops/Utility/ALWavePlayer.cs +++ b/src/SerialLoops/Utility/ALWavePlayer.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using NAudio.Wave; using OpenTK.Audio.OpenAL; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace SerialLoops.Utility; @@ -82,7 +83,7 @@ public float Volume private System.Threading.ManualResetEventSlim _signaller; - private System.Threading.CancellationTokenSource _playerCanceller; + private System.Threading.CancellationTokenSource? _playerCanceller; private Task Player; public WaveFormat OutputWaveFormat => WaveProvider.WaveFormat; diff --git a/src/SerialLoops/Utility/ControlGenerator.cs b/src/SerialLoops/Utility/ControlGenerator.cs index 9e1599f4..e83fc3e2 100644 --- a/src/SerialLoops/Utility/ControlGenerator.cs +++ b/src/SerialLoops/Utility/ControlGenerator.cs @@ -11,7 +11,7 @@ namespace SerialLoops.Utility; public static class ControlGenerator { - public static Bitmap GetIcon(string iconName, ILogger log, int size = 100) + public static Bitmap? GetIcon(string iconName, ILogger log, int size = 100) { try { @@ -25,12 +25,12 @@ public static Bitmap GetIcon(string iconName, ILogger log, int size = 100) } } - public static SvgImage GetVectorIcon(string iconName, ILogger log) + public static SvgImage? GetVectorIcon(string iconName, ILogger log) { try { var path = $"avares://SerialLoops/Assets/Icons/{iconName}.svg"; - return new SvgImage { Source = SvgSource.Load(path, new Uri(path)) }; + return new() { Source = SvgSource.Load(path, new Uri(path)) }; } catch (Exception ex) { @@ -39,11 +39,11 @@ public static SvgImage GetVectorIcon(string iconName, ILogger log) } } - public static Avalonia.Svg.Svg GetVectorIcon(string iconName, ILogger log, int size = 100) + public static Avalonia.Svg.Svg? GetVectorIcon(string iconName, ILogger log, int size = 100) { try { - return new Avalonia.Svg.Svg(new Uri($"avares://SerialLoops/Assets/Icons/{iconName}.svg")) + return new(new Uri($"avares://SerialLoops/Assets/Icons/{iconName}.svg")) { Path = $"avares://SerialLoops/Assets/Icons/{iconName}.svg", Width = size, @@ -71,13 +71,17 @@ public static StackPanel GetControlWithIcon(Control control, string iconName, IL VerticalAlignment = VerticalAlignment.Center, Spacing = 5, }; - panel.Children.Add(GetVectorIcon(iconName, log, size: 16)); + Avalonia.Svg.Svg? vectorIcon = GetVectorIcon(iconName, log, size: 16); + if (vectorIcon is not null) + { + panel.Children.Add(vectorIcon); + } panel.Children.Add(control); return panel; } internal static TextBlock GetTextHeader(string text, int size = 14) { - return new TextBlock { Text = text, FontWeight = FontWeight.Bold, FontSize = size }; + return new() { Text = text, FontWeight = FontWeight.Bold, FontSize = size }; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Utility/GuiExtensions.cs b/src/SerialLoops/Utility/GuiExtensions.cs index 2c252958..a681f646 100644 --- a/src/SerialLoops/Utility/GuiExtensions.cs +++ b/src/SerialLoops/Utility/GuiExtensions.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Media; +using Avalonia.Platform; using Avalonia.Platform.Storage; using HaruhiChokuretsuLib.Util; using MsBox.Avalonia; @@ -15,7 +17,7 @@ namespace SerialLoops.Utility; public static class GuiExtensions { - public static async Task ShowOpenFilePickerAsync(this Window window, string title, IReadOnlyList fileFilter, string suggestedStartLocation = "") + public static async Task ShowOpenFilePickerAsync(this Window window, string title, IReadOnlyList fileFilter, string suggestedStartLocation = "") { FilePickerOpenOptions options = new() { @@ -28,7 +30,7 @@ public static async Task ShowOpenFilePickerAsync(this Window windo } return (await window.StorageProvider.OpenFilePickerAsync(options)).FirstOrDefault(); } - public static async Task ShowSaveFilePickerAsync(this Window window, string title, IReadOnlyList fileFilter, string suggestedFileName = "") + public static async Task ShowSaveFilePickerAsync(this Window window, string title, IReadOnlyList fileFilter, string suggestedFileName = "") { FilePickerSaveOptions options = new() { @@ -49,7 +51,7 @@ public static async Task> ShowOpenMultiFilePickerAsy }; return await window.StorageProvider.OpenFilePickerAsync(options); } - public static async Task ShowOpenFolderPickerAsync(this Window window, string title) + public static async Task ShowOpenFolderPickerAsync(this Window window, string title) { FolderPickerOpenOptions options = new() { @@ -65,7 +67,7 @@ public static async Task ShowMessageBoxAsync(this Window window, s { ButtonDefinitions = buttons, Icon = icon, - WindowIcon = new(ControlGenerator.GetIcon("AppIcon", log)), + WindowIcon = new(ControlGenerator.GetIcon("AppIcon", log)!), ContentTitle = title, ContentHeader = title, ContentMessage = message, @@ -94,13 +96,13 @@ public static void AddRange(this Avalonia.Controls.Controls controlsCollection, } } - public static NativeMenuItem FindNativeMenuItem(this NativeMenu menu, string header) + public static NativeMenuItem? FindNativeMenuItem(this NativeMenu menu, string header) { foreach (NativeMenuItemBase itemBase in menu.Items) { if (itemBase is NativeMenuItem item) { - if (item.Header.Equals(header)) + if (item.Header!.Equals(header)) { return item; } @@ -120,4 +122,4 @@ public static Color ToAvalonia(this SKColor color) { return new(color.Alpha, color.Red, color.Green, color.Blue); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Utility/LoopyLogger.cs b/src/SerialLoops/Utility/LoopyLogger.cs index 34e438e0..f51cf427 100644 --- a/src/SerialLoops/Utility/LoopyLogger.cs +++ b/src/SerialLoops/Utility/LoopyLogger.cs @@ -11,21 +11,15 @@ namespace SerialLoops.Utility; -public class LoopyLogger : ILogger +public class LoopyLogger(Window window) : ILogger { - private readonly Window _owner; private Config? _config; - private string _logFile; - - public LoopyLogger(Window window) - { - _owner = window; - } + private string _logFile = ""; public void Initialize(Config? config) { _config = config; - if (!Directory.Exists(_config.LogsDirectory)) + if (!Directory.Exists(_config!.LogsDirectory)) { Directory.CreateDirectory(_config.LogsDirectory); } @@ -60,7 +54,7 @@ public void LogError(string message, bool lookForWarnings = false) private async Task LogErrorAsync(string message, bool lookForWarnings = false) { - await _owner.ShowMessageBoxAsync(Strings.Error, string.Format(Strings.ERROR___0_, message), ButtonEnum.Ok, Icon.Error, this); + await window.ShowMessageBoxAsync(Strings.Error, string.Format(Strings.ERROR___0_, message), ButtonEnum.Ok, Icon.Error, this); if (!string.IsNullOrEmpty(_logFile) && !string.IsNullOrEmpty(message)) { for (int i = 0; i < 10; i++) @@ -121,4 +115,4 @@ public void LogCrash(Exception ex) } } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Utility/SLConverters.cs b/src/SerialLoops/Utility/SLConverters.cs index fc5f8c66..8e88bee9 100644 --- a/src/SerialLoops/Utility/SLConverters.cs +++ b/src/SerialLoops/Utility/SLConverters.cs @@ -21,108 +21,84 @@ namespace SerialLoops.Utility; public static partial class SLConverters { public static FuncValueConverter ItemTypeToIconConverter => new((type) => new Bitmap(AssetLoader.Open(new Uri($"avares://SerialLoops/Assets/Icons/{type.ToString().Replace(' ', '_')}.png")))); - public static FuncValueConverter SKBitmapToAvaloniaConverter => new((bitmap) => new SKAvaloniaImage(bitmap)); + public static FuncValueConverter SKBitmapToAvaloniaConverter => new((bitmap) => bitmap is null ? null : new(bitmap)); public static FuncValueConverter TopScreenSelectableConverter => new((screen) => screen != DsScreen.TOP); public static FuncValueConverter BottomScreenSelectableConverter => new((screen) => screen != DsScreen.BOTTOM); public static FuncValueConverter BothScreensSelectedConverter => new((screen) => screen == DsScreen.BOTH); public static FuncValueConverter BooleanBrushConverter => new((val) => val ? Brushes.Transparent : Brushes.LightGreen); - public static FuncValueConverter CharacterNameCropConverter => new((name) => name[4..]); - public static FuncValueConverter, string> ListDisplayConverter => new((strs) => string.Join(", ", strs.Select(s => s.ToString()))); + public static FuncValueConverter CharacterNameCropConverter => new((name) => name![4..]); + public static FuncValueConverter, string> ListDisplayConverter => new((strs) => string.Join(", ", strs?.Select(s => s.ToString()) ?? [])); } public class DisplayNameConverter : IMultiValueConverter { - public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) + public object Convert(IList values, Type targetType, object? parameter, CultureInfo culture) { - if (values[0] is not UnsetValueType && values[1] is not UnsetValueType) + if (values[0] is string displayName && values[1] is bool unsavedChanges) { - string displayName = (string)values[0]; - bool unsavedChanges = (bool)values[1]; - return unsavedChanges ? $"* {displayName}" : displayName; } return string.Empty; } } -public class TextSubstitutionConverter : IValueConverter -{ - private static Project _project; - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return ((string)value).GetSubstitutedString(_project); - } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return ((string)value).GetOriginalString(_project); - } - public static void SetProject(Project project) - { - _project = project; - } -} - public class SKAvaloniaColorConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - return ((SKColor)value).ToAvalonia(); + return ((SKColor?)value ?? SKColor.Empty).ToAvalonia(); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - return ((Color)value).ToSKColor(); + return ((Color?)value ?? new Color()).ToSKColor(); } } public class DoubleSubtractionConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - return (double)value - double.Parse((string)parameter); + return (double?)value ?? 0 - double.Parse((string?)parameter ?? "0"); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - return (double)value + double.Parse((string)parameter); + return (double?)value ?? 0 + double.Parse((string?)parameter ?? "0"); } } public class IntSubtractionConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - return (int)value - int.Parse((string)parameter); + return (int?)value ?? 0 - int.Parse((string?)parameter ?? "0"); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - return (int)value + int.Parse((string)parameter); + return (int?)value ?? 0 + int.Parse((string?)parameter ?? "0"); } } public class IntAdditionConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - return (int)value + int.Parse((string)parameter); + return (int?)value ?? 0 + int.Parse((string?)parameter ?? "0"); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { - return (int)value - int.Parse((string)parameter); + return (int?)value ?? 0 - int.Parse((string?)parameter ?? "0"); } } public class BgmLoopSampleToTimestampConverter : IMultiValueConverter { - public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) + public object Convert(IList values, Type targetType, object? parameter, CultureInfo culture) { - if (values[0] is not UnsetValueType && values[1] is not UnsetValueType) + if (values[0] is BgmLoopPreviewItem loopPreview && values[1] is uint sample) { - BgmLoopPreviewItem loopPreview = (BgmLoopPreviewItem)values[0]; - uint sample = (uint)values[1]; - return (decimal)loopPreview.GetTimestampFromSample(sample); } return (decimal)0.0; diff --git a/src/SerialLoops/Utility/UpdateChecker.cs b/src/SerialLoops/Utility/UpdateChecker.cs index 9ee90773..5f4a4c3f 100644 --- a/src/SerialLoops/Utility/UpdateChecker.cs +++ b/src/SerialLoops/Utility/UpdateChecker.cs @@ -26,11 +26,16 @@ internal class UpdateChecker(MainWindowViewModel mainWindowViewModel) private MainWindowViewModel _mainWindowViewModel = mainWindowViewModel; private ILogger _logger => _mainWindowViewModel.Log; - private bool _preReleaseChannel => _mainWindowViewModel.CurrentConfig.PreReleaseChannel; + private bool _preReleaseChannel => _mainWindowViewModel.CurrentConfig!.PreReleaseChannel; public async void Check() { - (string version, string url, JsonArray assets, string changelog) = await GetLatestVersion(_currentVersion); + (string? version, string? url, JsonArray? assets, string? changelog) = await GetLatestVersion(_currentVersion); + if (version is null) + { + _logger.LogError("Update check failed: version was null!"); + return; + } if (_currentVersion.StartsWith(version)) // version might be something like 0.1.1, but current version will always be 4 digits { return; @@ -39,30 +44,34 @@ public async void Check() _logger.Log($"An update for Serial Loops is available! ({version})"); UpdateAvailableDialog updateDisplay = new(); UpdateAvailableDialogViewModel updateDisplayViewModel = new(); - updateDisplayViewModel.Initialize(_mainWindowViewModel, updateDisplay, version, assets, url, changelog); + updateDisplayViewModel.Initialize(_mainWindowViewModel, updateDisplay, version, assets!, url!, changelog!); updateDisplay.DataContext = updateDisplayViewModel; updateDisplay.ViewModel = updateDisplayViewModel; await updateDisplay.ShowDialog(_mainWindowViewModel.Window); } - private async Task<(string, string, JsonArray, string)> GetLatestVersion(string currentVersion) + private async Task<(string?, string?, JsonArray?, string?)> GetLatestVersion(string currentVersion) { HttpClient client = new(); client.DefaultRequestHeaders.UserAgent.Add( - new ProductInfoHeaderValue(USER_AGENT, currentVersion) + new(USER_AGENT, currentVersion) ); try { - var response = await client.GetAsync(GET_RELEASES); - var content = await response.Content.ReadAsStringAsync(); - var json = JsonNode.Parse(content).AsArray(); + HttpResponseMessage response = await client.GetAsync(GET_RELEASES); + string content = await response.Content.ReadAsStringAsync(); + JsonArray? json = JsonNode.Parse(content)?.AsArray(); - foreach (JsonNode release in json) + if (json is null) + { + throw new NullReferenceException("Failed to get latest version: parsed JSON was null!"); + } + foreach (JsonNode? release in json) { - if (bool.Parse(release["prerelease"].ToString()) == _preReleaseChannel) + if (bool.Parse(release?["prerelease"]?.ToString() ?? bool.FalseString) == _preReleaseChannel) { - return (release["tag_name"].ToString(), release["html_url"].ToString(), release["assets"].AsArray(), release["body"].ToString()); + return (release?["tag_name"]?.ToString(), release?["html_url"]?.ToString(), release?["assets"]?.AsArray(), release?["body"]?.ToString()); } } } @@ -73,4 +82,4 @@ public async void Check() return (currentVersion, "https://github.com/haroohie-club/SerialLoops/releases/latest", [], "N/A"); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Controls/AnimatedImageViewModel.cs b/src/SerialLoops/ViewModels/Controls/AnimatedImageViewModel.cs index d8caf404..f1263bcc 100644 --- a/src/SerialLoops/ViewModels/Controls/AnimatedImageViewModel.cs +++ b/src/SerialLoops/ViewModels/Controls/AnimatedImageViewModel.cs @@ -9,22 +9,17 @@ namespace SerialLoops.ViewModels.Controls; public class AnimatedImageViewModel : ViewModelBase { [Reactive] - public SKBitmap CurrentFrame { get; set; } + public SKBitmap? CurrentFrame { get; set; } public int CurrentFrameIndex { get; set; } public List<(SKBitmap Frame, int Timing)> FramesWithTimings { get; set; } - public DispatcherTimer FrameTimer { get; set; } + public DispatcherTimer? FrameTimer { get; set; } public AnimatedImageViewModel(IEnumerable<(SKBitmap Frame, int Timing)> framesWithTimings) { FramesWithTimings = [.. framesWithTimings]; Initialize(); } - public AnimatedImageViewModel(IEnumerable<(SKBitmap Frame, short Timing)> framesWithTimings) - { - FramesWithTimings = [.. framesWithTimings]; - Initialize(); - } private void Initialize() { @@ -55,12 +50,12 @@ public void Play() public void Stop() { - FrameTimer.Stop(); + FrameTimer?.Stop(); } - private void FrameTimer_Elapsed(object sender, EventArgs args) + private void FrameTimer_Elapsed(object? sender, EventArgs args) { - FrameTimer.Stop(); + FrameTimer?.Stop(); CurrentFrameIndex++; if (CurrentFrameIndex >= FramesWithTimings.Count) { @@ -69,4 +64,4 @@ private void FrameTimer_Elapsed(object sender, EventArgs args) UpdateImage(); Play(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Controls/ScreenSelectorViewModel.cs b/src/SerialLoops/ViewModels/Controls/ScreenSelectorViewModel.cs index e4b8f37d..03adda3a 100644 --- a/src/SerialLoops/ViewModels/Controls/ScreenSelectorViewModel.cs +++ b/src/SerialLoops/ViewModels/Controls/ScreenSelectorViewModel.cs @@ -8,7 +8,7 @@ namespace SerialLoops.ViewModels.Controls; public class ScreenSelectorViewModel : ViewModelBase { - public event EventHandler ScreenChanged; + public event EventHandler? ScreenChanged; public bool AllowSelectingBoth { get; set; } @@ -36,4 +36,4 @@ public ScreenSelectorViewModel(DsScreen selectedScreen, bool allowSelectingBoth) SelectBottomCommand = ReactiveCommand.Create(() => SelectedScreen = DsScreen.BOTTOM); SelectBothCommand = ReactiveCommand.Create((bothChecked) => SelectedScreen = bothChecked ? (SelectedScreen == DsScreen.BOTH ? DsScreen.BOTTOM : SelectedScreen) : DsScreen.BOTH); // reverse as IsChecked hasn't changed yet } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Controls/SoundPlayerPanelViewModel.cs b/src/SerialLoops/ViewModels/Controls/SoundPlayerPanelViewModel.cs index b5f30635..50fddc7f 100644 --- a/src/SerialLoops/ViewModels/Controls/SoundPlayerPanelViewModel.cs +++ b/src/SerialLoops/ViewModels/Controls/SoundPlayerPanelViewModel.cs @@ -1,4 +1,5 @@ using System.Windows.Input; +using HaruhiChokuretsuLib.Audio.SDAT; using HaruhiChokuretsuLib.Util; using NAudio.Wave; using ReactiveUI; @@ -16,7 +17,7 @@ public class SoundPlayerPanelViewModel : ViewModelBase internal SoundPlayer _player; [Reactive] - public IWaveProvider Sound { get; set; } + public IWaveProvider? Sound { get; set; } [Reactive] public SKBitmap Waveform { get; set; } [Reactive] @@ -26,14 +27,14 @@ public class SoundPlayerPanelViewModel : ViewModelBase [Reactive] public string TrackName { get; set; } public ICommand TrackNameCommand { get; set; } - public bool UseTextBoxForTrackName => TrackNameCommand is not null; + public bool UseTextBoxForTrackName => !string.IsNullOrEmpty(TrackName); public string TrackDetails { get; set; } public short? TrackFlag { get; set; } public ICommand PlayPauseCommand { get; private set; } public ICommand StopCommand { get; private set; } - public SoundPlayerPanelViewModel(ISoundItem item, ILogger log, string trackName, string trackDetails = null, short? trackFlag = null, ICommand trackNameCommand = null) + public SoundPlayerPanelViewModel(ISoundItem item, ILogger log, string trackName, string trackDetails = "", short? trackFlag = null, ICommand? trackNameCommand = null) { _log = log; _item = item; @@ -41,14 +42,15 @@ public SoundPlayerPanelViewModel(ISoundItem item, ILogger log, string trackName, TrackName = trackName; TrackDetails = trackDetails; TrackFlag = trackFlag; - TrackNameCommand = trackNameCommand; + TrackNameCommand = trackNameCommand ?? ReactiveCommand.Create(() => { }); InitializePlayer(); PlayPauseCommand = ReactiveCommand.Create(PlayPause_Executed); StopCommand = ReactiveCommand.Create(Stop_Executed); - _player.PlaybackStopped += (sender, args) => + _player!.PlaybackStopped += (sender, args) => { Stop(); }; + Waveform = new(); } private void InitializePlayer() @@ -85,4 +87,4 @@ private void Stop_Executed() { Stop(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/AboutDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/AboutDialogViewModel.cs index 542fdea4..e1f69cc6 100644 --- a/src/SerialLoops/ViewModels/Dialogs/AboutDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/AboutDialogViewModel.cs @@ -4,7 +4,7 @@ namespace SerialLoops.ViewModels.Dialogs; public class AboutDialogViewModel : ViewModelBase { - public string Version => Assembly.GetExecutingAssembly().GetCustomAttribute().InformationalVersion; + public string Version => Assembly.GetExecutingAssembly().GetCustomAttribute()!.InformationalVersion; public double Width => 500; public double Height => 450; -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs index 0899c103..71d83cce 100644 --- a/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/AsmHacksDialogViewModel.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using System.Windows.Input; using Avalonia.Controls; +using Avalonia.Logging; using Avalonia.Media; using Avalonia.Platform.Storage; using Avalonia.Styling; @@ -35,7 +36,7 @@ public class AsmHacksDialogViewModel : ViewModelBase public Config? Configuration { get; set; } private Dictionary _hackParameters { get; set; } = []; [Reactive] - public AsmHack SelectedHack { get; set; } + public AsmHack? SelectedHack { get; set; } public ICommand HackChangedCommand { get; set; } public ICommand ImportHackCommand { get; set; } public ICommand SaveCommand { get; set; } @@ -52,20 +53,20 @@ public AsmHacksDialogViewModel(Project project, Config? config, ILogger log) CancelCommand = ReactiveCommand.Create((dialog) => dialog.Close()); DetermineHackParameters(); - Configuration.UpdateHackAppliedStatus(_project, log); + Configuration?.UpdateHackAppliedStatus(_project, log); } private void DetermineHackParameters() { - foreach (HackFile file in Configuration.Hacks.SelectMany(h => h.Files).Distinct()) + foreach (HackFile file in Configuration!.Hacks.SelectMany(h => h.Files!).Distinct()) { try { - _hackParameters.Add(file, file.Parameters.Select(p => new SelectedHackParameter { Parameter = p, Selection = 0 }).ToArray()); + _hackParameters.Add(file, file.Parameters!.Select(p => new SelectedHackParameter { Parameter = p, Selection = 0 }).ToArray()); } catch (Exception ex) { - _log.LogException(string.Format(Strings.Failed_to_add_parameters_for_hack_file__0__in_hack__1_, file.File, SelectedHack.Name), ex); + _log.LogException(string.Format(Strings.Failed_to_add_parameters_for_hack_file__0__in_hack__1_, file.File, SelectedHack?.Name), ex); } } } @@ -73,38 +74,44 @@ private void DetermineHackParameters() public void HackChangedCommand_Executed(StackPanel descriptionPanel) { descriptionPanel.Children.Clear(); - descriptionPanel.Children.Add(ControlGenerator.GetTextHeader(SelectedHack.Name)); - descriptionPanel.Children.Add(new TextBlock { Text = SelectedHack.Description, TextWrapping = TextWrapping.Wrap }); + descriptionPanel.Children.Add(ControlGenerator.GetTextHeader(SelectedHack?.Name!)); + descriptionPanel.Children.Add(new TextBlock { Text = SelectedHack?.Description, TextWrapping = TextWrapping.Wrap }); StackPanel parametersLayout = new() { Spacing = 5, Margin = new(3) }; - foreach (HackFile file in SelectedHack.Files) + foreach (HackFile file in SelectedHack?.Files ?? []) { for (int i = 0; i < _hackParameters[file].Length; i++) { int currentParam = i; // need this as i increments and will mess up the SelectionChanged method ComboBox parameterComboBox = new(); - parameterComboBox.Items.AddRange(_hackParameters[file][currentParam].Parameter.Values.Select(v => new ComboBoxItem { Tag = file, Content = v.Name })); + parameterComboBox.Items.AddRange(_hackParameters[file][currentParam].Parameter!.Values!.Select(v => new ComboBoxItem { Tag = file, Content = v.Name })); parameterComboBox.SelectedIndex = _hackParameters[file][currentParam].Selection; parameterComboBox.SelectionChanged += (sender, args) => { - SelectedHack.ValueChanged = true; + SelectedHack!.ValueChanged = true; _hackParameters[file][currentParam].Selection = parameterComboBox.SelectedIndex; }; parametersLayout.Children.Add(parameterComboBox); } } GroupBox.Avalonia.Controls.GroupBox paramtersBox = new() { Header = Strings.Parameters, Content = parametersLayout }; - paramtersBox.Theme = (ControlTheme)paramtersBox.FindResource("GroupBoxClassic"); + paramtersBox.Theme = (ControlTheme)paramtersBox.FindResource("GroupBoxClassic")!; descriptionPanel.Children.Add(paramtersBox); } public async Task ImportHackCommand_Executed(AsmHacksDialog dialog) { - IStorageFile file = await dialog.ShowOpenFilePickerAsync(Strings.Import_a_Hack, [new(Strings.Serialized_ASM_hack) { Patterns = ["*.slhack"] }]); + IStorageFile? file = await dialog.ShowOpenFilePickerAsync(Strings.Import_a_Hack, [new(Strings.Serialized_ASM_hack) { Patterns = ["*.slhack"] }]); if (file is not null) { - AsmHack hack = JsonSerializer.Deserialize(File.ReadAllText(file.Path.LocalPath)); + AsmHack? hack = JsonSerializer.Deserialize(File.ReadAllText(file.Path.LocalPath)); - if (Configuration.Hacks.Any(h => h.Files.Any(f => hack.Files.Contains(f)))) + if (hack is null) + { + _log.LogError("Failed to import hack: deserialized hack was null!"); + return; + } + + if (Configuration!.Hacks.Any(h => h.Files!.Any(f => hack.Files!.Contains(f)))) { _log.LogError(Strings.Error__duplicate_hack_detected__A_file_with_the_same_name_as_a_file_in_this_hack_has_already_been_imported_); return; @@ -115,9 +122,9 @@ public async Task ImportHackCommand_Executed(AsmHacksDialog dialog) return; } - foreach (HackFile hackFile in hack.Files) + foreach (HackFile hackFile in hack.Files!) { - File.Copy(Path.Combine(Path.GetDirectoryName(file.Path.LocalPath), hackFile.File), Path.Combine(Configuration.HacksDirectory, hackFile.File)); + File.Copy(Path.Combine(Path.GetDirectoryName(file.Path.LocalPath)!, hackFile.File!), Path.Combine(Configuration.HacksDirectory, hackFile.File!)); } hack.IsApplied = hack.Applied(_project); @@ -131,7 +138,7 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) { List appliedHacks = []; List alreadyAppliedHacks = []; - foreach (AsmHack hack in Configuration.Hacks) + foreach (AsmHack hack in Configuration!.Hacks) { bool alreadyApplied = hack.Applied(_project); @@ -145,25 +152,25 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) } else if (hack.IsApplied) { - hack.Apply(_project, Configuration, _hackParameters.Where(kv => hack.Files.Contains(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value), _log, forceApplication: true); + hack.Apply(_project, Configuration, _hackParameters.Where(kv => hack.Files!.Contains(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value), _log, forceApplication: true); appliedHacks.Add(hack); } hack.ValueChanged = false; } // Write the symbols file based on what the hacks say they need - File.WriteAllLines(Path.Combine(_project.BaseDirectory, "src", "symbols.x"), appliedHacks.Concat(alreadyAppliedHacks).SelectMany(h => h.Files.Where(f => !f.Destination.Contains("overlays", StringComparison.OrdinalIgnoreCase)).SelectMany(f => f.Symbols))); + File.WriteAllLines(Path.Combine(_project.BaseDirectory, "src", "symbols.x"), appliedHacks.Concat(alreadyAppliedHacks).SelectMany(h => h.Files!.Where(f => !f.Destination!.Contains("overlays", StringComparison.OrdinalIgnoreCase)).SelectMany(f => f.Symbols!))); for (int i = 0; i < NUM_OVERLAYS; i++) { - if (appliedHacks.Concat(alreadyAppliedHacks).Any(h => h.Files.Any(f => f.Destination.Contains($"main_{i:X4}", StringComparison.OrdinalIgnoreCase)))) + if (appliedHacks.Concat(alreadyAppliedHacks).Any(h => h.Files!.Any(f => f.Destination!.Contains($"main_{i:X4}", StringComparison.OrdinalIgnoreCase)))) { - File.WriteAllLines(Path.Combine(_project.BaseDirectory, "src", "overlays", $"main_{i:X4}", "symbols.x"), appliedHacks.Concat(alreadyAppliedHacks).SelectMany(h => h.Files.Where(f => f.Destination.Contains($"main_{i:X4}", StringComparison.OrdinalIgnoreCase)).SelectMany(f => f.Symbols))); + File.WriteAllLines(Path.Combine(_project.BaseDirectory, "src", "overlays", $"main_{i:X4}", "symbols.x"), appliedHacks.Concat(alreadyAppliedHacks).SelectMany(h => h.Files!.Where(f => f.Destination!.Contains($"main_{i:X4}", StringComparison.OrdinalIgnoreCase)).SelectMany(f => f.Symbols!))); } } // Build and insert ARM9 hacks string arm9Path = Path.Combine(_project.BaseDirectory, "src", "arm9.bin"); - ARM9 arm9 = null; + ARM9? arm9 = null; try { arm9 = new(File.ReadAllBytes(arm9Path), 0x02000000); @@ -179,8 +186,8 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) await new ProgressDialog(() => { ARM9AsmHack.Insert(Path.Combine(_project.BaseDirectory, "src"), arm9, 0x02005ECC, Configuration.UseDocker ? Configuration.DevkitArmDockerTag : string.Empty, - (object sender, DataReceivedEventArgs e) => { _log.Log(e.Data); ((IProgressTracker)tracker).Focus(e.Data, 1); }, - (object sender, DataReceivedEventArgs e) => _log.LogWarning(e.Data), + (_, e) => { _log.Log(e.Data); ((IProgressTracker)tracker).Focus(e.Data ?? string.Empty, 1); }, + (_, e) => _log.LogWarning(e.Data), devkitArmPath: Configuration.DevkitArmPath); }, () => { }, tracker, Strings.Patching_ARM9).ShowDialog(dialog); } @@ -191,13 +198,13 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) try { - Lib.IO.WriteBinaryFile(Path.Combine("rom", "arm9.bin"), arm9.GetBytes(), _project, _log); + Lib.IO.WriteBinaryFile(Path.Combine("rom", "arm9.bin"), arm9?.GetBytes() ?? [], _project, _log); } catch (Exception ex) { _log.LogException("Failed to write ARM9 to disk", ex); } - if (appliedHacks.All(h => h.Files.Any(f => f.Destination.Contains("overlays", StringComparison.OrdinalIgnoreCase)))) + if (appliedHacks.All(h => h.Files!.Any(f => f.Destination!.Contains("overlays", StringComparison.OrdinalIgnoreCase)))) { // Overlay compilation relies on the presence of an arm9_newcode.x containing the symbols of the newly compiled ARM9 code // If there is no ARM9 code, we'll need to provide an empty file @@ -237,7 +244,7 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) await new ProgressDialog(() => { OverlayAsmHack.Insert(overlaySourceDir, overlays[i], newRomInfoPath, Configuration.UseDocker ? Configuration.DevkitArmDockerTag : string.Empty, - (object sender, DataReceivedEventArgs e) => { _log.Log(e.Data); ((IProgressTracker)tracker).Focus(e.Data, 1); }, + (object sender, DataReceivedEventArgs e) => { _log.Log(e.Data); ((IProgressTracker)tracker).Focus(e.Data ?? string.Empty, 1); }, (object sender, DataReceivedEventArgs e) => _log.LogWarning(e.Data), devkitArmPath: Configuration.DevkitArmPath); }, () => { }, tracker, string.Format(Strings.Patching_Overlay__0_, overlays[i].Name)).ShowDialog(dialog); @@ -258,7 +265,7 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) overlay.Save(Path.Combine(_project.BaseDirectory, "rom", "overlay", $"{overlay.Name}.bin")); File.Copy(Path.Combine(_project.BaseDirectory, "rom", "overlay", $"{overlay.Name}.bin"), Path.Combine(_project.IterativeDirectory, "rom", "overlay", $"{overlay.Name}.bin"), true); - _project.Settings.File.RomInfo.ARM9Ovt.First(o => o.Id == overlay.Id).RamSize = (uint)overlay.Length; + _project.Settings!.File.RomInfo.ARM9Ovt.First(o => o.Id == overlay.Id).RamSize = (uint)overlay.Length; } catch (Exception ex) { @@ -269,7 +276,7 @@ public async Task SaveCommand_Executed(AsmHacksDialog dialog) // We don't provide visible errors during the compilation of the hacks because it will deadlock the threads // So at the end, we should check if any of the hacks that were supposed to be applied are not applied, // and if there are some then we should let the user know. - IEnumerable failedHackNames = appliedHacks.Where(h => !h.Applied(_project)).Select(h => h.Name); + IEnumerable failedHackNames = appliedHacks.Where(h => !h.Applied(_project)).Select(h => h.Name)!; if (failedHackNames.Any()) { _log.LogError(string.Format(Strings.Failed_to_apply_the_following_hacks_to_the_ROM__n_0__n_nPlease_check_the_log_file_for_more_information__n_nIn_order_to_preserve_state__no_hacks_were_applied_, string.Join(", ", failedHackNames))); @@ -304,4 +311,4 @@ await dialog.ShowMessageBoxAsync(Strings.Successfully_applied_hacks_, string.For dialog.Close(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/BgmLoopPropertiesDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/BgmLoopPropertiesDialogViewModel.cs index 18f786d2..65665113 100644 --- a/src/SerialLoops/ViewModels/Dialogs/BgmLoopPropertiesDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/BgmLoopPropertiesDialogViewModel.cs @@ -37,9 +37,9 @@ public BgmLoopPropertiesDialogViewModel(WaveStream wav, string title, ILogger lo endSample = (uint)(wav.Length / (wav.WaveFormat.BitsPerSample / 8)); } LoopPreview = new(wav, loopEnabled, startSample, endSample); - LoopPreviewPlayer = new(LoopPreview, Log, null); + LoopPreviewPlayer = new(LoopPreview, Log, string.Empty); SaveCommand = ReactiveCommand.Create((dialog) => dialog.Close(LoopPreview)); CancelCommand = ReactiveCommand.Create((dialog) => dialog.Close()); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/BgmVolumePropertiesDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/BgmVolumePropertiesDialogViewModel.cs index 17118286..edab12e0 100644 --- a/src/SerialLoops/ViewModels/Dialogs/BgmVolumePropertiesDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/BgmVolumePropertiesDialogViewModel.cs @@ -39,7 +39,7 @@ public BgmVolumePropertiesDialogViewModel(WaveStream wav, string title, ILogger Waveform = WaveformRenderer.Render(wav, WaveFormRendererSettings.StandardSettings); _waveLength = wav.Length; VolumePreview = new(wav); - VolumePreviewPlayer = new(VolumePreview, _log, null); + VolumePreviewPlayer = new(VolumePreview, _log, string.Empty); VolumeSliderValueChangedCommand = ReactiveCommand.Create(VolumeSlider_ValueChanged); SaveCommand = ReactiveCommand.Create((dialog) => dialog.Close(VolumePreview)); @@ -55,4 +55,4 @@ private void VolumeSlider_ValueChanged() _wav.Seek(0, SeekOrigin.Begin); VolumePreviewPlayer.Stop(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/GraphicSelectionDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/GraphicSelectionDialogViewModel.cs index ec21223b..7cb26787 100644 --- a/src/SerialLoops/ViewModels/Dialogs/GraphicSelectionDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/GraphicSelectionDialogViewModel.cs @@ -20,12 +20,12 @@ public class GraphicSelectionDialogViewModel : ViewModelBase private readonly ILogger _log; private readonly IEnumerable _items; private Func _specialPredicate; - private IPreviewableGraphic _currentSelection; + private IPreviewableGraphic? _currentSelection; private string _filter; [Reactive] public ObservableCollection Items { get; set; } - public IPreviewableGraphic CurrentSelection + public IPreviewableGraphic? CurrentSelection { get => _currentSelection; set @@ -51,23 +51,25 @@ public string Filter Items = new(_items.Where(i => i.Text.Contains(_filter, StringComparison.OrdinalIgnoreCase))); } } + [Reactive] - public string PreviewLabel { get; set; } + public string PreviewLabel { get; set; } = string.Empty; [Reactive] - public SKBitmap Preview { get; set; } + public SKBitmap? Preview { get; set; } public ICommand ConfirmCommand { get; } public ICommand CancelCommand { get; } - public GraphicSelectionDialogViewModel(IEnumerable items, IPreviewableGraphic currentSelection, Project project, ILogger log, Func specialPredicate = null) : base() + public GraphicSelectionDialogViewModel(IEnumerable items, IPreviewableGraphic? currentSelection, Project project, ILogger log, Func? specialPredicate = null) { _project = project; _log = log; _specialPredicate = specialPredicate ?? (i => true); - _items = items.Where(i => specialPredicate((ItemDescription)i)); + _items = specialPredicate is not null ? items.Where(i => specialPredicate((ItemDescription)i)) : items; Items = new(_items); CurrentSelection = currentSelection; + _filter = string.Empty; ConfirmCommand = ReactiveCommand.Create((dialog) => dialog.Close(CurrentSelection)); CancelCommand = ReactiveCommand.Create((dialog) => dialog.Close()); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs index 6e7b4c9d..7422ecca 100644 --- a/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/PreferencesDialogViewModel.cs @@ -12,6 +12,7 @@ using SerialLoops.Lib.Util; using SerialLoops.Views.Dialogs; using SixLabors.Fonts; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace SerialLoops.ViewModels.Dialogs; @@ -25,15 +26,15 @@ public class PreferencesDialogViewModel : ViewModelBase public ICommand SaveCommand { get; private set; } public ICommand CancelCommand { get; private set; } - private IConfigFactory _configFactory; + private IConfigFactory? _configFactory; public Config? Configuration { get; set; } - public ILogger Log { get; set; } + public ILogger? Log { get; set; } [Reactive] public bool RequireRestart { get; set; } public bool Saved { get; set; } - private PreferencesDialog _preferencesDialog; + private PreferencesDialog? _preferencesDialog; - public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfigFactory configFactory = null) + public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfigFactory? configFactory = null) { _preferencesDialog = preferencesDialog; if (configFactory is not null) @@ -52,34 +53,34 @@ public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfig new FolderOption(_preferencesDialog) { OptionName = Strings.devkitARM_Path, - Path = Configuration.DevkitArmPath, - OnChange = (path) => Configuration.DevkitArmPath = path, + Path = Configuration!.DevkitArmPath, + OnChange = (path) => Configuration.DevkitArmPath = path ?? string.Empty, }, new FileOption(_preferencesDialog) { OptionName = Strings.Emulator_Path, Path = Configuration.EmulatorPath, - OnChange = (path) => Configuration.EmulatorPath = path, + OnChange = (path) => Configuration.EmulatorPath = path ?? string.Empty, }, new TextOption { OptionName = Strings.Emulator_Flatpak, Value = Configuration.EmulatorFlatpak, - OnChange = (flatpak) => Configuration.EmulatorFlatpak = flatpak, + OnChange = (flatpak) => Configuration.EmulatorFlatpak = flatpak ?? string.Empty, Enabled = OperatingSystem.IsLinux(), }, new BooleanOption { OptionName = Strings.Use_Docker_for_ASM_Hacks, Value = Configuration.UseDocker, - OnChange = (value) => Configuration.UseDocker = value, + OnChange = (value) => Configuration.UseDocker = value ?? false, Enabled = !OperatingSystem.IsMacOS(), }, new TextOption { OptionName = Strings.devkitARM_Docker_Tag, Value = Configuration.DevkitArmDockerTag, - OnChange = (value) => Configuration.DevkitArmDockerTag = value, + OnChange = (value) => Configuration.DevkitArmDockerTag = value ?? string.Empty, Enabled = !OperatingSystem.IsMacOS(), } ]); @@ -89,19 +90,19 @@ public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfig { OptionName = Strings.Auto_Re_Open_Last_Project, Value = Configuration.AutoReopenLastProject, - OnChange = (value) => Configuration.AutoReopenLastProject = value, + OnChange = (value) => Configuration.AutoReopenLastProject = value ?? false, }, new BooleanOption { OptionName = Strings.Remember_Project_Workspace, Value = Configuration.RememberProjectWorkspace, - OnChange = (value) => Configuration.RememberProjectWorkspace = value, + OnChange = (value) => Configuration.RememberProjectWorkspace = value ?? false, }, new BooleanOption { OptionName = Strings.Remove_Missing_Projects, Value = Configuration.RemoveMissingProjects, - OnChange = (value) => Configuration.RemoveMissingProjects = value, + OnChange = (value) => Configuration.RemoveMissingProjects = value ?? false, }, ]); _preferencesDialog.SerialLoopsOptions.InitializeOptions("Serial Loops", @@ -122,7 +123,7 @@ public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfig OnChange = (value) => { Strings.Culture = CultureInfo.CurrentCulture; - Configuration.CurrentCultureName = value; + Configuration.CurrentCultureName = value?? "en"; RequireRestart = true; }, }, @@ -135,7 +136,7 @@ public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfig Value = Configuration.DisplayFont ?? "", OnChange = (value) => { - Configuration.DisplayFont = value; + Configuration.DisplayFont = value ?? Strings.Default_Font; RequireRestart = true; }, }, @@ -143,13 +144,13 @@ public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfig { OptionName = Strings.Check_for_Updates_on_Startup, Value = Configuration.CheckForUpdates, - OnChange = (value) => Configuration.CheckForUpdates = value, + OnChange = (value) => Configuration.CheckForUpdates = value ?? false, }, new BooleanOption { OptionName = Strings.Use_Pre_Release_Update_Channel, Value = Configuration.PreReleaseChannel, - OnChange = (value) => Configuration.PreReleaseChannel = value, + OnChange = (value) => Configuration.PreReleaseChannel = value ?? false, } ]); @@ -159,9 +160,9 @@ public void Initialize(PreferencesDialog preferencesDialog, ILogger log, IConfig public void SaveCommand_Executed() { - Configuration.Save(Log); + Configuration!.Save(Log!); Saved = true; - _preferencesDialog.Close(); + _preferencesDialog!.Close(); } private static (string Culture, string Language) GetLanguageComboxBoxOption(string culture) diff --git a/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs index a3d93e86..a0a0d498 100644 --- a/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/ProjectCreationDialogViewModel.cs @@ -22,8 +22,8 @@ public partial class ProjectCreationDialogViewModel : ViewModelBase private Config? _config; public string? ProjectName { get; set; } - public ComboBoxItem LanguageTemplateItem { get; set; } - public string? LanguageTemplateCode => (string)LanguageTemplateItem?.Tag ?? ""; + public ComboBoxItem? LanguageTemplateItem { get; set; } + public string LanguageTemplateCode => (string?)LanguageTemplateItem?.Tag ?? ""; [Reactive] public string RomPath { get; set; } = Strings.None_Selected; @@ -43,7 +43,7 @@ public ProjectCreationDialogViewModel(Config? config, MainWindowViewModel mainWi private async Task PickRom() { - IStorageFile rom = await _mainWindow.Window.ShowOpenFilePickerAsync(Strings.Open_ROM, [new FilePickerFileType(Strings.Chokuretsu_ROM) { Patterns = ["*.nds"] }]); + IStorageFile? rom = await _mainWindow.Window.ShowOpenFilePickerAsync(Strings.Open_ROM, [new FilePickerFileType(Strings.Chokuretsu_ROM) { Patterns = ["*.nds"] }]); if (rom is not null) { RomPath = rom.Path.LocalPath; diff --git a/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs index 32c03c89..d31b3071 100644 --- a/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/ProjectSettingsDialogViewModel.cs @@ -8,6 +8,7 @@ using SerialLoops.Utility; using SerialLoops.Views.Dialogs; using SkiaSharp; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace SerialLoops.ViewModels.Dialogs; @@ -25,13 +26,13 @@ public class ProjectSettingsDialogViewModel : ViewModelBase [Reactive] public string GameTitle { get; set; } - private SKBitmap _icon; - public SKBitmap Icon + private SKBitmap? _icon; + public SKBitmap? Icon { get { SKBitmap preview = new(64, 64); - _icon.ScalePixels(preview, SKFilterQuality.None); + _icon?.ScalePixels(preview, SKFilterQuality.None); return preview; } set => this.RaiseAndSetIfChanged(ref _icon, value); @@ -47,8 +48,8 @@ public void Initialize(ProjectSettingsDialog settingsDialog, ProjectSettings? se _settingsDialog = settingsDialog; _settings = settings; - Icon = settings.Icon; - GameTitle = settings.Name; + Icon = settings?.Icon; + GameTitle = settings?.Name ?? string.Empty; Log = log; ReplaceCommand = ReactiveCommand.Create(ReplaceCommand_Executed); @@ -58,7 +59,7 @@ public void Initialize(ProjectSettingsDialog settingsDialog, ProjectSettings? se private async void ReplaceCommand_Executed() { - IStorageFile image = await _settingsDialog.ShowOpenFilePickerAsync(Strings.Replace_Game_Icon, [new FilePickerFileType(Strings.Supported_Images) { Patterns = Shared.SupportedImageFiletypes }]); + IStorageFile? image = await _settingsDialog.ShowOpenFilePickerAsync(Strings.Replace_Game_Icon, [new FilePickerFileType(Strings.Supported_Images) { Patterns = Shared.SupportedImageFiletypes }]); if (image is null) { return; @@ -87,14 +88,14 @@ private void ApplyCommand_Executed() Log.LogError(Strings.Game_banner_can_only_contain_up_to_three_lines_); return; } - _settings.Name = GameTitle; + _settings!.Name = GameTitle; if (Icon is not null) { - _settings.Icon = _icon; + _settings.Icon = Icon; } Applied = true; _settingsDialog.Close(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs b/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs index 74c0051d..3d425a72 100644 --- a/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs +++ b/src/SerialLoops/ViewModels/Dialogs/UpdateAvailableDialogViewModel.cs @@ -7,6 +7,7 @@ using SerialLoops.Assets; using SerialLoops.Lib; using SerialLoops.Views.Dialogs; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace SerialLoops.ViewModels.Dialogs; @@ -50,4 +51,4 @@ public void OpenReleaseLink() { Process.Start(new ProcessStartInfo(Url) { UseShellExecute = true }); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/BackgroundEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/BackgroundEditorViewModel.cs index 65a2bcb7..a76ff78e 100644 --- a/src/SerialLoops/ViewModels/Editors/BackgroundEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/BackgroundEditorViewModel.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Input; +using Avalonia.Logging; using Avalonia.Platform.Storage; using HaruhiChokuretsuLib.Archive.Data; using HaruhiChokuretsuLib.Archive.Graphics; @@ -23,7 +24,7 @@ namespace SerialLoops.ViewModels.Editors; public class BackgroundEditorViewModel : EditorViewModel { public BackgroundItem Bg { get; set; } - public SKBitmap BgBitmap => Bg.GetBackground(); + public SKBitmap? BgBitmap => Bg.GetBackground(); public string BgDescription => $"{Bg.Id} (0x{Bg.Id:X3}); {Bg.BackgroundType}"; public ICommand ExportCommand { get; set; } public ICommand ReplaceCommand { get; set; } @@ -42,7 +43,7 @@ public BackgroundEditorViewModel(BackgroundItem item, MainWindowViewModel window { if (!string.IsNullOrEmpty(cgName) && !cgName.Equals(Bg.CgName)) { - _project.Extra.Cgs[_project.Extra.Cgs.IndexOf(_project.Extra.Cgs.First(b => b.Name?.GetSubstitutedString(_project).Equals(Bg.CgName) ?? false))].Name = cgName.GetOriginalString(_project); + _project!.Extra!.Cgs[_project.Extra.Cgs.IndexOf(_project.Extra.Cgs.First(b => b.Name?.GetSubstitutedString(_project).Equals(Bg.CgName) ?? false))].Name = cgName.GetOriginalString(_project); Bg.CgName = cgName; Description.UnsavedChanges = true; } @@ -58,13 +59,13 @@ private async Task ExportButton_Click() new FilePickerFileType(Strings.PNG_Image) { Patterns = ["*.png"] } ] }; - IStorageFile savedFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Export_Background_Image, [new FilePickerFileType(Strings.PNG_Image) { Patterns = ["*.png"] }], $"{Bg.Name}.png"); + IStorageFile? savedFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Export_Background_Image, [new FilePickerFileType(Strings.PNG_Image) { Patterns = ["*.png"] }], $"{Bg.Name}.png"); if (savedFile is not null) { try { using FileStream fs = File.Create(savedFile.Path.LocalPath); - Bg.GetBackground().Encode(fs, SKEncodedImageFormat.Png, GraphicsFile.PNG_QUALITY); + Bg.GetBackground()!.Encode(fs, SKEncodedImageFormat.Png, GraphicsFile.PNG_QUALITY); } catch (Exception ex) { @@ -75,23 +76,28 @@ private async Task ExportButton_Click() private async Task ReplaceButton_Click() { - IStorageFile openFile = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_Background_Image, [new FilePickerFileType(Strings.Supported_Images) { Patterns = Shared.SupportedImageFiletypes }]); + IStorageFile? openFile = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_Background_Image, [new FilePickerFileType(Strings.Supported_Images) { Patterns = Shared.SupportedImageFiletypes }]); if (openFile is not null) { - SKBitmap original = Bg.GetBackground(); + SKBitmap? original = Bg.GetBackground(); + if (original is null) + { + _log.LogError("Can't replace background image: background image was null!"); + return; + } SKBitmap newImage = SKBitmap.Decode(openFile.Path.LocalPath); ImageCropResizeDialogViewModel cropResizeDialogViewModel = new(newImage, original.Width, original.Height, _log); - SKBitmap finalImage = await new ImageCropResizeDialog() + SKBitmap? finalImage = await new ImageCropResizeDialog() { DataContext = cropResizeDialogViewModel, - }.ShowDialog(_window.Window); + }.ShowDialog(_window.Window); if (finalImage is not null) { try { LoopyProgressTracker tracker = new(); bool success = false; - await new ProgressDialog(() => success = Bg.SetBackground(finalImage, tracker, _log, _project.Localize), + await new ProgressDialog(() => success = Bg.SetBackground(finalImage, tracker, _log, _project!.Localize), () => { }, tracker, string.Format(Strings.Replacing__0____, Bg.DisplayName)).ShowDialog(_window.Window); if (success) { @@ -106,4 +112,4 @@ private async Task ReplaceButton_Click() } } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/BackgroundMusicEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/BackgroundMusicEditorViewModel.cs index a393ef79..003b67c9 100644 --- a/src/SerialLoops/ViewModels/Editors/BackgroundMusicEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/BackgroundMusicEditorViewModel.cs @@ -44,7 +44,7 @@ public BackgroundMusicEditorViewModel(BackgroundMusicItem bgm, MainWindowViewMod { Bgm = bgm; - _bgmCachedFile = Path.Combine(project.Config.CachesDirectory, "bgm", $"{Bgm.Name}.wav"); + _bgmCachedFile = Path.Combine(project.Config!.CachesDirectory, "bgm", $"{Bgm.Name}.wav"); _titleBoxTextChangedCommand = ReactiveCommand.Create(TitleBox_TextChanged); BgmPlayer = new(Bgm, _log, Bgm.BgmName, Bgm.Name, Bgm.Flag, !string.IsNullOrEmpty(Bgm.BgmName) ? _titleBoxTextChangedCommand : null); @@ -59,7 +59,7 @@ private void TitleBox_TextChanged(string newText) { if (!string.IsNullOrEmpty(newText) && !newText.Equals(Bgm.BgmName)) { - _project.Extra.Bgms[_project.Extra.Bgms.IndexOf(_project.Extra.Bgms.First(b => b.Name.GetSubstitutedString(_project) == Bgm.BgmName))].Name = newText.GetOriginalString(_project); + _project!.Extra!.Bgms[_project.Extra.Bgms.IndexOf(_project.Extra.Bgms.First(b => b.Name.GetSubstitutedString(_project) == Bgm.BgmName))].Name = newText.GetOriginalString(_project); Bgm.BgmName = newText; Bgm.UnsavedChanges = true; } @@ -67,7 +67,7 @@ private void TitleBox_TextChanged(string newText) private async Task Extract_Executed() { - IStorageFile file = await _window.Window.ShowSaveFilePickerAsync(Strings.Save_BGM_as_WAV, [new(Strings.WAV_File) { Patterns = ["*.wav"] }]); + IStorageFile? file = await _window.Window.ShowSaveFilePickerAsync(Strings.Save_BGM_as_WAV, [new(Strings.WAV_File) { Patterns = ["*.wav"] }]); if (file is not null) { LoopyProgressTracker tracker = new(); @@ -78,7 +78,7 @@ private async Task Extract_Executed() private async Task Replace_Executed() { - IStorageFile file = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_BGM, + IStorageFile? file = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_BGM, [ new(Strings.Supported_Audio_Files) { Patterns = Shared.SupportedAudioFiletypes }, new(Strings.WAV_files) { Patterns = ["*.wav"] }, @@ -93,7 +93,7 @@ private async Task Replace_Executed() BgmPlayer.Stop(); Shared.AudioReplacementCancellation.Cancel(); Shared.AudioReplacementCancellation = new(); - await new ProgressDialog(() => Bgm.Replace(file.Path.LocalPath, _project.BaseDirectory, _project.IterativeDirectory, _bgmCachedFile, _loopEnabled, _loopStartSample, _loopEndSample, _log, secondTracker, Shared.AudioReplacementCancellation.Token), + await new ProgressDialog(() => Bgm.Replace(file.Path.LocalPath, _project!.BaseDirectory, _project.IterativeDirectory, _bgmCachedFile, _loopEnabled, _loopStartSample, _loopEndSample, _log, secondTracker, Shared.AudioReplacementCancellation.Token), () => BgmPlayer = new(Bgm, _log, Bgm.BgmName, Bgm.Name, Bgm.Flag, !string.IsNullOrEmpty(Bgm.BgmName) ? _titleBoxTextChangedCommand : null), firstTracker, Strings.Replace_BGM_track).ShowDialog(_window.Window); } } @@ -102,7 +102,7 @@ private void Restore_Executed() { BgmPlayer.Stop(); File.Delete(_bgmCachedFile); // Clear the cached WAV as we're restoring the original ADX - File.Copy(Path.Combine(_project.BaseDirectory, "original", "bgm", Path.GetFileName(Bgm.BgmFile)), Path.Combine(_project.BaseDirectory, Bgm.BgmFile), true); + File.Copy(Path.Combine(_project!.BaseDirectory, "original", "bgm", Path.GetFileName(Bgm.BgmFile)), Path.Combine(_project.BaseDirectory, Bgm.BgmFile), true); File.Copy(Path.Combine(_project.IterativeDirectory, "original", "bgm", Path.GetFileName(Bgm.BgmFile)), Path.Combine(_project.IterativeDirectory, Bgm.BgmFile), true); BgmPlayer = new(Bgm, _log, Bgm.BgmName, Bgm.Name, Bgm.Flag, !string.IsNullOrEmpty(Bgm.BgmName) ? _titleBoxTextChangedCommand : null); } @@ -115,12 +115,12 @@ private async Task ManageLoop_Executed() { await new ProgressDialog(() => WaveFileWriter.CreateWaveFile(_bgmCachedFile, Bgm.GetWaveProvider(_log, false)), () => { }, firstTracker, Strings.Caching_BGM).ShowDialog(_window.Window); } - string loopAdjustedWav = Path.Combine(Path.GetDirectoryName(_bgmCachedFile), $"{Path.GetFileNameWithoutExtension(_bgmCachedFile)}-loop.wav"); + string loopAdjustedWav = Path.Combine(Path.GetDirectoryName(_bgmCachedFile)!, $"{Path.GetFileNameWithoutExtension(_bgmCachedFile)}-loop.wav"); File.Copy(_bgmCachedFile, loopAdjustedWav, true); - using WaveFileReader reader = new(loopAdjustedWav); + WaveFileReader reader = new(loopAdjustedWav); BgmLoopPropertiesDialogViewModel loopPropertiesDialog = new(reader, Bgm.Name, _log, - ((AdxWaveProvider)BgmPlayer.Sound).LoopEnabled, ((AdxWaveProvider)BgmPlayer.Sound).LoopStartSample, ((AdxWaveProvider)BgmPlayer.Sound).LoopEndSample); - BgmLoopPreviewItem loopPreview = await new BgmLoopPropertiesDialog() { DataContext = loopPropertiesDialog }.ShowDialog(_window.Window); + ((AdxWaveProvider)BgmPlayer.Sound!).LoopEnabled, ((AdxWaveProvider)BgmPlayer.Sound).LoopStartSample, ((AdxWaveProvider)BgmPlayer.Sound).LoopEndSample); + BgmLoopPreviewItem? loopPreview = await new BgmLoopPropertiesDialog() { DataContext = loopPropertiesDialog }.ShowDialog(_window.Window); if (loopPreview is not null) { _loopEnabled = loopPreview.LoopEnabled; @@ -132,7 +132,7 @@ private async Task ManageLoop_Executed() LoopyProgressTracker thirdTracker = new(Strings.Adjusting_Loop_Info); await new ProgressDialog(() => { - Bgm.Replace(_bgmCachedFile, _project.BaseDirectory, _project.IterativeDirectory, _bgmCachedFile, _loopEnabled, _loopStartSample, _loopEndSample, _log, secondTracker, Shared.AudioReplacementCancellation.Token); + Bgm.Replace(_bgmCachedFile, _project!.BaseDirectory, _project.IterativeDirectory, _bgmCachedFile, _loopEnabled, _loopStartSample, _loopEndSample, _log, secondTracker, Shared.AudioReplacementCancellation.Token); reader.Dispose(); File.Delete(loopAdjustedWav); }, @@ -151,7 +151,7 @@ private async Task AdjustVolume_Executed() { await new ProgressDialog(() => WaveFileWriter.CreateWaveFile(_bgmCachedFile, Bgm.GetWaveProvider(_log, false)), () => { }, firstTracker, Strings.Caching_BGM).ShowDialog(_window.Window); } - string volumeAdjustedWav = Path.Combine(Path.GetDirectoryName(_bgmCachedFile), $"{Path.GetFileNameWithoutExtension(_bgmCachedFile)}-volume.wav"); + string volumeAdjustedWav = Path.Combine(Path.GetDirectoryName(_bgmCachedFile)!, $"{Path.GetFileNameWithoutExtension(_bgmCachedFile)}-volume.wav"); File.Copy(_bgmCachedFile, volumeAdjustedWav, true); using WaveFileReader reader = new(volumeAdjustedWav); BgmVolumePropertiesDialogViewModel volumeDialog = new(reader, Bgm.Name, _log); @@ -167,7 +167,7 @@ private async Task AdjustVolume_Executed() { WaveFileWriter.CreateWaveFile(_bgmCachedFile, volumeDialog.VolumePreview.GetWaveProvider(_log, false)); secondTracker.Finished++; - Bgm.Replace(_bgmCachedFile, _project.BaseDirectory, _project.IterativeDirectory, _bgmCachedFile, _loopEnabled, _loopStartSample, _loopEndSample, _log, secondTracker, Shared.AudioReplacementCancellation.Token); + Bgm.Replace(_bgmCachedFile, _project!.BaseDirectory, _project.IterativeDirectory, _bgmCachedFile, _loopEnabled, _loopStartSample, _loopEndSample, _log, secondTracker, Shared.AudioReplacementCancellation.Token); secondTracker.Finished++; reader.Dispose(); File.Delete(volumeAdjustedWav); @@ -177,4 +177,4 @@ private async Task AdjustVolume_Executed() }, thirdTracker, Strings.Replace_BGM_track).ShowDialog(_window.Window); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/CharacterSpriteEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/CharacterSpriteEditorViewModel.cs index 5ce326f8..9c98b263 100644 --- a/src/SerialLoops/ViewModels/Editors/CharacterSpriteEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/CharacterSpriteEditorViewModel.cs @@ -73,8 +73,8 @@ public bool IsLarge public CharacterSpriteEditorViewModel(CharacterSpriteItem item, MainWindowViewModel mainWindow, ILogger log) : base(item, mainWindow, log) { _sprite = item; - AnimatedImage = new(_sprite.GetLipFlapAnimation(mainWindow.OpenProject)); - Characters = new(mainWindow.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Character).Cast()); + AnimatedImage = new(_sprite.GetLipFlapAnimation(mainWindow.OpenProject!)); + Characters = new(mainWindow.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Character).Cast()); _character = (CharacterItem)mainWindow.OpenProject.Items.First(i => i.Type == ItemDescription.ItemType.Character && ((CharacterItem)i).MessageInfo.Character == item.Sprite.Character); _isLarge = _sprite.Sprite.IsLarge; @@ -85,12 +85,12 @@ public CharacterSpriteEditorViewModel(CharacterSpriteItem item, MainWindowViewMo private async Task ReplaceSprite() { - + await Task.Delay(1); } private async Task ExportFrames() { - IStorageFolder dir = await _window.Window.ShowOpenFolderPickerAsync(Strings.Select_character_sprite_export_folder); + IStorageFolder? dir = await _window.Window.ShowOpenFolderPickerAsync(Strings.Select_character_sprite_export_folder); if (dir is not null) { SKBitmap layout = _sprite.GetBaseLayout(); @@ -144,14 +144,14 @@ private async Task ExportGIF() List<(SKBitmap bitmap, int timing)> animationFrames; if (await _window.Window.ShowMessageBoxAsync(Strings.Animation_Export_Option, Strings.Include_lip_flap_animation_, MsBox.Avalonia.Enums.ButtonEnum.YesNo, MsBox.Avalonia.Enums.Icon.Question, _log) == MsBox.Avalonia.Enums.ButtonResult.Yes) { - animationFrames = _sprite.GetLipFlapAnimation(_window.OpenProject); + animationFrames = _sprite.GetLipFlapAnimation(_window.OpenProject!); } else { - animationFrames = _sprite.GetClosedMouthAnimation(_window.OpenProject); + animationFrames = _sprite.GetClosedMouthAnimation(_window.OpenProject!); } - IStorageFile saveFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Save_character_sprite_GIF, [new FilePickerFileType(Strings.GIF_file) { Patterns = ["*.gif"] }]); + IStorageFile? saveFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Save_character_sprite_GIF, [new FilePickerFileType(Strings.GIF_file) { Patterns = ["*.gif"] }]); if (saveFile is not null) { List frames = []; @@ -169,4 +169,4 @@ private async Task ExportGIF() tracker, Strings.Exporting_GIF___).ShowDialog(_window.Window); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/EditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/EditorViewModel.cs index 3d86576b..56bbe96e 100644 --- a/src/SerialLoops/ViewModels/Editors/EditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/EditorViewModel.cs @@ -7,16 +7,14 @@ namespace SerialLoops.ViewModels.Editors; -public class EditorViewModel(ItemDescription item, MainWindowViewModel window, ILogger log, Project project = null, EditorTabsPanelViewModel tabs = null, ItemExplorerPanelViewModel explorer = null) : ViewModelBase +public class EditorViewModel(ItemDescription item, MainWindowViewModel window, ILogger log, Project? project = null, EditorTabsPanelViewModel? tabs = null, ItemExplorerPanelViewModel? explorer = null) : ViewModelBase { protected MainWindowViewModel _window = window; protected ILogger _log = log; - protected Project _project = project; - protected EditorTabsPanelViewModel _tabs = tabs; - protected ItemExplorerPanelViewModel _explorer = explorer; + protected Project? _project = project; + protected EditorTabsPanelViewModel? _tabs = tabs; + protected ItemExplorerPanelViewModel? _explorer = explorer; public ItemDescription Description { get; set; } = item; - public List EditorCommands { get; } - - public string IconSource => $"avares://SerialLoops/Assets/Icons/{Description.Type.ToString().Replace(' ', '_')}.png"; -} \ No newline at end of file + public List EditorCommands { get; } = []; +} diff --git a/src/SerialLoops/ViewModels/Editors/GroupSelectionEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/GroupSelectionEditorViewModel.cs index 1931d5ec..2c218787 100644 --- a/src/SerialLoops/ViewModels/Editors/GroupSelectionEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/GroupSelectionEditorViewModel.cs @@ -22,9 +22,9 @@ public class GroupSelectionEditorViewModel : EditorViewModel public GroupSelectionEditorViewModel(GroupSelectionItem groupSelection, MainWindowViewModel window, ILogger log) : base(groupSelection, window, log) { - Tabs = window.EditorTabs; + Tabs = window.EditorTabs!; GroupSelection = groupSelection; - OpenProject = window.OpenProject; + OpenProject = window.OpenProject!; Activities = new(groupSelection.Selection.Activities.Select(a => new ScenarioActivityViewModel(this, a))); } @@ -40,10 +40,10 @@ public class ScenarioActivityViewModel(GroupSelectionEditorViewModel selection, private string _title = activity.Title; public string Title { - get => _title.GetSubstitutedString(selection.OpenProject); + get => _title.GetSubstitutedString(_selection.OpenProject); set { - this.RaiseAndSetIfChanged(ref _title, value.GetOriginalString(selection.OpenProject)); + this.RaiseAndSetIfChanged(ref _title, value.GetOriginalString(_selection.OpenProject)); Activity.Title = _title; // _selection.GroupSelection.UnsavedChanges = true; } @@ -52,7 +52,7 @@ public string Title private string _futureDesc = activity.FutureDesc; public string FutureDesc { - get => _futureDesc.GetSubstitutedString(selection.OpenProject); + get => _futureDesc.GetSubstitutedString(_selection.OpenProject); set { this.RaiseAndSetIfChanged(ref _futureDesc, value.GetOriginalString(_selection.OpenProject)); @@ -79,38 +79,36 @@ public string PastDesc public class ScenarioRouteViewModel(GroupSelectionEditorViewModel selection, ScenarioRoute route) : ViewModelBase { - private GroupSelectionEditorViewModel _selection = selection; - [Reactive] public ScenarioRoute Route { get; set; } = route; private string _title = route.Title; public string Title { - get => _title.GetSubstitutedString(_selection.OpenProject); + get => _title.GetSubstitutedString(selection.OpenProject); set { - this.RaiseAndSetIfChanged(ref _title, value.GetOriginalString(_selection.OpenProject)); + this.RaiseAndSetIfChanged(ref _title, value.GetOriginalString(selection.OpenProject)); Route.Title = _title; // _selection.GroupSelection.UnsavedChanges = true; } } public ObservableCollection KyonlessTopics { get; set; } = new(route.KyonlessTopics.Select(t => - (TopicItem)selection.OpenProject.Items.FirstOrDefault(i => - i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry.Id == t)) - .Where(t => t is not null)); + (TopicItem?)selection.OpenProject.Items.FirstOrDefault(i => + i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry?.Id == t)) + .Where(t => t is not null)!); - private ScriptItem _script = (ScriptItem)selection.OpenProject.Items.FirstOrDefault(i => - i.Type == ItemDescription.ItemType.Script && ((ScriptItem)i).Event.Index == route.ScriptIndex); - public ScriptItem Script + private ScriptItem? _script = (ScriptItem?)selection.OpenProject.Items.FirstOrDefault(i => + i.Type == ItemDescription.ItemType.Script && ((ScriptItem)i).Event!.Index == route.ScriptIndex); + public ScriptItem? Script { get => _script; set { this.RaiseAndSetIfChanged(ref _script, value); - Route.ScriptIndex = (short)_script.Event.Index; + Route.ScriptIndex = (short)(_script?.Event?.Index ?? 0); // selection.GroupSelection.UnsavedChanges = true; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/LoadSceneScenarioCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/LoadSceneScenarioCommandEditorViewModel.cs index 559c014f..88433511 100644 --- a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/LoadSceneScenarioCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/LoadSceneScenarioCommandEditorViewModel.cs @@ -19,7 +19,7 @@ public ScriptItem Scene set { this.RaiseAndSetIfChanged(ref _scene, value); - _parameter = _scene.Event.Index; + _parameter = _scene.Event!.Index; SelectedScenarioCommand.Parameter = _scene.DisplayName; SelectedScenarioCommand.Scenario.Scenario.Commands[SelectedScenarioCommand.CommandIndex].Parameter = _parameter; SelectedScenarioCommand.Scenario.UnsavedChanges = true; @@ -29,7 +29,7 @@ public ScriptItem Scene public LoadSceneScenarioCommandEditorViewModel(PrettyScenarioCommand command, Project project, EditorTabsPanelViewModel tabs) : base(command, tabs) { Scripts = new(project.Items.Where(i => i.Type == ItemDescription.ItemType.Script).Cast()); - _scene = Scripts.FirstOrDefault(s => s.DisplayName == command.Parameter); - _parameter = _scene.Event.Index; + _scene = Scripts.First(s => s.DisplayName == command.Parameter); + _parameter = _scene.Event!.Index; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/PuzzlePhaseScenarioCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/PuzzlePhaseScenarioCommandEditorViewModel.cs index 1794daa8..b483b0f7 100644 --- a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/PuzzlePhaseScenarioCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/PuzzlePhaseScenarioCommandEditorViewModel.cs @@ -29,7 +29,7 @@ public PuzzleItem Puzzle public PuzzlePhaseScenarioCommandEditorViewModel(PrettyScenarioCommand command, Project project, EditorTabsPanelViewModel tabs) : base(command, tabs) { Puzzles = new(project.Items.Where(i => i.Type == ItemDescription.ItemType.Puzzle).Cast()); - _puzzle = Puzzles.FirstOrDefault(s => s.DisplayName == command.Parameter); + _puzzle = Puzzles.First(s => s.DisplayName == command.Parameter); _parameter = _puzzle.Puzzle.Index; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/RouteSelectScenarioCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/RouteSelectScenarioCommandEditorViewModel.cs index 19bf0e24..21cadc3d 100644 --- a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/RouteSelectScenarioCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/RouteSelectScenarioCommandEditorViewModel.cs @@ -29,7 +29,7 @@ public GroupSelectionItem GroupSelection public RouteSelectScenarioCommandEditorViewModel(PrettyScenarioCommand command, Project project, EditorTabsPanelViewModel tabs) : base(command, tabs) { GroupSelections = new(project.Items.Where(i => i.Type == ItemDescription.ItemType.Group_Selection).Cast()); - _groupSelection = GroupSelections.FirstOrDefault(g => g.DisplayName == command.Parameter); + _groupSelection = GroupSelections.First(g => g.DisplayName == command.Parameter); _parameter = GroupSelections.IndexOf(_groupSelection); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/ScenarioCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/ScenarioCommandEditorViewModel.cs index 847541a2..cdcf10f0 100644 --- a/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/ScenarioCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScenarioCommandEditors/ScenarioCommandEditorViewModel.cs @@ -36,4 +36,4 @@ public ScenarioCommandEditorViewModel(PrettyScenarioCommand command, EditorTabsP } public short MaxValue => short.MaxValue; -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScenarioEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScenarioEditorViewModel.cs index 9c020f8f..c12e0ae6 100644 --- a/src/SerialLoops/ViewModels/Editors/ScenarioEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScenarioEditorViewModel.cs @@ -23,11 +23,11 @@ namespace SerialLoops.ViewModels.Editors; public class ScenarioEditorViewModel : EditorViewModel { private ScenarioItem _scenario; - private PrettyScenarioCommand _selectedCommand; + private PrettyScenarioCommand? _selectedCommand; public ObservableCollection Commands { get; set; } - public PrettyScenarioCommand SelectedCommand + public PrettyScenarioCommand? SelectedCommand { get => _selectedCommand; set @@ -44,7 +44,7 @@ public PrettyScenarioCommand SelectedCommand } } [Reactive] - public ScenarioCommandEditorViewModel CurrentCommandViewModel { get; set; } + public ScenarioCommandEditorViewModel? CurrentCommandViewModel { get; set; } public ICommand AddCommand { get; set; } public ICommand DeleteCommand { get; set; } @@ -65,15 +65,15 @@ public ScenarioEditorViewModel(ScenarioItem scenario, MainWindowViewModel window private async void Add() { - int selectedIndex = Math.Min(_scenario.Scenario.Commands.Count - 1, Commands.IndexOf(SelectedCommand)); - ScenarioVerb? newVerb = await new AddScenarioCommandDialog() { DataContext = new AddScenarioCommandDialogViewModel() }.ShowDialog(_window.Window); + int selectedIndex = Math.Min(_scenario.Scenario.Commands.Count - 1, SelectedCommand is null ? -1 : Commands.IndexOf(SelectedCommand)); + ScenarioVerb? newVerb = await new AddScenarioCommandDialog { DataContext = new AddScenarioCommandDialogViewModel() }.ShowDialog(_window.Window); if (newVerb is not null) { int param = newVerb switch { ScenarioVerb.NEW_GAME => 1, - ScenarioVerb.PUZZLE_PHASE => ((PuzzleItem)_window.OpenProject.Items.First(i => i.Type == ItemDescription.ItemType.Puzzle)).Puzzle.Index, - ScenarioVerb.LOAD_SCENE => ((ScriptItem)_window.OpenProject.Items.First(i => i.Type == ItemDescription.ItemType.Script)).Event.Index, + ScenarioVerb.PUZZLE_PHASE => ((PuzzleItem)_window.OpenProject!.Items.First(i => i.Type == ItemDescription.ItemType.Puzzle)).Puzzle.Index, + ScenarioVerb.LOAD_SCENE => ((ScriptItem)_window.OpenProject!.Items.First(i => i.Type == ItemDescription.ItemType.Script)).Event!.Index, _ => 0, }; ScenarioCommand newCommand = new(newVerb ?? ScenarioVerb.LOAD_SCENE, param); @@ -88,7 +88,7 @@ private async void Add() } private void Delete() { - int selectedIndex = Commands.IndexOf(SelectedCommand); + int selectedIndex = SelectedCommand is null ? -1 : Commands.IndexOf(SelectedCommand); if (selectedIndex < 0 || selectedIndex >= _scenario.Scenario.Commands.Count) { return; @@ -112,7 +112,7 @@ private async Task Clear() } private void Up() { - int selectedIndex = Commands.IndexOf(SelectedCommand); + int selectedIndex = SelectedCommand is null ? -1 : Commands.IndexOf(SelectedCommand); if (selectedIndex <= 0 || selectedIndex >= _scenario.Scenario.Commands.Count) { return; @@ -126,7 +126,7 @@ private void Up() } private void Down() { - int selectedIndex = Commands.IndexOf(SelectedCommand); + int selectedIndex = SelectedCommand is null ? -1 : Commands.IndexOf(SelectedCommand); if (selectedIndex < 0 || selectedIndex >= _scenario.Scenario.Commands.Count - 1) { return; @@ -138,14 +138,18 @@ private void Down() Description.UnsavedChanges = true; } - public ScenarioCommandEditorViewModel GetScenarioCommandEditor(PrettyScenarioCommand command) + public ScenarioCommandEditorViewModel? GetScenarioCommandEditor(PrettyScenarioCommand? command) { + if (command is null) + { + return null; + } return command.Verb switch { - ScenarioVerb.LOAD_SCENE => new LoadSceneScenarioCommandEditorViewModel(command, _window.OpenProject, _window.EditorTabs), - ScenarioVerb.PUZZLE_PHASE => new PuzzlePhaseScenarioCommandEditorViewModel(command, _window.OpenProject, _window.EditorTabs), - ScenarioVerb.ROUTE_SELECT => new RouteSelectScenarioCommandEditorViewModel(command, _window.OpenProject, _window.EditorTabs), - _ => new ScenarioCommandEditorViewModel(command, _window.EditorTabs), + ScenarioVerb.LOAD_SCENE => new LoadSceneScenarioCommandEditorViewModel(command, _window.OpenProject!, _window.EditorTabs!), + ScenarioVerb.PUZZLE_PHASE => new PuzzlePhaseScenarioCommandEditorViewModel(command, _window.OpenProject!, _window.EditorTabs!), + ScenarioVerb.ROUTE_SELECT => new RouteSelectScenarioCommandEditorViewModel(command, _window.OpenProject!, _window.EditorTabs!), + _ => new(command, _window.EditorTabs!), }; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgDispScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgDispScriptCommandEditorViewModel.cs index a0d8e7fa..e5cd869c 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgDispScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgDispScriptCommandEditorViewModel.cs @@ -17,16 +17,20 @@ public class BgDispScriptCommandEditorViewModel : ScriptCommandEditorViewModel private MainWindowViewModel _window; public EditorTabsPanelViewModel Tabs { get; } - private BackgroundItem _bg; - public BackgroundItem Bg + private BackgroundItem? _bg; + public BackgroundItem? Bg { get => _bg; set { + if (value is null) + { + return; + } this.RaiseAndSetIfChanged(ref _bg, value); ((BgScriptParameter)Command.Parameters[0]).Background = _bg; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] - .Objects[Command.Index].Parameters[0] = (short)_bg.Id; + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + .Objects[Command.Index].Parameters[0] = (short)_bg!.Id; ScriptEditor.UpdatePreview(); Script.UnsavedChanges = true; } @@ -37,27 +41,26 @@ public BackgroundItem Bg public BgDispScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEditorViewModel scriptEditor, MainWindowViewModel window) : base(command, scriptEditor) { _window = window; - Tabs = _window.EditorTabs; + Tabs = _window.EditorTabs!; _bg = ((BgScriptParameter)Command.Parameters[0]).Background; ReplaceBgCommand = ReactiveCommand.CreateFromTask(ReplaceBg); } private async Task ReplaceBg() { - GraphicSelectionDialogViewModel graphicSelectionDialog = new(new List() { NonePreviewableGraphic.BACKGROUND }.Concat(_window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Background).Cast()), + GraphicSelectionDialogViewModel graphicSelectionDialog = new(new List() { NonePreviewableGraphic.BACKGROUND }.Concat(_window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Background).Cast()), Bg, _window.OpenProject, _window.Log, i => i.Name == "NONE" || ((BackgroundItem)i).BackgroundType == HaruhiChokuretsuLib.Archive.Data.BgType.TEX_BG); - IPreviewableGraphic bg = await new GraphicSelectionDialog() { DataContext = graphicSelectionDialog }.ShowDialog(_window.Window); - if (bg is null) + IPreviewableGraphic? bg = await new GraphicSelectionDialog() { DataContext = graphicSelectionDialog }.ShowDialog(_window.Window); + if (bg is not null) { - return; - } - else if (bg.Text == "NONE") - { - Bg = null; - } - else - { - Bg = (BackgroundItem)bg; + if (bg.Text == "NONE") + { + Bg = null; + } + else + { + Bg = (BackgroundItem)bg; + } } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgmPlayScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgmPlayScriptCommandEditorViewModel.cs index 91647fee..68b66268 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgmPlayScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/BgmPlayScriptCommandEditorViewModel.cs @@ -24,7 +24,7 @@ public BackgroundMusicItem Music { this.RaiseAndSetIfChanged(ref _music, value); ((BgmScriptParameter)Command.Parameters[0]).Bgm = _music; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = (short)_music.Index; Script.UnsavedChanges = true; } @@ -39,7 +39,7 @@ public string Mode { this.RaiseAndSetIfChanged(ref _mode, Enum.Parse(value)); ((BgmModeScriptParameter)Command.Parameters[1]).Mode = _mode; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = (short)_mode; Script.UnsavedChanges = true; } @@ -53,7 +53,7 @@ public short Volume { this.RaiseAndSetIfChanged(ref _volume, value); ((ShortScriptParameter)Command.Parameters[2]).Value = _volume; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[2] = _volume; Script.UnsavedChanges = true; } @@ -67,7 +67,7 @@ public short FadeInTime { this.RaiseAndSetIfChanged(ref _fadeInTime, value); ((ShortScriptParameter)Command.Parameters[3]).Value = _fadeInTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[3] = _fadeInTime; Script.UnsavedChanges = true; } @@ -81,7 +81,7 @@ public short FadeOutTime { this.RaiseAndSetIfChanged(ref _fadeOutTime, value); ((ShortScriptParameter)Command.Parameters[4]).Value = _fadeOutTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[4] = _fadeOutTime; } } @@ -89,8 +89,8 @@ public short FadeOutTime public BgmPlayScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEditorViewModel scriptEditor, MainWindowViewModel window) : base(command, scriptEditor) { - Tabs = window.EditorTabs; - Bgms = new(window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.BGM) + Tabs = window.EditorTabs!; + Bgms = new(window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.BGM) .Cast()); _music = ((BgmScriptParameter)Command.Parameters[0]).Bgm; _mode = ((BgmModeScriptParameter)Command.Parameters[1]).Mode; @@ -98,4 +98,4 @@ public BgmPlayScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEdit _fadeInTime = ((ShortScriptParameter)Command.Parameters[3]).Value; _fadeOutTime = ((ShortScriptParameter)Command.Parameters[4]).Value; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/DialogueScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/DialogueScriptCommandEditorViewModel.cs index f897f8b1..89f7d912 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/DialogueScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/DialogueScriptCommandEditorViewModel.cs @@ -24,8 +24,8 @@ public partial class DialogueScriptCommandEditorViewModel : ScriptCommandEditorV public DialogueScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEditorViewModel scriptEditor, MainWindowViewModel window) : base(command, scriptEditor) { _window = window; - Tabs = _window.EditorTabs; - Characters = new(_window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Character).Cast()); + Tabs = _window.EditorTabs!; + Characters = new(_window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Character).Cast()); _speaker = _window.OpenProject.GetCharacterBySpeaker(((DialogueScriptParameter)Command.Parameters[0]).Line.Speaker); _specialPredicate = i => i.Name != "NONE" && ((CharacterSpriteItem)i).Sprite.Character == _speaker.MessageInfo.Character; _dialogueLine = ((DialogueScriptParameter)command.Parameters[0]).Line.Text; @@ -64,17 +64,17 @@ public CharacterItem Speaker } this.RaiseAndSetIfChanged(ref _speaker, value); ((DialogueScriptParameter)Command.Parameters[0]).Line.Speaker = _speaker.MessageInfo.Character; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Speaker = _speaker.MessageInfo.Character; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Speaker = _speaker.MessageInfo.Character; _specialPredicate = i => i.Name != "NONE" && ((CharacterSpriteItem)i).Sprite.Character == _speaker.MessageInfo.Character; Script.UnsavedChanges = true; ScriptEditor.UpdatePreview(); } } - private string _dialogueLine; - public string DialogueLine + private string? _dialogueLine; + public string? DialogueLine { - get => _dialogueLine.GetSubstitutedString(_window.OpenProject); + get => _dialogueLine?.GetSubstitutedString(_window.OpenProject!); set { if (value is null) @@ -84,12 +84,12 @@ public string DialogueLine text = MidStringOpenQuotes().Replace(text, "$1“"); text = text.Replace('"', '”'); - this.RaiseAndSetIfChanged(ref _dialogueLine, text.GetOriginalString(_window.OpenProject)); + this.RaiseAndSetIfChanged(ref _dialogueLine, text.GetOriginalString(_window.OpenProject!)); if (string.IsNullOrEmpty(_dialogueLine)) { ((DialogueScriptParameter)Command.Parameters[0]).Line.Text = ""; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Text = ""; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Text = ""; ((DialogueScriptParameter)Command.Parameters[0]).Line.Pointer = 0; Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Pointer = 0; } @@ -100,10 +100,10 @@ public string DialogueLine // It doesn't matter what we set this to as long as it's greater than zero // The ASM creation routine only checks that the pointer is not zero ((DialogueScriptParameter)Command.Parameters[0]).Line.Pointer = 1; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Pointer = 1; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Pointer = 1; } ((DialogueScriptParameter)Command.Parameters[0]).Line.Text = _dialogueLine; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Text = _dialogueLine; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Text = _dialogueLine; } ScriptEditor.UpdatePreview(); @@ -112,8 +112,8 @@ public string DialogueLine } } - private CharacterSpriteItem _characterSprite; - public CharacterSpriteItem CharacterSprite + private CharacterSpriteItem? _characterSprite; + public CharacterSpriteItem? CharacterSprite { get => _characterSprite; set @@ -122,13 +122,13 @@ public CharacterSpriteItem CharacterSprite if (_characterSprite is null) { ((SpriteScriptParameter)Command.Parameters[1]).Sprite = null; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = 0; } else { ((SpriteScriptParameter)Command.Parameters[1]).Sprite = _characterSprite; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = (short)(_characterSprite.Index); } ScriptEditor.UpdatePreview(); @@ -139,9 +139,9 @@ public CharacterSpriteItem CharacterSprite private async Task SelectCharacterSpriteCommand_Executed() { - GraphicSelectionDialogViewModel graphicSelectionDialog = new(_window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Character_Sprite).Cast(), + GraphicSelectionDialogViewModel graphicSelectionDialog = new(_window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Character_Sprite).Cast(), CharacterSprite, _window.OpenProject, _window.Log, _specialPredicate); - CharacterSpriteItem sprite = await new GraphicSelectionDialog() { DataContext = graphicSelectionDialog }.ShowDialog(_window.Window); + CharacterSpriteItem? sprite = await new GraphicSelectionDialog() { DataContext = graphicSelectionDialog }.ShowDialog(_window.Window); if (sprite is not null) { CharacterSprite = sprite; @@ -157,7 +157,7 @@ public string SpriteEntranceTransition { this.RaiseAndSetIfChanged(ref _spriteEntranceTransition, Enum.Parse(value)); ((SpriteEntranceScriptParameter)Command.Parameters[2]).EntranceTransition = _spriteEntranceTransition; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[2] = (short)_spriteEntranceTransition; ScriptEditor.UpdatePreview(); Script.UnsavedChanges = true; @@ -173,7 +173,7 @@ public string SpriteExitTransition { this.RaiseAndSetIfChanged(ref _spriteExitTransition, Enum.Parse(value)); ((SpriteExitScriptParameter)Command.Parameters[3]).ExitTransition = _spriteExitTransition; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[3] = (short)_spriteExitTransition; Script.UnsavedChanges = true; } @@ -188,7 +188,7 @@ public string SpriteShakeEffect { this.RaiseAndSetIfChanged(ref _spriteShakeEffect, Enum.Parse(value)); ((SpriteShakeScriptParameter)Command.Parameters[4]).ShakeEffect = _spriteShakeEffect; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[4] = (short)_spriteShakeEffect; Script.UnsavedChanges = true; } @@ -203,7 +203,7 @@ public VoicedLineItem VoicedLine { this.RaiseAndSetIfChanged(ref _voicedLine, value); ((VoicedLineScriptParameter)Command.Parameters[5]).VoiceLine = _voicedLine; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[5] = (short)_voicedLine.Index; Script.UnsavedChanges = true; } @@ -217,7 +217,7 @@ public CharacterItem TextVoiceFont { this.RaiseAndSetIfChanged(ref _textVoiceFont, value); ((DialoguePropertyScriptParameter)Command.Parameters[6]).Character = _textVoiceFont; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[6] = (short)_textVoiceFont.MessageInfo.Character; Script.UnsavedChanges = true; } @@ -231,7 +231,7 @@ public CharacterItem TextSpeed { this.RaiseAndSetIfChanged(ref _textSpeed, value); ((DialoguePropertyScriptParameter)Command.Parameters[7]).Character = _textSpeed; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[7] = (short)_textSpeed.MessageInfo.Character; Script.UnsavedChanges = true; } @@ -246,7 +246,7 @@ public string TextEntranceEffect { this.RaiseAndSetIfChanged(ref _textEntranceEffect, Enum.Parse(value)); ((TextEntranceEffectScriptParameter)Command.Parameters[8]).EntranceEffect = _textEntranceEffect; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[8] = (short)_textEntranceEffect; Script.UnsavedChanges = true; } @@ -260,7 +260,7 @@ public short SpriteLayer { this.RaiseAndSetIfChanged(ref _spriteLayer, value); ((ShortScriptParameter)Command.Parameters[9]).Value = _spriteLayer; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[9] = _spriteLayer; ScriptEditor.UpdatePreview(); Script.UnsavedChanges = true; @@ -275,7 +275,7 @@ public bool DontClearText { this.RaiseAndSetIfChanged(ref _dontClearText, value); ((BoolScriptParameter)Command.Parameters[10]).Value = _dontClearText; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[10] = _dontClearText ? ((BoolScriptParameter)Command.Parameters[10]).TrueValue : ((BoolScriptParameter)Command.Parameters[10]).FalseValue; Script.UnsavedChanges = true; } @@ -289,7 +289,7 @@ public bool DisableLipFlap { this.RaiseAndSetIfChanged(ref _disableLipFlap, value); ((BoolScriptParameter)Command.Parameters[11]).Value = _disableLipFlap; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[11] = _disableLipFlap ? ((BoolScriptParameter)Command.Parameters[11]).TrueValue : ((BoolScriptParameter)Command.Parameters[11]).FalseValue; Script.UnsavedChanges = true; } @@ -299,4 +299,4 @@ public bool DisableLipFlap private static partial Regex StartStringQuotes(); [GeneratedRegex(@"(\s)""")] private static partial Regex MidStringOpenQuotes(); -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/FlagScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/FlagScriptCommandEditorViewModel.cs index 37901e7a..ed0d4a9e 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/FlagScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/FlagScriptCommandEditorViewModel.cs @@ -21,7 +21,7 @@ public string Flag } this.RaiseAndSetIfChanged(ref _flagId, flag); ((FlagScriptParameter)Command.Parameters[0]).Id = _flagId; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _flagId; Script.UnsavedChanges = true; } @@ -36,7 +36,7 @@ public bool SetClear { this.RaiseAndSetIfChanged(ref _setClear, value); ((BoolScriptParameter)Command.Parameters[1]).Value = _setClear; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = _setClear ? ((BoolScriptParameter)Command.Parameters[1]).TrueValue : ((BoolScriptParameter)Command.Parameters[1]).FalseValue; diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/KbgDispScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/KbgDispScriptCommandEditorViewModel.cs index bb57f3b0..2b61d9aa 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/KbgDispScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/KbgDispScriptCommandEditorViewModel.cs @@ -19,8 +19,8 @@ public class KbgDispScriptCommandEditorViewModel : ScriptCommandEditorViewModel private MainWindowViewModel _window; public EditorTabsPanelViewModel Tabs { get; } - private BackgroundItem _kbg; - public BackgroundItem Kbg + private BackgroundItem? _kbg; + public BackgroundItem? Kbg { get => _kbg; set @@ -29,13 +29,13 @@ public BackgroundItem Kbg if (_kbg is null) { ((BgScriptParameter)Command.Parameters[0]).Background = null; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = 0; } else { ((BgScriptParameter)Command.Parameters[0]).Background = _kbg; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = (short)_kbg.Id; } } @@ -46,15 +46,15 @@ public KbgDispScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEdit _kbg = ((BgScriptParameter)command.Parameters[0]).Background; ReplaceKbgCommand = ReactiveCommand.CreateFromTask(ReplaceKbg); _window = window; - Tabs = _window.EditorTabs; + Tabs = _window.EditorTabs!; } private async Task ReplaceKbg() { // Order of the predicate matters here as "NONE" short circuits the NonePreviewableGraphic, preventing it from being cast - GraphicSelectionDialogViewModel graphicSelectionDialog = new(new List() { NonePreviewableGraphic.BACKGROUND }.Concat(_window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Background).Cast()), + GraphicSelectionDialogViewModel graphicSelectionDialog = new(new List() { NonePreviewableGraphic.BACKGROUND }.Concat(_window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Background).Cast()), Kbg, _window.OpenProject, _window.Log, i => i.Name == "NONE" || ((BackgroundItem)i).BackgroundType == BgType.KINETIC_SCREEN); - IPreviewableGraphic bgItem = await new GraphicSelectionDialog() { DataContext = graphicSelectionDialog }.ShowDialog(_window.Window); + IPreviewableGraphic? bgItem = await new GraphicSelectionDialog() { DataContext = graphicSelectionDialog }.ShowDialog(_window.Window); if (bgItem is null || bgItem == Kbg) { return; @@ -70,4 +70,4 @@ private async Task ReplaceKbg() ScriptEditor.UpdatePreview(); Script.UnsavedChanges = true; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/PinMnlScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/PinMnlScriptCommandEditorViewModel.cs index fef2d914..6e1e04d7 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/PinMnlScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/PinMnlScriptCommandEditorViewModel.cs @@ -26,7 +26,7 @@ public CharacterItem Speaker this.RaiseAndSetIfChanged(ref _speaker, value); ((DialogueScriptParameter)Command.Parameters[0]).Line.Speaker = _speaker.MessageInfo.Character; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Speaker = _speaker.MessageInfo.Character; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Speaker = _speaker.MessageInfo.Character; ScriptEditor.UpdatePreview(); Script.UnsavedChanges = true; } @@ -48,7 +48,7 @@ public string DialogueLine if (string.IsNullOrEmpty(_dialogueLine)) { ((DialogueScriptParameter)Command.Parameters[0]).Line.Text = ""; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Text = ""; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Text = ""; ((DialogueScriptParameter)Command.Parameters[0]).Line.Pointer = 0; Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Pointer = 0; } @@ -59,10 +59,10 @@ public string DialogueLine // It doesn't matter what we set this to as long as it's greater than zero // The ASM creation routine only checks that the pointer is not zero ((DialogueScriptParameter)Command.Parameters[0]).Line.Pointer = 1; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Pointer = 1; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Pointer = 1; } ((DialogueScriptParameter)Command.Parameters[0]).Line.Text = _dialogueLine; - Script.Event.DialogueSection.Objects[Command.Section.Objects[Command.Index].Parameters[0]].Text = _dialogueLine; + Script.Event!.DialogueSection.Objects[Command.Section!.Objects[Command.Index].Parameters[0]].Text = _dialogueLine; } ScriptEditor.UpdatePreview(); @@ -74,4 +74,4 @@ public string DialogueLine private static partial Regex StartStringQuotes(); [GeneratedRegex(@"(\s)""")] private static partial Regex MidStringOpenQuotes(); -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeInScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeInScriptCommandEditorViewModel.cs index 5bd1f5de..05a52856 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeInScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeInScriptCommandEditorViewModel.cs @@ -18,7 +18,7 @@ public short FadeTime { this.RaiseAndSetIfChanged(ref _fadeTime, value); ((ShortScriptParameter)Command.Parameters[0]).Value = _fadeTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _fadeTime; Script.UnsavedChanges = true; } @@ -32,7 +32,7 @@ public short FadePercentage { this.RaiseAndSetIfChanged(ref _fadePercentage, value); ((ShortScriptParameter)Command.Parameters[1]).Value = _fadePercentage; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = _fadePercentage; Script.UnsavedChanges = true; } @@ -50,7 +50,7 @@ public string Color { this.RaiseAndSetIfChanged(ref _color, Enum.Parse(value)); ((ColorMonochromeScriptParameter)Command.Parameters[3]).ColorType = _color; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[3] = (short)_color; Script.UnsavedChanges = true; } @@ -64,10 +64,10 @@ public ScreenFadeInScriptCommandEditorViewModel(ScriptItemCommand command, Scrip ScreenSelector.ScreenChanged += (sender, args) => { ((ScreenScriptParameter)Command.Parameters[2]).Screen = ScreenSelector.SelectedScreen; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[2] = (short)ScreenSelector.SelectedScreen; Script.UnsavedChanges = true; }; _color = ((ColorMonochromeScriptParameter)command.Parameters[3]).ColorType; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeOutScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeOutScriptCommandEditorViewModel.cs index 549c8f32..4fc34af6 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeOutScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFadeOutScriptCommandEditorViewModel.cs @@ -19,7 +19,7 @@ public short FadeTime { this.RaiseAndSetIfChanged(ref _fadeTime, value); ((ShortScriptParameter)Command.Parameters[0]).Value = _fadeTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _fadeTime; Script.UnsavedChanges = true; } @@ -33,7 +33,7 @@ public short FadePercentage { this.RaiseAndSetIfChanged(ref _fadePercentage, value); ((ShortScriptParameter)Command.Parameters[1]).Value = _fadePercentage; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = _fadePercentage; Script.UnsavedChanges = true; } @@ -47,7 +47,7 @@ public SKColor CustomColor { this.RaiseAndSetIfChanged(ref _customColor, value); ((ColorScriptParameter)Command.Parameters[2]).Color = _customColor; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[2] = _customColor.Red; Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[3] = _customColor.Green; @@ -69,7 +69,7 @@ public string Color { this.RaiseAndSetIfChanged(ref _color, Enum.Parse(value)); ((ColorMonochromeScriptParameter)Command.Parameters[4]).ColorType = _color; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[6] = (short)_color; Script.UnsavedChanges = true; } @@ -84,10 +84,10 @@ public ScreenFadeOutScriptCommandEditorViewModel(ScriptItemCommand command, Scri ScreenSelector.ScreenChanged += (sender, args) => { ((ScreenScriptParameter)Command.Parameters[3]).Screen = ScreenSelector.SelectedScreen; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[5] = (short)ScreenSelector.SelectedScreen; Script.UnsavedChanges = true; }; _color = ((ColorMonochromeScriptParameter)Command.Parameters[4]).ColorType; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFlashScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFlashScriptCommandEditorViewModel.cs index 26be8461..79c2285a 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFlashScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ScreenFlashScriptCommandEditorViewModel.cs @@ -15,7 +15,7 @@ public short FadeInTime { this.RaiseAndSetIfChanged(ref _fadeInTime, value); ((ShortScriptParameter)Command.Parameters[0]).Value = _fadeInTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _fadeInTime; Script.UnsavedChanges = true; } @@ -29,7 +29,7 @@ public short HoldTime { this.RaiseAndSetIfChanged(ref _holdTime, value); ((ShortScriptParameter)Command.Parameters[1]).Value = _holdTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = _holdTime; Script.UnsavedChanges = true; } @@ -43,7 +43,7 @@ public short FadeOutTime { this.RaiseAndSetIfChanged(ref _fadeOutTime, value); ((ShortScriptParameter)Command.Parameters[2]).Value = _fadeOutTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[2] = _fadeOutTime; Script.UnsavedChanges = true; } @@ -57,7 +57,7 @@ public SKColor Color { this.RaiseAndSetIfChanged(ref _color, value); ((ColorScriptParameter)Command.Parameters[3]).Color = _color; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[3] = _color.Red; Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[4] = _color.Green; @@ -66,4 +66,4 @@ public SKColor Color Script.UnsavedChanges = true; } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/SndPlayScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/SndPlayScriptCommandEditorViewModel.cs index 6d73da46..85cae708 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/SndPlayScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/SndPlayScriptCommandEditorViewModel.cs @@ -24,7 +24,7 @@ public SfxItem SelectedSfx { this.RaiseAndSetIfChanged(ref _selectedSfx, value); ((SfxScriptParameter)Command.Parameters[0]).Sfx = _selectedSfx; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _selectedSfx.Index; Script.UnsavedChanges = true; } @@ -39,7 +39,7 @@ public string SfxMode { this.RaiseAndSetIfChanged(ref _sfxMode, Enum.Parse(value)); ((SfxModeScriptParameter)Command.Parameters[1]).Mode = _sfxMode; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[1] = (short)_sfxMode; Script.UnsavedChanges = true; } @@ -53,7 +53,7 @@ public short Volume { this.RaiseAndSetIfChanged(ref _volume, value); ((ShortScriptParameter)Command.Parameters[2]).Value = _volume; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[2] = _volume; Script.UnsavedChanges = true; } @@ -69,7 +69,7 @@ public bool LoadSound if (_loadSound) { ((BoolScriptParameter)Command.Parameters[3]).Value = true; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[3] = ((BoolScriptParameter)Command.Parameters[3]).TrueValue; CrossfadeMin = -1; CrossfadeMax = -1; @@ -99,7 +99,7 @@ public short CrossfadeTime { this.RaiseAndSetIfChanged(ref _crossfadeTime, value); ((ShortScriptParameter)Command.Parameters[4]).Value = _crossfadeTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[4] = _crossfadeTime; Script.UnsavedChanges = true; } @@ -108,12 +108,12 @@ public short CrossfadeTime public SndPlayScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEditorViewModel scriptEditor, MainWindowViewModel window) : base(command, scriptEditor) { - Tabs = window.EditorTabs; - SfxChoices = new(window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.SFX && ((SfxItem)i).AssociatedGroups.Contains(window.OpenProject.Snd.Groups[Script.SfxGroupIndex].Name)).Cast()); + Tabs = window.EditorTabs!; + SfxChoices = new(window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.SFX && ((SfxItem)i).AssociatedGroups.Contains(window.OpenProject.Snd!.Groups[Script.SfxGroupIndex].Name)).Cast()); _selectedSfx = ((SfxScriptParameter)Command.Parameters[0]).Sfx; _sfxMode = ((SfxModeScriptParameter)Command.Parameters[1]).Mode; _volume = ((ShortScriptParameter)Command.Parameters[2]).Value; _crossfadeTime = ((ShortScriptParameter)Command.Parameters[4]).Value; _loadSound = ((BoolScriptParameter)Command.Parameters[3]).Value && _crossfadeTime < 0; } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ToggleDialogueScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ToggleDialogueScriptCommandEditorViewModel.cs index 877141f9..26033175 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ToggleDialogueScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/ToggleDialogueScriptCommandEditorViewModel.cs @@ -14,7 +14,7 @@ public bool DialogueVisible { this.RaiseAndSetIfChanged(ref _dialogueVisible, value); ((BoolScriptParameter)Command.Parameters[0]).Value = _dialogueVisible; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _dialogueVisible ? ((BoolScriptParameter)Command.Parameters[0]).TrueValue : ((BoolScriptParameter)Command.Parameters[0]).FalseValue; diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorViewModel.cs index 306f29ca..f2c9c7b5 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorViewModel.cs @@ -25,23 +25,23 @@ public TopicItem SelectedTopic set { this.RaiseAndSetIfChanged(ref _selectedTopic, value); - ((TopicScriptParameter)Command.Parameters[0]).TopicId = _selectedTopic.TopicEntry.Id; + ((TopicScriptParameter)Command.Parameters[0]).TopicId = _selectedTopic.TopicEntry!.Id; TopicId = _selectedTopic.TopicEntry.Id; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _selectedTopic.TopicEntry.Id; Script.UnsavedChanges = true; } } - public ICommand SelectTopicCommand { get; } + public ICommand ReassignTopicCommand { get; } public TopicGetScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEditorViewModel scriptEditor, MainWindowViewModel window) : base(command, scriptEditor) { - Tabs = window.EditorTabs; - Topics = new(window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Topic).Cast()); + Tabs = window.EditorTabs!; + Topics = new(window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Topic).Cast()); TopicId = ((TopicScriptParameter)Command.Parameters[0]).TopicId; - _selectedTopic = (TopicItem)window.OpenProject.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry.Id == TopicId); - SelectTopicCommand = ReactiveCommand.Create(() => SelectedTopic = Topics.FirstOrDefault()); + _selectedTopic = (TopicItem)window.OpenProject.Items.First(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry!.Id == TopicId); + ReassignTopicCommand = ReactiveCommand.Create(() => SelectedTopic = Topics.First()); } } diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/VcePlayScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/VcePlayScriptCommandEditorViewModel.cs index a699736e..27de7770 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/VcePlayScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/VcePlayScriptCommandEditorViewModel.cs @@ -21,7 +21,7 @@ public VoicedLineItem Vce { this.RaiseAndSetIfChanged(ref _vce, value); ((VoicedLineScriptParameter)Command.Parameters[0]).VoiceLine = _vce; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = (short)_vce.Index; Script.UnsavedChanges = true; } @@ -30,8 +30,8 @@ public VoicedLineItem Vce public VcePlayScriptCommandEditorViewModel(ScriptItemCommand command, ScriptEditorViewModel scriptEditor, MainWindowViewModel window) : base(command, scriptEditor) { - Tabs = window.EditorTabs; - Vces = new(window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Voice).Cast()); + Tabs = window.EditorTabs!; + Vces = new(window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Voice).Cast()); _vce = ((VoicedLineScriptParameter)Command.Parameters[0]).VoiceLine; } } diff --git a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/WaitScriptCommandEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/WaitScriptCommandEditorViewModel.cs index 57e08e24..ebcbf0ec 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/WaitScriptCommandEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptCommandEditors/WaitScriptCommandEditorViewModel.cs @@ -14,10 +14,10 @@ public short WaitTime { this.RaiseAndSetIfChanged(ref _waitTime, value); ((ShortScriptParameter)Command.Parameters[0]).Value = _waitTime; - Script.Event.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] + Script.Event!.ScriptSections[Script.Event.ScriptSections.IndexOf(Command.Section)] .Objects[Command.Index].Parameters[0] = _waitTime; Script.UnsavedChanges = true; Command.UpdateDisplay(); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/ScriptEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/ScriptEditorViewModel.cs index 27b2552a..cdf9a0d5 100644 --- a/src/SerialLoops/ViewModels/Editors/ScriptEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/ScriptEditorViewModel.cs @@ -24,7 +24,7 @@ namespace SerialLoops.ViewModels.Editors; public class ScriptEditorViewModel : EditorViewModel { private ScriptItem _script; - private ScriptItemCommand _selectedCommand; + private ScriptItemCommand? _selectedCommand; private Dictionary> _commands = []; public ICommand SelectedCommandChangedCommand { get; } @@ -33,7 +33,7 @@ public class ScriptEditorViewModel : EditorViewModel public ICommand DeleteScriptCommandOrSectionCommand { get; } public ICommand ClearScriptCommand { get; } - public ScriptItemCommand SelectedCommand + public ScriptItemCommand? SelectedCommand { get => _selectedCommand; set @@ -44,12 +44,12 @@ public ScriptItemCommand SelectedCommand } } [Reactive] - public ScriptSection SelectedSection { get; set; } + public ScriptSection? SelectedSection { get; set; } [Reactive] - public SKBitmap PreviewBitmap { get; set; } + public SKBitmap? PreviewBitmap { get; set; } [Reactive] - public ScriptCommandEditorViewModel CurrentCommandViewModel { get; set; } + public ScriptCommandEditorViewModel? CurrentCommandViewModel { get; set; } public Dictionary> Commands { @@ -70,14 +70,14 @@ public Dictionary> Commands ) } }; - Source.RowSelection.SingleSelect = true; + Source.RowSelection!.SingleSelect = true; Source.RowSelection.SelectionChanged += RowSelection_SelectionChanged; Source.ExpandAll(); } } [Reactive] - public HierarchicalTreeDataGridSource Source { get; private set; } + public HierarchicalTreeDataGridSource? Source { get; private set; } public ScriptEditorViewModel(ScriptItem script, MainWindowViewModel window, ILogger log) : base(script, window, log) { @@ -85,15 +85,20 @@ public ScriptEditorViewModel(ScriptItem script, MainWindowViewModel window, ILog _project = window.OpenProject; PopulateScriptCommands(); _script.CalculateGraphEdges(_commands, _log); + SelectedCommandChangedCommand = ReactiveCommand.Create(SelectedCommandChanged); + AddScriptCommandCommand = ReactiveCommand.Create(AddScriptCommand); + AddScriptSectionCommand = ReactiveCommand.Create(AddScriptSection); + DeleteScriptCommandOrSectionCommand = ReactiveCommand.Create(Delete); + ClearScriptCommand = ReactiveCommand.Create(Clear); } public void PopulateScriptCommands(bool refresh = false) { if (refresh) { - _script.Refresh(_project, _log); + _script.Refresh(_project!, _log); } - Commands = _script.GetScriptCommandTree(_project, _log); + Commands = _script.GetScriptCommandTree(_project!, _log) ?? []; } private void UpdateCommandViewModel() @@ -109,7 +114,7 @@ private void UpdateCommandViewModel() CommandVerb.INIT_READ_FLAG => new EmptyScriptCommandEditorViewModel(_selectedCommand, this), CommandVerb.DIALOGUE => new DialogueScriptCommandEditorViewModel(_selectedCommand, this, _window), CommandVerb.KBG_DISP => new KbgDispScriptCommandEditorViewModel(_selectedCommand, this, _window), - CommandVerb.PIN_MNL => new PinMnlScriptCommandEditorViewModel(_selectedCommand, this, _window.OpenProject), + CommandVerb.PIN_MNL => new PinMnlScriptCommandEditorViewModel(_selectedCommand, this, _window.OpenProject!), CommandVerb.BG_DISP => new BgDispScriptCommandEditorViewModel(_selectedCommand, this, _window), CommandVerb.SCREEN_FADEIN => new ScreenFadeInScriptCommandEditorViewModel(_selectedCommand, this), CommandVerb.SCREEN_FADEOUT => new ScreenFadeOutScriptCommandEditorViewModel(_selectedCommand, this), @@ -132,7 +137,7 @@ private void UpdateCommandViewModel() CommandVerb.NEXT_SCENE => new EmptyScriptCommandEditorViewModel(_selectedCommand, this), CommandVerb.AVOID_DISP => new EmptyScriptCommandEditorViewModel(_selectedCommand, this), CommandVerb.BG_DISP2 => new BgDispScriptCommandEditorViewModel(_selectedCommand, this, _window), - _ => new ScriptCommandEditorViewModel(_selectedCommand, this) + _ => new(_selectedCommand, this) }; } } @@ -147,13 +152,13 @@ public void UpdatePreview() } else { - (SKBitmap previewBitmap, string errorImage) = _script.GeneratePreviewImage(_commands, SelectedCommand, _project, _log); + (SKBitmap? previewBitmap, string? errorImage) = _script.GeneratePreviewImage(_commands, SelectedCommand, _project!, _log); if (previewBitmap is null) { previewBitmap = new(256, 384); SKCanvas canvas = new(previewBitmap); canvas.DrawColor(SKColors.Black); - using Stream noPreviewStream = Assembly.GetCallingAssembly().GetManifestResourceStream(errorImage); + using Stream noPreviewStream = Assembly.GetCallingAssembly().GetManifestResourceStream(errorImage ?? "")!; canvas.DrawImage(SKImage.FromEncodedData(noPreviewStream), new SKPoint(0, 0)); canvas.Flush(); } @@ -166,7 +171,7 @@ public void UpdatePreview() } } - private void RowSelection_SelectionChanged(object sender, TreeSelectionModelSelectionChangedEventArgs e) + private void RowSelection_SelectionChanged(object? sender, TreeSelectionModelSelectionChangedEventArgs e) { if (e.SelectedIndexes.Count == 0 || e.SelectedIndexes[0].Count == 0) { @@ -184,4 +189,29 @@ private void RowSelection_SelectionChanged(object sender, TreeSelectionModelSele SelectedSection = Commands.Keys.ElementAt(e.SelectedIndexes[0][0]); } } + + private void SelectedCommandChanged() + { + + } + + private void AddScriptCommand() + { + + } + + private void AddScriptSection() + { + + } + + private void Delete() + { + + } + + private void Clear() + { + + } } diff --git a/src/SerialLoops/ViewModels/Editors/SfxEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/SfxEditorViewModel.cs index 5d99efd6..95ad70d1 100644 --- a/src/SerialLoops/ViewModels/Editors/SfxEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/SfxEditorViewModel.cs @@ -31,7 +31,7 @@ public class SfxEditorViewModel : EditorViewModel public SfxEditorViewModel(ItemDescription item, MainWindowViewModel window, ILogger log) : base(item, window, log, window.OpenProject) { Sfx = (SfxItem)Description; - _archive = _project.Snd.SequenceArchives[Sfx.Entry.SequenceArchive].File; + _archive = _project!.Snd!.SequenceArchives[Sfx.Entry.SequenceArchive].File; _sequence = _archive.Sequences[Sfx.Entry.Index]; _player = new(new(window.SfxMixer.Player)); @@ -46,10 +46,10 @@ public SfxEditorViewModel(ItemDescription item, MainWindowViewModel window, ILog private async Task Extract() { _player.Stop(); - IStorageFile wavFile = await GuiExtensions.ShowSaveFilePickerAsync(_window.Window, Strings.Export_SFX, [new(Strings.WAV_File) { Patterns = ["*.wav"] }], $"{Sfx.DisplayName}.wav"); + IStorageFile? wavFile = await GuiExtensions.ShowSaveFilePickerAsync(_window.Window, Strings.Export_SFX, [new(Strings.WAV_File) { Patterns = ["*.wav"] }], $"{Sfx.DisplayName}.wav"); if (wavFile is not null) { _player.Record(wavFile.TryGetLocalPath()); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/SystemTextureEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/SystemTextureEditorViewModel.cs index e4cada75..988f32b9 100644 --- a/src/SerialLoops/ViewModels/Editors/SystemTextureEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/SystemTextureEditorViewModel.cs @@ -37,7 +37,7 @@ public SystemTextureEditorViewModel(SystemTextureItem item, MainWindowViewModel private async Task ExportButton_Click() { - IStorageFile savedFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Export_System_Texture, [new FilePickerFileType(Strings.PNG_Image) { Patterns = ["*.png"] }], $"{SystemTexture.Grp.Index:D4}.png"); + IStorageFile? savedFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Export_System_Texture, [new FilePickerFileType(Strings.PNG_Image) { Patterns = ["*.png"] }], $"{SystemTexture.Grp.Index:D4}.png"); if (savedFile is not null) { try @@ -65,15 +65,15 @@ private async Task ReplaceWithPaletteButton_Click() private async Task ReplaceImage(bool replacePalette) { SKBitmap original = SystemTexture.GetTexture(); - IStorageFile openFile = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_System_Texture, [new FilePickerFileType(Strings.Supported_Images) { Patterns = Shared.SupportedImageFiletypes }]); + IStorageFile? openFile = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_System_Texture, [new FilePickerFileType(Strings.Supported_Images) { Patterns = Shared.SupportedImageFiletypes }]); if (openFile is not null) { SKBitmap newImage = SKBitmap.Decode(openFile.Path.LocalPath); ImageCropResizeDialogViewModel cropResizeDialogViewModel = new(newImage, original.Width, original.Height, _log); - SKBitmap finalImage = await new ImageCropResizeDialog() + SKBitmap? finalImage = await new ImageCropResizeDialog() { DataContext = cropResizeDialogViewModel, - }.ShowDialog(_window.Window); + }.ShowDialog(_window.Window); if (finalImage is not null) { try @@ -91,4 +91,4 @@ private async Task ReplaceImage(bool replacePalette) } } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Editors/TopicEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/TopicEditorViewModel.cs index ae842302..a653bc9a 100644 --- a/src/SerialLoops/ViewModels/Editors/TopicEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/TopicEditorViewModel.cs @@ -22,12 +22,12 @@ public class TopicEditorViewModel : EditorViewModel public string Title { - get => _title.GetSubstitutedString(_window.OpenProject); + get => _title.GetSubstitutedString(_window.OpenProject!); set { - this.RaiseAndSetIfChanged(ref _title, value.GetOriginalString(_window.OpenProject)); - Topic.TopicEntry.Title = _title; - Topic.DisplayName = $"{Topic.TopicEntry.Id} - {_title.GetSubstitutedString(_window.OpenProject)}"; + this.RaiseAndSetIfChanged(ref _title, value.GetOriginalString(_window.OpenProject!)); + Topic.TopicEntry!.Title = _title; + Topic.DisplayName = $"{Topic.TopicEntry.Id} - {_title.GetSubstitutedString(_window.OpenProject!)}"; Topic.UnsavedChanges = true; } } @@ -39,14 +39,18 @@ public ScriptItem AssociatedScript get => _associatedScript; set { + if (Topic.TopicEntry is null) + { + return; + } this.RaiseAndSetIfChanged(ref _associatedScript, value); - if (Topic.TopicEntry.Type == TopicType.Main) + if (Topic.TopicEntry!.Type == TopicType.Main) { - Topic.HiddenMainTopic.EventIndex = (short)_associatedScript.Event.Index; + Topic.HiddenMainTopic!.EventIndex = (short)_associatedScript.Event!.Index; } else { - Topic.TopicEntry.EventIndex = (short)_associatedScript.Event.Index; + Topic.TopicEntry!.EventIndex = (short)_associatedScript.Event!.Index; } Topic.UnsavedChanges = true; } @@ -60,7 +64,7 @@ public byte EpisodeGroup set { this.RaiseAndSetIfChanged(ref _episodeGroup, (byte)(value + 1)); - Topic.TopicEntry.EpisodeGroup = _episodeGroup; + Topic.TopicEntry!.EpisodeGroup = _episodeGroup; Topic.UnsavedChanges = true; } } @@ -72,7 +76,7 @@ public byte PuzzlePhaseGroup set { this.RaiseAndSetIfChanged(ref _puzzlePhaseGroup, value); - Topic.TopicEntry.PuzzlePhaseGroup = _puzzlePhaseGroup; + Topic.TopicEntry!.PuzzlePhaseGroup = _puzzlePhaseGroup; Topic.UnsavedChanges = true; } } @@ -84,7 +88,7 @@ public short BaseTimeGain set { this.RaiseAndSetIfChanged(ref _baseTimeGain, value); - Topic.TopicEntry.BaseTimeGain = _baseTimeGain; + Topic.TopicEntry!.BaseTimeGain = _baseTimeGain; KyonTime = BaseTimeGain * _kyonTimePercentage / 100.0; MikuruTime = BaseTimeGain * _mikuruTimePercentage / 100.0; NagatoTime = BaseTimeGain * _nagatoTimePercentage / 100.0; @@ -102,7 +106,7 @@ public short KyonTimePercentage set { this.RaiseAndSetIfChanged(ref _kyonTimePercentage, value); - Topic.TopicEntry.KyonTimePercentage = _kyonTimePercentage; + Topic.TopicEntry!.KyonTimePercentage = _kyonTimePercentage; KyonTime = BaseTimeGain * _kyonTimePercentage / 100.0; Topic.UnsavedChanges = true; } @@ -117,7 +121,7 @@ public short MikuruTimePercentage set { this.RaiseAndSetIfChanged(ref _mikuruTimePercentage, value); - Topic.TopicEntry.MikuruTimePercentage = _mikuruTimePercentage; + Topic.TopicEntry!.MikuruTimePercentage = _mikuruTimePercentage; MikuruTime = BaseTimeGain * _mikuruTimePercentage / 100.0; Topic.UnsavedChanges = true; } @@ -132,7 +136,7 @@ public short NagatoTimePercentage set { this.RaiseAndSetIfChanged(ref _nagatoTimePercentage, value); - Topic.TopicEntry.NagatoTimePercentage = _nagatoTimePercentage; + Topic.TopicEntry!.NagatoTimePercentage = _nagatoTimePercentage; NagatoTime = BaseTimeGain * _nagatoTimePercentage / 100.0; Topic.UnsavedChanges = true; } @@ -147,7 +151,7 @@ public short KoizumiTimePercentage set { this.RaiseAndSetIfChanged(ref _koizumiTimePercentage, value); - Topic.TopicEntry.KoizumiTimePercentage = _koizumiTimePercentage; + Topic.TopicEntry!.KoizumiTimePercentage = _koizumiTimePercentage; KoizumiTime = BaseTimeGain * _koizumiTimePercentage / 100.0; Topic.UnsavedChanges = true; } @@ -157,13 +161,13 @@ public short KoizumiTimePercentage public TopicEditorViewModel(TopicItem topic, MainWindowViewModel window, ILogger log) : base(topic, window, log) { - Tabs = window.EditorTabs; + Tabs = window.EditorTabs!; Topic = topic; - _title = Topic.TopicEntry.Title; - Scripts = new(window.OpenProject.Items.Where(i => i.Type == ItemDescription.ItemType.Script).Cast()); + _title = Topic.TopicEntry!.Title; + Scripts = new(window.OpenProject!.Items.Where(i => i.Type == ItemDescription.ItemType.Script).Cast()); short associatedScriptIndex = (short)(Topic.TopicEntry.Type == TopicType.Main ? Topic.HiddenMainTopic?.EventIndex ?? Topic.TopicEntry.EventIndex : Topic.TopicEntry.EventIndex); - _associatedScript = (ScriptItem)window.OpenProject.Items.FirstOrDefault(i => - i.Type == ItemDescription.ItemType.Script && ((ScriptItem)i).Event.Index == associatedScriptIndex); + _associatedScript = (ScriptItem)window.OpenProject.Items.First(i => + i.Type == ItemDescription.ItemType.Script && ((ScriptItem)i).Event!.Index == associatedScriptIndex); EpisodeGroups = [Strings.Episode_1, Strings.Episode_2, Strings.Episode_3, Strings.Episode_4, Strings.Episode_5]; _episodeGroup = Topic.TopicEntry.EpisodeGroup; _puzzlePhaseGroup = Topic.TopicEntry.PuzzlePhaseGroup; diff --git a/src/SerialLoops/ViewModels/Editors/VoicedLineEditorViewModel.cs b/src/SerialLoops/ViewModels/Editors/VoicedLineEditorViewModel.cs index 1736d2e4..d6930fc7 100644 --- a/src/SerialLoops/ViewModels/Editors/VoicedLineEditorViewModel.cs +++ b/src/SerialLoops/ViewModels/Editors/VoicedLineEditorViewModel.cs @@ -24,8 +24,8 @@ namespace SerialLoops.ViewModels.Editors; public class VoicedLineEditorViewModel : EditorViewModel { private VoicedLineItem _vce; - private VoiceMapEntry _voiceMapEntry; - private string _subtitle; + private VoiceMapEntry? _voiceMapEntry; + private string? _subtitle; public ICommand ReplaceCommand { get; set; } public ICommand ExportCommand { get; set; } @@ -112,15 +112,15 @@ public bool BottomY } } - public string Subtitle + public string? Subtitle { - get => _project.LangCode.Equals("ja") ? _subtitle : (_subtitle?.GetSubstitutedString(_project) ?? string.Empty); + get => _project!.LangCode!.Equals("ja") ? _subtitle : (_subtitle?.GetSubstitutedString(_project) ?? string.Empty); set { - this.RaiseAndSetIfChanged(ref _subtitle, _project.LangCode.Equals("ja") ? value : value.GetOriginalString(_project)); + this.RaiseAndSetIfChanged(ref _subtitle, _project!.LangCode!.Equals("ja") ? value : value?.GetOriginalString(_project)); if (_voiceMapEntry is null) { - _project.VoiceMap.VoiceMapEntries.Add(new() + _project.VoiceMap!.VoiceMapEntries.Add(new() { VoiceFileName = Path.GetFileNameWithoutExtension(_vce.VoiceFile), FontSize = 100, @@ -140,12 +140,12 @@ public string Subtitle } } - public bool SubsEnabled => _window.OpenProject.VoiceMap is not null; + public bool SubsEnabled => _window.OpenProject!.VoiceMap is not null; public VoicedLineEditorViewModel(VoicedLineItem item, MainWindowViewModel window, ILogger log) : base(item, window, log, window.OpenProject) { _vce = item; - VcePlayer = new(_vce, log, null); + VcePlayer = new(_vce, log, string.Empty); ReplaceCommand = ReactiveCommand.CreateFromTask(Replace); ExportCommand = ReactiveCommand.CreateFromTask(Export); RestoreCommand = ReactiveCommand.Create(Restore); @@ -156,7 +156,7 @@ public VoicedLineEditorViewModel(VoicedLineItem item, MainWindowViewModel window SubtitleScreen = ScreenSelector.SelectedScreen; }; - _voiceMapEntry = _project.VoiceMap.VoiceMapEntries.FirstOrDefault(v => v.VoiceFileName.Equals(Path.GetFileNameWithoutExtension(_vce.VoiceFile))); + _voiceMapEntry = _project!.VoiceMap!.VoiceMapEntries.FirstOrDefault(v => v.VoiceFileName.Equals(Path.GetFileNameWithoutExtension(_vce.VoiceFile))); if (_voiceMapEntry is not null) { _subtitle = _voiceMapEntry.Subtitle; @@ -168,21 +168,21 @@ public VoicedLineEditorViewModel(VoicedLineItem item, MainWindowViewModel window private async Task Replace() { - IStorageFile openFile = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_voiced_line, [new FilePickerFileType(Strings.Supported_Audio_Files) { Patterns = Shared.SupportedAudioFiletypes }, - new FilePickerFileType(Strings.WAV_files) { Patterns = ["*.wav"] }, new FilePickerFileType(Strings.FLAC_files) { Patterns = ["*.flac"] }, - new FilePickerFileType(Strings.MP3_files) { Patterns = ["*.mp3"] }, new FilePickerFileType(Strings.Vorbis_files) { Patterns = ["*.ogg"] }]); + IStorageFile? openFile = await _window.Window.ShowOpenFilePickerAsync(Strings.Replace_voiced_line, [new(Strings.Supported_Audio_Files) { Patterns = Shared.SupportedAudioFiletypes }, + new(Strings.WAV_files) { Patterns = ["*.wav"] }, new(Strings.FLAC_files) { Patterns = ["*.flac"] }, + new(Strings.MP3_files) { Patterns = ["*.mp3"] }, new(Strings.Vorbis_files) { Patterns = ["*.ogg"] }]); if (openFile is not null) { LoopyProgressTracker tracker = new(); VcePlayer.Stop(); - await new ProgressDialog(() => _vce.Replace(openFile.Path.LocalPath, _project.BaseDirectory, _project.IterativeDirectory, Path.Combine(_project.Config.CachesDirectory, "vce", $"{_vce.Name}.wav"), _log), + await new ProgressDialog(() => _vce.Replace(openFile.Path.LocalPath, _project!.BaseDirectory, _project.IterativeDirectory, Path.Combine(_project.Config!.CachesDirectory, "vce", $"{_vce.Name}.wav"), _log), () => { }, tracker, Strings.Replace_voiced_line).ShowDialog(_window.Window); } } private async Task Export() { - IStorageFile saveFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Save_voiced_line_as_WAV, [new FilePickerFileType(Strings.WAV_File) { Patterns = ["*.wav"] }]); + IStorageFile? saveFile = await _window.Window.ShowSaveFilePickerAsync(Strings.Save_voiced_line_as_WAV, [new(Strings.WAV_File) { Patterns = ["*.wav"] }]); if (saveFile is not null) { WaveFileWriter.CreateWaveFile(saveFile.Path.LocalPath, _vce.GetWaveProvider(_log)); @@ -196,12 +196,17 @@ private void Restore() private void UpdatePreview() { + if (_subtitle is null) + { + return; + } + SubtitlesPreview = new(256, 384); SKCanvas canvas = new(SubtitlesPreview); canvas.DrawColor(SKColors.DarkGray); - canvas.DrawLine(new SKPoint { X = 0, Y = 192 }, new SKPoint { X = 256, Y = 192 }, DialogueScriptParameter.Paint00); + canvas.DrawLine(new() { X = 0, Y = 192 }, new() { X = 256, Y = 192 }, DialogueScriptParameter.Paint00); - bool bottomScreen = _voiceMapEntry.TargetScreen == VoiceMapEntry.Screen.BOTTOM; + bool bottomScreen = _voiceMapEntry!.TargetScreen == VoiceMapEntry.Screen.BOTTOM; if (bottomScreen) { for (int i = 0; i <= 1; i++) @@ -209,7 +214,7 @@ private void UpdatePreview() canvas.DrawHaroohieText( _subtitle, DialogueScriptParameter.Paint07, - _project, + _project!, i + _voiceMapEntry.X, 1 + _voiceMapEntry.Y + (bottomScreen ? 192 : 0), false @@ -220,7 +225,7 @@ private void UpdatePreview() canvas.DrawHaroohieText( _subtitle, DialogueScriptParameter.Paint00, - _project, + _project!, _voiceMapEntry.X, _voiceMapEntry.Y + (bottomScreen ? 192 : 0), false @@ -228,4 +233,4 @@ private void UpdatePreview() canvas.Flush(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/MainWindowViewModel.cs b/src/SerialLoops/ViewModels/MainWindowViewModel.cs index 4caf3bc4..491f8d29 100644 --- a/src/SerialLoops/ViewModels/MainWindowViewModel.cs +++ b/src/SerialLoops/ViewModels/MainWindowViewModel.cs @@ -33,6 +33,7 @@ using SerialLoops.Views.Dialogs; using SerialLoops.Views.Panels; using SkiaSharp; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace SerialLoops.ViewModels; @@ -49,12 +50,12 @@ public partial class MainWindowViewModel : ViewModelBase public MainWindow Window { get; set; } public ProjectsCache ProjectsCache { get; set; } public Config? CurrentConfig { get; set; } - public Project OpenProject { get; set; } + public Project? OpenProject { get; set; } public OpenProjectPanel ProjectPanel { get; set; } public Dictionary WindowMenu { get; set; } public Toolbar ToolBar => Window.ToolBar; - public EditorTabsPanelViewModel EditorTabs { get; set; } - public ItemExplorerPanelViewModel ItemExplorer { get; set; } + public EditorTabsPanelViewModel? EditorTabs { get; set; } + public ItemExplorerPanelViewModel? ItemExplorer { get; set; } public NativeMenuItem RecentProjectsMenu { get; set; } = new(Strings.Recent_Projects); public LoopyLogger Log { get; set; } @@ -62,7 +63,7 @@ public partial class MainWindowViewModel : ViewModelBase private SKBitmap _blankNameplate, _blankNameplateBaseArrow; private SKTypeface _msGothicHaruhi; - public string ShutdownUpdateUrl { get; set; } = null; + public string? ShutdownUpdateUrl { get; set; } = null; public ICommand NewProjectCommand { get; private set; } public ICommand OpenProjectCommand { get; private set; } @@ -126,33 +127,33 @@ public MainWindowViewModel() { Process.Start(new ProcessStartInfo { - FileName = Path.Combine(CurrentConfig.UserDirectory, "Logs", "SerialLoops.log"), + FileName = Path.Combine(CurrentConfig!.UserDirectory, "Logs", "SerialLoops.log"), UseShellExecute = true, }); } catch (Exception) { - Log.LogError("Failed to open log file directly. " + - $"Logs can be found at {Path.Combine(CurrentConfig.UserDirectory, "Logs", "SerialLoops.log")}"); + Log!.LogError("Failed to open log file directly. " + + $"Logs can be found at {Path.Combine(CurrentConfig!.UserDirectory, "Logs", "SerialLoops.log")}"); } }); } - public async void Initialize(MainWindow window, IConfigFactory configFactory = null) + public async void Initialize(MainWindow window, IConfigFactory? configFactory = null) { Window = window; Log = new(Window); configFactory ??= new ConfigFactory(); CurrentConfig = configFactory.LoadConfig((s) => s, Log); - Strings.Culture = new(CurrentConfig.CurrentCultureName); + Strings.Culture = new(CurrentConfig!.CurrentCultureName); Log.Initialize(CurrentConfig); var fontStyle = new Style(x => x.OfType()); var font = FontFamily.Parse(string.IsNullOrEmpty(CurrentConfig.DisplayFont) ? Strings.Default_Font : CurrentConfig.DisplayFont); fontStyle.Add(new Setter(Avalonia.Controls.Primitives.TemplatedControl.FontFamilyProperty, font)); - Application.Current.Styles.Add(fontStyle); + Application.Current!.Styles.Add(fontStyle); - ProjectsCache = ProjectsCache.LoadCache(CurrentConfig, Log); + ProjectsCache = ProjectsCache.LoadCache(CurrentConfig, Log)!; UpdateRecentProjects(); if (CurrentConfig.CheckForUpdates) @@ -160,7 +161,7 @@ public async void Initialize(MainWindow window, IConfigFactory configFactory = n new UpdateChecker(this).Check(); } - if (CurrentConfig.AutoReopenLastProject && ProjectsCache.RecentProjects.Count > 0) + if (CurrentConfig.AutoReopenLastProject && ProjectsCache.RecentProjects!.Count > 0) { await OpenProjectFromPath(ProjectsCache.RecentProjects[0]); } @@ -181,7 +182,7 @@ private void OpenHomePanel() internal void OpenProjectView(Project project, IProgressTracker tracker) { EditorTabs = new(this, project, Log); - ItemExplorer = new(OpenProject, EditorTabs, Log); + ItemExplorer = new(OpenProject!, EditorTabs, Log); ProjectPanel = new() { DataContext = new OpenProjectPanelViewModel(ItemExplorer, EditorTabs), @@ -212,7 +213,7 @@ internal void OpenProjectView(Project project, IProgressTracker tracker) Window.MainContent.Content = ProjectPanel; } - public async Task CloseProject_Executed(WindowClosingEventArgs e) + public async Task CloseProject_Executed(WindowClosingEventArgs? e) { bool cancel = false; if (OpenProject is not null) @@ -254,7 +255,7 @@ public async Task CloseProject_Executed(WindowClosingEventArgs e) } // Record open items - List openItems = EditorTabs.Tabs.Cast() + List openItems = EditorTabs!.Tabs.Cast() .Select(e => e.Description) .Select(i => i.Name) .ToList(); @@ -267,7 +268,7 @@ public async Task CloseProject_Executed(WindowClosingEventArgs e) public async Task ApplyHacksCommand_Executed() { - AsmHacksDialogViewModel hacksModel = new(OpenProject, CurrentConfig, Log); + AsmHacksDialogViewModel hacksModel = new(OpenProject!, CurrentConfig, Log); AsmHacksDialog hacksDialog = new(hacksModel); await hacksDialog.ShowDialog(Window); } @@ -276,7 +277,7 @@ public async Task ProjectSettingsCommand_Executed() { ProjectSettingsDialogViewModel projectSettingsDialogViewModel = new(); ProjectSettingsDialog projectSettingsDialog = new(); - projectSettingsDialogViewModel.Initialize(projectSettingsDialog, OpenProject.Settings, Log); + projectSettingsDialogViewModel.Initialize(projectSettingsDialog, OpenProject!.Settings, Log); projectSettingsDialog.DataContext = projectSettingsDialogViewModel; await projectSettingsDialog.ShowDialog(Window); } @@ -296,7 +297,7 @@ public async Task CloseProjectView() ItemExplorer = null; ToolBar.Items.Clear(); - NativeMenu menu = NativeMenu.GetMenu(Window); + NativeMenu menu = NativeMenu.GetMenu(Window)!; menu.Items.Remove(WindowMenu[MenuHeader.PROJECT]); WindowMenu.Remove(MenuHeader.PROJECT); menu.Items.Remove(WindowMenu[MenuHeader.TOOLS]); @@ -312,7 +313,7 @@ private void UpdateRecentProjects() RecentProjectsMenu.Menu = []; List projectsToRemove = []; - foreach (string project in ProjectsCache.RecentProjects) + foreach (string project in ProjectsCache.RecentProjects!) { NativeMenuItem recentProject = new() { @@ -323,7 +324,7 @@ private void UpdateRecentProjects() }; if (!File.Exists(project)) { - if (CurrentConfig.RemoveMissingProjects) + if (CurrentConfig!.RemoveMissingProjects) { projectsToRemove.Add(project); continue; @@ -342,7 +343,7 @@ private void UpdateRecentProjects() projectsToRemove.ForEach(project => { ProjectsCache.RecentProjects.Remove(project); - ProjectsCache.RecentWorkspaces.Remove(project); + ProjectsCache.RecentWorkspaces!.Remove(project); }); ProjectsCache.Save(Log); } @@ -373,7 +374,7 @@ public async Task NewProjectCommand_Executed() public async Task OpenProjectCommand_Executed() { - IStorageFile projectFile = await Window.ShowOpenFilePickerAsync(Strings.Open_Project, [new FilePickerFileType(Strings.Serial_Loops_Project) { Patterns = [$"*.{Project.PROJECT_FORMAT}"] }], CurrentConfig.ProjectsDirectory); + IStorageFile? projectFile = await Window.ShowOpenFilePickerAsync(Strings.Open_Project, [new FilePickerFileType(Strings.Serial_Loops_Project) { Patterns = [$"*.{Project.PROJECT_FORMAT}"] }], CurrentConfig!.ProjectsDirectory); if (projectFile is not null) { await OpenProjectFromPath(projectFile.Path.LocalPath); @@ -416,19 +417,19 @@ public async Task OpenProjectFromPath(string path) switch (result.BadArchive) { case "dat.bin": - File.Delete(Path.Combine(OpenProject.BaseDirectory, "assets", "data", + File.Delete(Path.Combine(OpenProject!.BaseDirectory, "assets", "data", $"{result.BadFileIndex:X3}.s")); break; case "grp.bin": - File.Delete(Path.Combine(OpenProject.BaseDirectory, "assets", "graphics", + File.Delete(Path.Combine(OpenProject!.BaseDirectory, "assets", "graphics", $"{result.BadFileIndex:X3}.png")); File.Delete(Path.Combine(OpenProject.BaseDirectory, "assets", "graphics", $"{result.BadFileIndex:X3}.gi")); break; case "evt.bin": - File.Delete(Path.Combine(OpenProject.BaseDirectory, "assets", "events", + File.Delete(Path.Combine(OpenProject!.BaseDirectory, "assets", "events", $"{result.BadFileIndex:X3}.s")); break; } @@ -503,17 +504,17 @@ public void SaveProject_Executed() { { "GRPBIN", - OpenProject.Grp.GetSourceInclude().Split('\n').Where(s => !string.IsNullOrEmpty(s)) + OpenProject.Grp!.GetSourceInclude().Split('\n').Where(s => !string.IsNullOrEmpty(s)) .Select(i => new IncludeEntry(i)).ToArray() }, { "DATBIN", - OpenProject.Dat.GetSourceInclude().Split('\n').Where(s => !string.IsNullOrEmpty(s)) + OpenProject.Dat!.GetSourceInclude().Split('\n').Where(s => !string.IsNullOrEmpty(s)) .Select(i => new IncludeEntry(i)).ToArray() }, { "EVTBIN", - OpenProject.Evt.GetSourceInclude().Split('\n').Where(s => !string.IsNullOrEmpty(s)) + OpenProject.Evt!.GetSourceInclude().Split('\n').Where(s => !string.IsNullOrEmpty(s)) .Select(i => new IncludeEntry(i)).ToArray() } }; @@ -525,7 +526,7 @@ public void SaveProject_Executed() case ItemDescription.ItemType.Background: if (!savedExtra) { - IO.WriteStringFile(Path.Combine("assets", "data", $"{OpenProject.Extra.Index:X3}.s"), + IO.WriteStringFile(Path.Combine("assets", "data", $"{OpenProject.Extra!.Index:X3}.s"), OpenProject.Extra.GetSource([]), OpenProject, Log); savedExtra = true; } @@ -535,7 +536,7 @@ public void SaveProject_Executed() case ItemDescription.ItemType.BGM: if (!savedExtra) { - IO.WriteStringFile(Path.Combine("assets", "data", $"{OpenProject.Extra.Index:X3}.s"), + IO.WriteStringFile(Path.Combine("assets", "data", $"{OpenProject.Extra!.Index:X3}.s"), OpenProject.Extra.GetSource([]), OpenProject, Log); savedExtra = true; } @@ -543,7 +544,7 @@ public void SaveProject_Executed() case ItemDescription.ItemType.Character_Sprite: if (!savedChrData) { - IO.WriteStringFile(Path.Combine("assets", "data", $"{OpenProject.ChrData.Index:X3}.s"), + IO.WriteStringFile(Path.Combine("assets", "data", $"{OpenProject.ChrData!.Index:X3}.s"), OpenProject.ChrData.GetSource(new Dictionary() { { "GRPBIN", OpenProject.Grp.GetSourceInclude().Split('\n').Where(l => !string.IsNullOrWhiteSpace(l)).Select(l => new IncludeEntry(l)).ToArray() } @@ -563,9 +564,9 @@ public void SaveProject_Executed() if (!savedEventTable) { OpenProject.RecalculateEventTable(); - IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.EventTableFile.Index:X3}.s"), OpenProject.EventTableFile.GetSource(includes), OpenProject, Log); + IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.EventTableFile!.Index:X3}.s"), OpenProject.EventTableFile.GetSource(includes), OpenProject, Log); } - EventFile evt = ((ScriptItem)item).Event; + EventFile evt = ((ScriptItem)item).Event!; evt.CollectGarbage(); IO.WriteStringFile(Path.Combine("assets", "events", $"{evt.Index:X3}.s"), evt.GetSource(includes), OpenProject, Log); break; @@ -595,7 +596,7 @@ public void SaveProject_Executed() nameplateCanvas.Flush(); speakerCanvas.Flush(); MemoryStream nameplateStream = new(); - OpenProject.NameplateBitmap.Encode(nameplateStream, SKEncodedImageFormat.Png, 1); + OpenProject.NameplateBitmap!.Encode(nameplateStream, SKEncodedImageFormat.Png, 1); IO.WriteBinaryFile(Path.Combine("assets", "graphics", "B87.png"), nameplateStream.ToArray(), OpenProject, Log); IO.WriteStringFile(Path.Combine("assets", "graphics", "B87.gi"), JsonSerializer.Serialize(OpenProject.NameplateInfo), @@ -604,13 +605,13 @@ public void SaveProject_Executed() if (changedTopics) { - IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.TopicFile.Index:X3}.s"), + IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.TopicFile!.Index:X3}.s"), OpenProject.TopicFile.GetSource([]), OpenProject, Log); } if (changedSubs) { - IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.VoiceMap.Index:X3}.s"), + IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.VoiceMap!.Index:X3}.s"), OpenProject.VoiceMap.GetSource(), OpenProject, Log); } } @@ -662,7 +663,7 @@ public async Task BuildAndRun_Executed() { if (OpenProject is not null) { - if (string.IsNullOrWhiteSpace(CurrentConfig.EmulatorPath) && string.IsNullOrWhiteSpace(CurrentConfig.EmulatorFlatpak)) + if (string.IsNullOrWhiteSpace(CurrentConfig!.EmulatorPath) && string.IsNullOrWhiteSpace(CurrentConfig.EmulatorFlatpak)) { Log.LogWarning("Attempted to build and run project while no emulator path/flatpak was set."); await Window.ShowMessageBoxAsync(Strings.No_Emulator_Path, Strings.No_emulator_path_has_been_set__nPlease_set_the_path_to_a_Nintendo_DS_emulator_in_Preferences_to_use_Build___Run_, @@ -722,9 +723,9 @@ private void InitializeProjectMenu() // Skip adding the new menu items if they're already here return; } - NativeMenu menu = NativeMenu.GetMenu(Window); + NativeMenu menu = NativeMenu.GetMenu(Window)!; int insertionPoint = menu.Items.Count; - if (((NativeMenuItem)menu.Items.Last()).Header.Equals(Strings._Help)) + if (((NativeMenuItem)menu.Items.Last()).Header!.Equals(Strings._Help)) { insertionPoint--; } @@ -863,4 +864,4 @@ private void InitializeProjectMenu() Icon = ControlGenerator.GetVectorIcon("Search", Log), }); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Panels/EditorTabsPanelViewModel.cs b/src/SerialLoops/ViewModels/Panels/EditorTabsPanelViewModel.cs index a83c7ae3..ef19146c 100644 --- a/src/SerialLoops/ViewModels/Panels/EditorTabsPanelViewModel.cs +++ b/src/SerialLoops/ViewModels/Panels/EditorTabsPanelViewModel.cs @@ -14,11 +14,10 @@ public class EditorTabsPanelViewModel : ViewModelBase { private Project _project; private ILogger _log; - private EditorViewModel _selectedTab; public MainWindowViewModel MainWindow { get; private set; } [Reactive] - public EditorViewModel SelectedTab { get; set; } + public EditorViewModel? SelectedTab { get; set; } public ICommand TabSwitchedCommand { get; set; } @@ -43,7 +42,7 @@ public void OpenTab(ItemDescription item) } } - EditorViewModel newTab = CreateTab(item); + EditorViewModel? newTab = CreateTab(item); if (newTab is not null) { Tabs.Add(newTab); @@ -51,7 +50,7 @@ public void OpenTab(ItemDescription item) } } - private EditorViewModel CreateTab(ItemDescription item) + private EditorViewModel? CreateTab(ItemDescription item) { switch (item.Type) { @@ -101,9 +100,4 @@ public void OnTabClosed(EditorViewModel closedEditor) ((SfxEditorViewModel)closedEditor).SfxPlayerPanel.Stop(); } } - - public void OnTabMiddleClicked() - { - Tabs.Remove(SelectedTab); - } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Panels/HomePanelViewModel.cs b/src/SerialLoops/ViewModels/Panels/HomePanelViewModel.cs index 57c633f6..98e7200f 100644 --- a/src/SerialLoops/ViewModels/Panels/HomePanelViewModel.cs +++ b/src/SerialLoops/ViewModels/Panels/HomePanelViewModel.cs @@ -7,6 +7,7 @@ using SerialLoops.Controls; using SerialLoops.Utility; using SerialLoops.Views.Panels; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace SerialLoops.ViewModels.Panels; @@ -20,17 +21,17 @@ public void Initialize(MainWindowViewModel mainWindow, HomePanel homePanel) { MainWindow = mainWindow; _homePanel = homePanel; - foreach (string project in MainWindow.ProjectsCache.RecentProjects) + foreach (string project in MainWindow.ProjectsCache.RecentProjects!) { bool missing = !File.Exists(project); - if (missing && MainWindow.CurrentConfig.RemoveMissingProjects) + if (missing && MainWindow.CurrentConfig!.RemoveMissingProjects) { continue; } LinkButton linkButton = new() { Text = Path.GetFileName(project), - OnClick = (sender, args) => + OnClick = (_, _) => { MainWindow.OpenRecentProjectCommand.Execute(project); }, @@ -46,7 +47,7 @@ public void Initialize(MainWindowViewModel mainWindow, HomePanel homePanel) if (missing) { MainWindow.Window.TryFindResource("DisabledLinkColor", MainWindow.Window.ActualThemeVariant, out object? brush); - panel.Children.Add(new TextBlock { Text = Strings.Missing_ + $" {project}", Foreground = (ImmutableSolidColorBrush)brush }); + panel.Children.Add(new TextBlock { Text = Strings.Missing_ + $" {project}", Foreground = (ImmutableSolidColorBrush)brush! }); } _homePanel.RecentsPanel.Children.Add(ControlGenerator.GetControlWithIcon(panel, !missing ? "AppIconSimple" : "Warning", Log)); } @@ -56,4 +57,4 @@ public void Initialize(MainWindowViewModel mainWindow, HomePanel homePanel) _homePanel.RecentsPanel.Children.Add(new TextBlock() { Text = Strings.No_recent_projects__Create_one_and_it_will_appear_here_ }); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/ViewModels/Panels/ItemExplorerPanelViewModel.cs b/src/SerialLoops/ViewModels/Panels/ItemExplorerPanelViewModel.cs index 3ff4cd1b..aa69fe59 100644 --- a/src/SerialLoops/ViewModels/Panels/ItemExplorerPanelViewModel.cs +++ b/src/SerialLoops/ViewModels/Panels/ItemExplorerPanelViewModel.cs @@ -21,7 +21,7 @@ public class ItemExplorerPanelViewModel : ViewModelBase private EditorTabsPanelViewModel _tabs; private ILogger _log; - private ObservableCollection _items; + private ObservableCollection _items = []; public ObservableCollection Items { get => _items; @@ -58,7 +58,7 @@ public ObservableCollection Items } [Reactive] - public HierarchicalTreeDataGridSource Source { get; private set; } + public HierarchicalTreeDataGridSource Source { get; private set; } = new([]); [Reactive] public bool ExpandItems { get; set; } @@ -77,7 +77,7 @@ public ItemExplorerPanelViewModel(Project project, EditorTabsPanelViewModel tabs public void OpenItem(TreeDataGrid viewer) { - ItemDescription item = _project.FindItem(((ITreeItem)viewer.RowSelection.SelectedItem)?.Text); + ItemDescription? item = _project.FindItem(((ITreeItem?)viewer.RowSelection?.SelectedItem)?.Text); if (item is not null) { _tabs.OpenTab(item); @@ -86,7 +86,7 @@ public void OpenItem(TreeDataGrid viewer) private ObservableCollection GetSections() { - return new ObservableCollection(Items.GroupBy(i => i.Type).OrderBy(g => LocalizeItemTypes(g.Key)) + return new(Items.GroupBy(i => i.Type).OrderBy(g => LocalizeItemTypes(g.Key)) .Select(g => new SectionTreeItem( LocalizeItemTypes(g.Key), g.Select(i => new ItemDescriptionTreeItem(i)), @@ -134,4 +134,4 @@ private void Search(string query) Items = new(_project.Items.Where(i => i.DisplayName.Contains(query, System.StringComparison.OrdinalIgnoreCase))); } } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Views/Dialogs/BgmLoopPropertiesDialog.axaml.cs b/src/SerialLoops/Views/Dialogs/BgmLoopPropertiesDialog.axaml.cs index 750e7379..29a0d935 100644 --- a/src/SerialLoops/Views/Dialogs/BgmLoopPropertiesDialog.axaml.cs +++ b/src/SerialLoops/Views/Dialogs/BgmLoopPropertiesDialog.axaml.cs @@ -16,20 +16,20 @@ protected override void OnLoaded(RoutedEventArgs e) base.OnLoaded(e); // Order here matters. Do not change the order. I do not know why. Please don't change the order. - EndSampleSlider.Value = (double)EndSampleBox.Value; - StartSampleSlider.Value = (double)StartSampleBox.Value; + EndSampleSlider.Value = (double)(EndSampleBox.Value ?? 0); + StartSampleSlider.Value = (double)(StartSampleBox.Value ?? 0); } protected override void OnClosing(WindowClosingEventArgs e) { base.OnClosing(e); - ((BgmLoopPropertiesDialogViewModel)DataContext).LoopPreviewPlayer.Stop(); + ((BgmLoopPropertiesDialogViewModel)DataContext!).LoopPreviewPlayer.Stop(); } private void StartSlider_ValueChanged(object? sender, Avalonia.Controls.Primitives.RangeBaseValueChangedEventArgs e) { - BgmLoopPropertiesDialogViewModel viewModel = (BgmLoopPropertiesDialogViewModel)DataContext; + BgmLoopPropertiesDialogViewModel viewModel = (BgmLoopPropertiesDialogViewModel)DataContext!; if (StartSampleSlider.Value > EndSampleSlider.Value) { StartSampleSlider.ValueChanged -= StartSlider_ValueChanged; @@ -45,7 +45,7 @@ private void StartSlider_ValueChanged(object? sender, Avalonia.Controls.Primitiv private void EndSlider_ValueChanged(object? sender, Avalonia.Controls.Primitives.RangeBaseValueChangedEventArgs e) { - BgmLoopPropertiesDialogViewModel viewModel = (BgmLoopPropertiesDialogViewModel)DataContext; + BgmLoopPropertiesDialogViewModel viewModel = (BgmLoopPropertiesDialogViewModel)DataContext!; if (EndSampleSlider.Value < StartSampleSlider.Value) { EndSampleSlider.ValueChanged -= EndSlider_ValueChanged; @@ -57,4 +57,4 @@ private void EndSlider_ValueChanged(object? sender, Avalonia.Controls.Primitives viewModel.LoopPreview.EndSample = viewModel.LoopPreview.GetSampleFromTimestamp(EndSampleSlider.Value); viewModel.LoopPreviewPlayer.Stop(); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Views/Dialogs/ProjectCreationDialog.axaml.cs b/src/SerialLoops/Views/Dialogs/ProjectCreationDialog.axaml.cs index 0a638aec..37d17c8e 100644 --- a/src/SerialLoops/Views/Dialogs/ProjectCreationDialog.axaml.cs +++ b/src/SerialLoops/Views/Dialogs/ProjectCreationDialog.axaml.cs @@ -13,7 +13,7 @@ public ProjectCreationDialog() NameBox.AddHandler(KeyDownEvent, NameBox_KeyDown, RoutingStrategies.Tunnel); } - private void NameBox_KeyDown(object sender, KeyEventArgs e) + private void NameBox_KeyDown(object? sender, KeyEventArgs e) { if (!string.IsNullOrEmpty(e.KeySymbol) && !AllowedCharactersRegex().IsMatch(e.KeySymbol) && e.Key != Key.Back) { @@ -24,4 +24,4 @@ private void NameBox_KeyDown(object sender, KeyEventArgs e) [GeneratedRegex(@"[A-Za-z\d-_\.]")] private static partial Regex AllowedCharactersRegex(); -} \ No newline at end of file +} diff --git a/src/SerialLoops/Views/Dialogs/UpdateAvailableDialog.axaml.cs b/src/SerialLoops/Views/Dialogs/UpdateAvailableDialog.axaml.cs index e33a2208..d45a10ef 100644 --- a/src/SerialLoops/Views/Dialogs/UpdateAvailableDialog.axaml.cs +++ b/src/SerialLoops/Views/Dialogs/UpdateAvailableDialog.axaml.cs @@ -6,7 +6,7 @@ namespace SerialLoops.Views.Dialogs; public partial class UpdateAvailableDialog : Window { - public UpdateAvailableDialogViewModel ViewModel { get; set; } + public UpdateAvailableDialogViewModel? ViewModel { get; set; } public UpdateAvailableDialog() { @@ -15,13 +15,13 @@ public UpdateAvailableDialog() private void ReleaseLink_Click(object? sender, EventArgs e) { - ViewModel.OpenReleaseLink(); + ViewModel!.OpenReleaseLink(); } private void DialogClosed(object? sender, EventArgs e) { - ViewModel.Config.CheckForUpdates = CheckForUpdatesBox.IsChecked ?? false; + ViewModel!.Config!.CheckForUpdates = CheckForUpdatesBox.IsChecked ?? false; ViewModel.Config.PreReleaseChannel = PreReleaseChannelBox.IsChecked ?? false; ViewModel.Config.Save(ViewModel.Log); } -} \ No newline at end of file +} diff --git a/src/SerialLoops/Views/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorView.axaml b/src/SerialLoops/Views/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorView.axaml index f3691d16..c6ac135e 100644 --- a/src/SerialLoops/Views/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorView.axaml +++ b/src/SerialLoops/Views/Editors/ScriptCommandEditors/TopicGetScriptCommandEditorView.axaml @@ -13,7 +13,7 @@ -