diff --git a/ConverterApp/App.axaml b/ConverterApp/App.axaml new file mode 100644 index 00000000..8f1d37ae --- /dev/null +++ b/ConverterApp/App.axaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConverterApp/App.axaml.cs b/ConverterApp/App.axaml.cs new file mode 100644 index 00000000..15de164a --- /dev/null +++ b/ConverterApp/App.axaml.cs @@ -0,0 +1,86 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using ReactiveUI; +using ReactiveUI.Avalonia; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Windows.Input; + +namespace LSTools.DivineGUI; + +public class BatchProcessItem : ReactiveObject +{ + private bool _isChecked; + private string _name = string.Empty; + private string _type = string.Empty; + private string _batchStatusText = string.Empty; + private double _batchProgressValue; + + public bool IsChecked { get => _isChecked; set => this.RaiseAndSetIfChanged(ref _isChecked, value); } + public string Name { get => _name; set => this.RaiseAndSetIfChanged(ref _name, value); } + public string Type { get => _type; set => this.RaiseAndSetIfChanged(ref _type, value); } + + public ConverterAppSettings Settings { get; set; } = new(); + + public bool FlipUVs { get; set; } + public bool MirrorSkeletons { get; set; } + public bool ApplyBasisTransforms { get; set; } + public bool MeshRigidChecked { get; set; } + public bool MeshRigidEnabled { get; set; } + public bool MeshClothChecked { get; set; } + public bool MeshClothEnabled { get; set; } + public bool MeshProxyChecked { get; set; } + public bool MeshProxyEnabled { get; set; } + + public string BatchStatusText { get => _batchStatusText; set => this.RaiseAndSetIfChanged(ref _batchStatusText, value); } + public double BatchProgressValue { get => _batchProgressValue; set => this.RaiseAndSetIfChanged(ref _batchProgressValue, value); } +} + +public class MainSettingsProvider : ISettingsDataSource +{ + public ConverterAppSettings Settings { get; set; } = new(); +} + +public partial class App : Application +{ + public ObservableCollection BatchProcessItemsCollection { get; } = []; + public ICommand? BrowsePathCommand { get; set; } + public ICommand? SaveOutputCommand { get; set; } + + [STAThread] + public static void Main(string[] args) + { + CultureInfo customCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone(); + customCulture.NumberFormat.NumberDecimalSeparator = "."; + + Thread.CurrentThread.CurrentCulture = customCulture; + Thread.CurrentThread.CurrentUICulture = customCulture; + CultureInfo.DefaultThreadCurrentCulture = customCulture; + CultureInfo.DefaultThreadCurrentUICulture = customCulture; + + AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace() + .UseReactiveUI(rxui => { }) + .RegisterReactiveUIViewsFromEntryAssembly() + .StartWithClassicDesktopLifetime(args); + } + + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + var mainSettingsContext = new MainSettingsProvider(); + desktop.MainWindow = new MainWindow(mainSettingsContext); + } + + base.OnFrameworkInitializationCompleted(); + } +} \ No newline at end of file diff --git a/ConverterApp/App.config b/ConverterApp/App.config deleted file mode 100644 index d0f8440b..00000000 --- a/ConverterApp/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/ConverterApp/ConverterApp.csproj b/ConverterApp/ConverterApp.csproj index e8a4d4c4..4adbf123 100644 --- a/ConverterApp/ConverterApp.csproj +++ b/ConverterApp/ConverterApp.csproj @@ -1,94 +1,44 @@  - - net8.0-windows - WinExe - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - false - true - true - - - x64 - - - x64 - - - - - Always - - - bin\Editor Debug\ - true - MinimumRecommendedRules.ruleset - - - - UserControl - - - Component - - - UserControl - - - UserControl - - - UserControl - - - UserControl - - - UserControl - - - UserControl - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - \ No newline at end of file + + + net10.0 + WinExe + LSTools.DivineGUI + LSTools.DivineGUI.App + + 14 + enable + enable + true + + true + link + Speed + + true + + x64 + AnyCPU;x64 + + LSLib - Divine Cross-Platform GUI Tool + LSLib + Copyright © Norbyte 2012-2026 + 1.18.5.0 + 1.18.5.0 + + + + + + + + + + + + + + + + + diff --git a/ConverterApp/ConverterAppSettings.cs b/ConverterApp/ConverterAppSettings.cs index e377ce57..4cd112e7 100644 --- a/ConverterApp/ConverterAppSettings.cs +++ b/ConverterApp/ConverterAppSettings.cs @@ -1,412 +1,166 @@ -using LSLib.Granny.Model; -using LSLib.LS; +using LSLib.LS; using LSLib.LS.Enums; -using System; -using System.Collections.Generic; +using ReactiveUI; using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; +using System.Text.Json; +using System.Text.Json.Serialization; -namespace ConverterApp; +namespace LSTools.DivineGUI; public interface ISettingsDataSource { ConverterAppSettings Settings { get; set; } } -public class SettingsBase : INotifyPropertyChanged +public interface IGameSettingsTarget { - public event PropertyChangedEventHandler PropertyChanged; - - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - var handler = PropertyChanged; - if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); - } + void SetGame(Game game); } -public class ConverterAppSettings : SettingsBase +public class ConverterAppSettings : ReactiveObject { - private GR2PaneSettings gr2; - - public GR2PaneSettings GR2 - { - get { return gr2; } - set { gr2 = value; } - } - - private PackagePaneSettings pakSettings; - - public PackagePaneSettings PAK - { - get { return pakSettings; } - set { pakSettings = value; } - } - - private ResourcePaneSettings resourceSettings; - - public ResourcePaneSettings Resources - { - get { return resourceSettings; } - set { resourceSettings = value; } - } - - private VirtualTexturesPaneSettings virtualTextureSettings; - public VirtualTexturesPaneSettings VirtualTextures - { - get { return virtualTextureSettings; } - set { virtualTextureSettings = value; } - } - - private OsirisPaneSettings storySettings; - - public OsirisPaneSettings Story - { - get { return storySettings; } - set { storySettings = value; } - } - - private DebugPaneSettings debugSettings; - - public DebugPaneSettings Debugging - { - get { return debugSettings; } - set { debugSettings = value; } - } - - private Game selectedGame = Game.BaldursGate3; + public GR2PaneSettings GR2 { get; init; } = new(); + public PackagePaneSettings PAK { get; init; } = new(); + public ResourcePaneSettings Resources { get; init; } = new(); + public VirtualTexturesPaneSettings VirtualTextures { get; init; } = new(); + public OsirisPaneSettings Story { get; init; } = new(); + public DebugPaneSettings Debugging { get; init; } = new(); public int SelectedGame { - get { return (int)selectedGame; } - set { selectedGame = (Game)value; OnPropertyChanged(); } - } - - private string version = ""; + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } = 4; // Defaults to index 4 (Baldur's Gate 3) - public string Version - { - get { return version; } - set { version = value; } - } + public string Version { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; public void SetPropertyChangedEvent(PropertyChangedEventHandler eventHandler) { - this.PropertyChanged += eventHandler; + PropertyChanged += eventHandler; GR2.PropertyChanged += eventHandler; PAK.PropertyChanged += eventHandler; Resources.PropertyChanged += eventHandler; + VirtualTextures.PropertyChanged += eventHandler; Story.PropertyChanged += eventHandler; - } - - public ConverterAppSettings() - { - GR2 = new GR2PaneSettings(); - PAK = new PackagePaneSettings(); - Resources = new ResourcePaneSettings(); - VirtualTextures = new VirtualTexturesPaneSettings(); - Story = new OsirisPaneSettings(); - Debugging = new DebugPaneSettings(); + Debugging.PropertyChanged += eventHandler; } } -public class GR2PaneSettings : SettingsBase +public class GR2PaneSettings : ReactiveObject { - private string inputPath = ""; - - public string InputPath - { - get { return inputPath; } - set { inputPath = value; OnPropertyChanged(); } - } - - private string outputPath = ""; - - public string OutputPath - { - get { return outputPath; } - set { outputPath = value; OnPropertyChanged(); } - } - - private string batchInputPath = ""; - - public string BatchInputPath - { - get { return batchInputPath; } - set { batchInputPath = value; OnPropertyChanged(); } - } - - private string batchOutputPath = ""; - - public string BatchOutputPath - { - get { return batchOutputPath; } - set { batchOutputPath = value; OnPropertyChanged(); } - } + public string InputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string OutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string BatchInputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string BatchOutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; - private ExportFormat batchInputFormat = ExportFormat.GR2; - - public int BatchInputFormat - { - get { return (int)batchInputFormat; } - set { batchInputFormat = (ExportFormat)value; OnPropertyChanged(); } - } - - private ExportFormat batchOutputFormat = ExportFormat.DAE; - - public int BatchOutputFormat + public LSLib.Granny.ExportFormat BatchInputFormat { - get { return (int)batchOutputFormat; } - set { batchOutputFormat = (ExportFormat)value; OnPropertyChanged(); } - } + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } = LSLib.Granny.ExportFormat.GR2; - private string conformPath; - - public string ConformPath + public LSLib.Granny.ExportFormat BatchOutputFormat { - get { return conformPath; } - set { conformPath = value; OnPropertyChanged(); } - } + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } = LSLib.Granny.ExportFormat.DAE; + public string ConformPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; } -public class PackagePaneSettings : SettingsBase +public class PackagePaneSettings : ReactiveObject { - private string extractInputPath = ""; - - public string ExtractInputPath - { - get { return extractInputPath; } - set { extractInputPath = value; OnPropertyChanged(); } - } - - private string extractOutputPath = ""; - - public string ExtractOutputPath - { - get { return extractOutputPath; } - set { extractOutputPath = value; OnPropertyChanged(); } - } - - private string createInputPath = ""; + public string ExtractInputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string ExtractOutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string CreateInputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string CreateOutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; - public string CreateInputPath - { - get { return createInputPath; } - set { createInputPath = value; OnPropertyChanged(); } - } - - private string createOutputPath = ""; - - public string CreateOutputPath - { - get { return createOutputPath; } - set { createOutputPath = value; OnPropertyChanged(); } - } - - private int createPackageVersion = 0; - - public int CreatePackageVersion - { - get { return createPackageVersion; } - set { createPackageVersion = value; OnPropertyChanged(); } - } - - private int createPackageCompression = 3; - - public int CreatePackageCompression - { - get { return createPackageCompression; } - set { createPackageCompression = value; OnPropertyChanged(); } - } + [JsonConverter(typeof(PackageVersionJsonConverter))] + public LSLib.LS.PackageVersion CreatePackageVersion { get; set => this.RaiseAndSetIfChanged(ref field, value); } - //public string BatchInputPath { get; set; } = ""; - //public string BatchOutputPath { get; set; } = ""; + [JsonConverter(typeof(CompressionMethodJsonConverter))] + public CompressionMethod CreatePackageCompression { get; set => this.RaiseAndSetIfChanged(ref field, value); } = CompressionMethod.LZ4; } -public class ResourcePaneSettings : SettingsBase +public class ResourcePaneSettings : ReactiveObject { - private string inputPath = ""; - - public string InputPath - { - get { return inputPath; } - set { inputPath = value; OnPropertyChanged(); } - } - - private string outputPath = ""; - - public string OutputPath - { - get { return outputPath; } - set { outputPath = value; OnPropertyChanged(); } - } - - private string batchInputPath = ""; - - public string BatchInputPath - { - get { return batchInputPath; } - set { batchInputPath = value; OnPropertyChanged(); } - } - - private string batchOutputPath = ""; - - public string BatchOutputPath - { - get { return batchOutputPath; } - set { batchOutputPath = value; OnPropertyChanged(); } - } - - private int batchInputFormat; - - public int BatchInputFormat - { - get { return batchInputFormat; } - set { batchInputFormat = value; OnPropertyChanged(); } - } - - private int batchOutputFormat; - - public int BatchOutputFormat - { - get { return batchOutputFormat; } - set { batchOutputFormat = value; OnPropertyChanged(); } - } + public string InputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string OutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string BatchInputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string BatchOutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public LSLib.Granny.ExportFormat BatchInputFormat { get; set => this.RaiseAndSetIfChanged(ref field, value); } + public LSLib.Granny.ExportFormat BatchOutputFormat { get; set => this.RaiseAndSetIfChanged(ref field, value); } } -public class VirtualTexturesPaneSettings : SettingsBase +public class VirtualTexturesPaneSettings : ReactiveObject { - private string gtsPath = ""; - - public string GTSPath - { - get { return gtsPath; } - set { gtsPath = value; OnPropertyChanged(); } - } - - private string destinationPath = ""; - - public string DestinationPath - { - get { return destinationPath; } - set { destinationPath = value; OnPropertyChanged(); } - } + public string GTSPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string DestinationPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; } -public class OsirisPaneSettings : SettingsBase +public class OsirisPaneSettings : ReactiveObject { - private string inputPath = ""; - - public string InputPath - { - get { return inputPath; } - set { inputPath = value; OnPropertyChanged(); } - } - - private string outputPath = ""; - - public string OutputPath - { - get { return outputPath; } - set { outputPath = value; OnPropertyChanged(); } - } - - private string filterText = ""; - - public string FilterText - { - get { return filterText; } - set { filterText = value; OnPropertyChanged(); } - } - - private bool filterMatchCase = false; - - public bool FilterMatchCase - { - get { return filterMatchCase; } - set { filterMatchCase = value; OnPropertyChanged(); } - } + public string InputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string OutputPath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public string FilterText { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; + public bool FilterMatchCase { get; set => this.RaiseAndSetIfChanged(ref field, value); } } -public class DebugPaneSettings : SettingsBase +public class DebugPaneSettings : ReactiveObject { - private string savePath = ""; - - public string SavePath - { - get { return savePath; } - set { savePath = value; OnPropertyChanged(); } - } + public string SavePath { get; set => this.RaiseAndSetIfChanged(ref field, value); } = string.Empty; } -sealed class PackageVersionConverter : TypeConverter +public sealed class PackageVersionJsonConverter : JsonConverter { - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + public override LSLib.LS.PackageVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return true; + int index = reader.GetInt32(); + return index switch + { + 2 => LSLib.LS.PackageVersion.V10, + 3 => LSLib.LS.PackageVersion.V9, + 4 => LSLib.LS.PackageVersion.V7, + _ => LSLib.LS.PackageVersion.V18 + }; } - public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + public override void Write(Utf8JsonWriter writer, LSLib.LS.PackageVersion value, JsonSerializerOptions options) { - if(value is PackageVersion version) + int outIndex = value switch { - switch (version) - { - case PackageVersion.V10: - { - return 2; - } - case PackageVersion.V9: - { - return 3; - } - case PackageVersion.V7: - { - return 4; - } - case PackageVersion.V13: - default: - { - return 0; - } - } - } - return 0; + LSLib.LS.PackageVersion.V10 => 2, + LSLib.LS.PackageVersion.V9 => 3, + LSLib.LS.PackageVersion.V7 => 4, + _ => 0 + }; + writer.WriteNumberValue(outIndex); } } -sealed class CompressionConverter : TypeConverter +public sealed class CompressionMethodJsonConverter : JsonConverter { - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + public override CompressionMethod Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return true; + int index = reader.GetInt32(); + return index switch + { + 0 => CompressionMethod.None, + 1 => CompressionMethod.Zlib, + 3 => CompressionMethod.LZ4, + _ => CompressionMethod.LZ4 + }; } - public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + public override void Write(Utf8JsonWriter writer, CompressionMethod value, JsonSerializerOptions options) { - if (value is CompressionMethod compression) + int outIndex = value switch { - switch (compression) - { - case CompressionMethod.Zlib: - { - return 1; - } - case CompressionMethod.None: - { - return 0; - } - case CompressionMethod.LZ4: - default: - { - return 3; - } - } - } - return 0; + CompressionMethod.None => 0, + CompressionMethod.Zlib => 1, + CompressionMethod.LZ4 => 3, + _ => 3 + }; + writer.WriteNumberValue(outIndex); } } diff --git a/ConverterApp/DatabaseDumper.cs b/ConverterApp/DatabaseDumper.cs index 096ca76e..bb893c14 100644 --- a/ConverterApp/DatabaseDumper.cs +++ b/ConverterApp/DatabaseDumper.cs @@ -1,80 +1,122 @@ -using LSLib.LS.Story; -using System; -using System.IO; -using System.Linq; -using System.Text; +using System.Text; +using LSLib.LS.Story; -namespace ConverterApp; +namespace LSTools.DivineGUI; -class DatabaseDumper : IDisposable +public sealed class DatabaseDumper : IDisposable { - private StreamWriter Writer; + public bool DumpUnnamedDbs { get; set; } = false; - public bool DumpUnnamedDbs { get; set; } + private readonly StreamWriter _writer; public DatabaseDumper(Stream outputStream) { - Writer = new StreamWriter(outputStream, Encoding.UTF8); - DumpUnnamedDbs = false; + ArgumentNullException.ThrowIfNull(outputStream); + _writer = new StreamWriter(outputStream, Encoding.UTF8); } - public void Dispose() - { - Writer.Dispose(); - } - + public void Dispose() => _writer.Dispose(); + private void DumpFact(Story story, Fact fact) { - Writer.Write("("); - for (var i = 0; i < fact.Columns.Count; i++) + _writer.Write("("); + + int columnCount = fact.Columns.Count; + for (int i = 0; i < columnCount; i++) { - fact.Columns[i].DebugDump(Writer, story); - if (i + 1 < fact.Columns.Count) + fact.Columns[i].DebugDump(_writer, story); + if (i + 1 < columnCount) { - Writer.Write(", "); + _writer.Write(", "); } } - Writer.WriteLine(")"); + + _writer.Write(")\n"); } public void DumpDatabase(Story story, Database database) { - if (database.OwnerNode != null) + if (database.OwnerNode is { } node) { - if (database.OwnerNode.Name.Length > 0) + if (!string.IsNullOrEmpty(node.Name)) { - Writer.Write($"Database '{database.OwnerNode.Name}'"); + _writer.Write($"Database '{node.Name}'"); } else { - Writer.Write($"Database #{database.Index} <{database.OwnerNode.TypeName()}>"); + _writer.Write($"Database #{database.Index} <{node.TypeName()}>"); } } else { - Writer.Write($"Database #{database.Index}"); + _writer.Write($"Database #{database.Index}"); } - var types = String.Join(", ", database.Parameters.Types.Select(ty => story.Types[ty].Name)); - Writer.WriteLine($" ({types}):"); + var typeNamesList = new List(database.Parameters.Types.Count); + foreach (int typeId in database.Parameters.Types.Select(v => (int)v)) + { + if (story.Types.TryGetValue((uint)typeId, out var storyType)) + { + typeNamesList.Add(storyType.Name); + } + } + string typesString = string.Join(", ", typeNamesList); + _writer.Write($" ({typesString}):\n"); - foreach (var fact in database.Facts) + if (database.Facts is IEnumerable stronglyTypedFacts) { - Writer.Write("\t"); - DumpFact(story, fact); + foreach (Fact fact in stronglyTypedFacts) + { + _writer.Write("\t"); + DumpFact(story, fact); + } } } public void DumpAll(Story story) { - Writer.WriteLine(" === DUMP OF DATABASES === "); - foreach (var db in story.Databases) + ArgumentNullException.ThrowIfNull(story); + _writer.Write(" === DUMP OF DATABASES === \n"); + + foreach (KeyValuePair entry in story.Databases) { - if (DumpUnnamedDbs || (db.Value.OwnerNode != null && db.Value.OwnerNode.Name.Length > 0)) + Database db = entry.Value; + if (DumpUnnamedDbs || (db.OwnerNode is { } node && !string.IsNullOrEmpty(node.Name))) { - DumpDatabase(story, db.Value); - Writer.WriteLine(""); + DumpDatabase(story, db); + _writer.Write("\n"); } } } -} + + public List GenerateGridRows(Story story) + { + ArgumentNullException.ThrowIfNull(story); + var rowsCollection = new List(); + + foreach (KeyValuePair entry in story.Databases) + { + Database db = entry.Value; + + if (DumpUnnamedDbs || (db.OwnerNode is { } node && !string.IsNullOrEmpty(node.Name))) + { + if (db.Facts is IEnumerable stronglyTypedFacts) + { + foreach (Fact fact in stronglyTypedFacts) + { + var evaluatedDisplayValues = new string[fact.Columns.Count]; + for (int i = 0; i < fact.Columns.Count; i++) + { + using var stringWriter = new StringWriter(); + fact.Columns[i].DebugDump(stringWriter, story); + evaluatedDisplayValues[i] = stringWriter.ToString(); + } + rowsCollection.Add(new FactRowModel(fact, evaluatedDisplayValues)); + } + } + } + } + + return rowsCollection; + } +} \ No newline at end of file diff --git a/ConverterApp/DebugDumper.cs b/ConverterApp/DebugDumper.cs index df1d2ad8..9ce78505 100644 --- a/ConverterApp/DebugDumper.cs +++ b/ConverterApp/DebugDumper.cs @@ -1,174 +1,167 @@ -using LSLib.LS; -using LSLib.LS.Enums; -using LSLib.LS.Story; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Windows.Forms; +using System.Threading.Tasks; +using LSLib.LS; +using LSLib.LS.Enums; +using LSLib.LS.Resources.LSF; +using LSLib.LS.Story; +using LSLib.LS.Story.Compiler; // For handling the Diagnostic collection context -namespace ConverterApp; +namespace LSTools.DivineGUI; -public delegate void DumugDumperReportProgress(int percentage, string statusText); +public record DumperProgressEventArgs(int Percentage, string StatusText); public class DebugDumperTask { - private Package SavePackage; - private Resource SaveMeta; - private Resource SaveGlobals; - private Story SaveStory; + private Package? _savePackage; + private Resource? _saveMeta; + private Resource? _saveGlobals; + private Story? _saveStory; public Game GameVersion { get; set; } - public string SaveFilePath { get; set; } - public string ExtractionPath { get; set; } - public string DataDumpPath { get; set; } - - // General savegame dumping settings - public bool ExtractAll { get; set; } - public bool ConvertToLsx { get; set; } - public bool DumpModList { get; set; } - - // Behavior variable dumping settings - public bool DumpGlobalVars { get; set; } - public bool DumpCharacterVars { get; set; } - public bool DumpItemVars { get; set; } - public bool IncludeDeletedVars { get; set; } - public bool IncludeLocalScopes { get; set; } - - // Story dump settings - public bool DumpStoryDatabases { get; set; } - public bool DumpStoryGoals { get; set; } - public bool IncludeUnnamedDatabases { get; set; } - - public event DumugDumperReportProgress ReportProgress; - - public DebugDumperTask() - { - ExtractAll = true; - ConvertToLsx = true; - DumpModList = true; - - DumpGlobalVars = true; - DumpCharacterVars = true; - DumpItemVars = true; - IncludeDeletedVars = false; - IncludeLocalScopes = false; - // TODO ------------------ RE-IMPORTABLE VARS/DBS FORMAT ---------------------- - - DumpStoryDatabases = true; - DumpStoryGoals = true; - IncludeUnnamedDatabases = false; - } + public string SaveFilePath { get; set; } = string.Empty; + public string ExtractionPath { get; set; } = string.Empty; + public string DataDumpPath { get; set; } = string.Empty; + public bool ExtractAll { get; set; } = true; + public bool ConvertToLsx { get; set; } = true; + public bool DumpModList { get; set; } = true; + public bool DumpGlobalVars { get; set; } = true; + public bool DumpCharacterVars { get; set; } = true; + public bool DumpItemVars { get; set; } = true; + public bool IncludeDeletedVars { get; set; } = false; + public bool IncludeLocalScopes { get; set; } = false; + public bool DumpStoryDatabases { get; set; } = true; + public bool DumpStoryGoals { get; set; } = true; + public bool IncludeUnnamedDatabases { get; set; } = false; + + // TARGET EXTRACTION HOOK: Passes collected file logs, data validations, or errors back to the DataGrid collection + public List TaskDiagnostics { get; } = []; + + public event Action? ProgressUpdated; + + private void ReportProgress(int percentage, string statusText) => + ProgressUpdated?.Invoke(new DumperProgressEventArgs(percentage, statusText)); private void DoExtractPackage() { - var packager = new Packager(); - packager.ProgressUpdate = (file, numerator, denominator) => { - ReportProgress(5 + (int)(numerator * 15 / denominator), "Extracting: " + file); + ArgumentNullException.ThrowIfNull(_savePackage); + + var packager = new Packager + { + ProgressUpdate = (file, numerator, denominator) => + ReportProgress(5 + (int)(denominator == 0 ? 0 : numerator * 15 / denominator), $"Extracting: {file}") }; - packager.UncompressPackage(SavePackage, ExtractionPath); + + packager.UncompressPackage(_savePackage, ExtractionPath); + TaskDiagnostics.Add(new Diagnostic(null, MessageLevel.Info, "PAK01", $"Extracted complete payload successfully to {ExtractionPath}")); } private void DoLsxConversion() { + ArgumentNullException.ThrowIfNull(_savePackage); + var conversionParams = ResourceConversionParameters.FromGameVersion(GameVersion); var loadParams = ResourceLoadParameters.FromGameVersion(GameVersion); - var lsfList = SavePackage.Files.Where(p => p.Name.EndsWith(".lsf")); + var lsfList = _savePackage.Files.Where(p => p.Name.EndsWith(".lsf", StringComparison.OrdinalIgnoreCase)).ToList(); var numProcessed = 0; + foreach (var lsf in lsfList) { - var lsfPath = Path.Combine(ExtractionPath, lsf.Name); - var lsxPath = Path.Combine(ExtractionPath, lsf.Name.Substring(0, lsf.Name.Length - 4) + ".lsx"); + try + { + var lsfPath = Path.Combine(ExtractionPath, lsf.Name); + string baseName = lsf.Name.EndsWith(".lsf", StringComparison.OrdinalIgnoreCase) ? lsf.Name[..^4] : lsf.Name; + var lsxPath = Path.Combine(ExtractionPath, $"{baseName}.lsx"); - ReportProgress(20 + (numProcessed * 30 / lsfList.Count()), "Converting to LSX: " + lsf.Name); - var resource = ResourceUtils.LoadResource(lsfPath, ResourceFormat.LSF, loadParams); - ResourceUtils.SaveResource(resource, lsxPath, ResourceFormat.LSX, conversionParams); - numProcessed++; + int calculatedProgress = lsfList.Count == 0 ? 0 : numProcessed * 30 / lsfList.Count; + ReportProgress(20 + calculatedProgress, $"Converting to LSX: {lsf.Name}"); + + var resource = ResourceUtils.LoadResource(lsfPath, ResourceFormat.LSF, loadParams); + ResourceUtils.SaveResource(resource, lsxPath, ResourceFormat.LSX, conversionParams); + numProcessed++; + } + catch (Exception ex) + { + // Logs any localized serialization error cleanly into the grid display + TaskDiagnostics.Add(new Diagnostic(null, MessageLevel.Warning, "CONV02", $"Failed transforming '{lsf.Name}': {ex.Message}")); + } } } private Resource LoadPackagedResource(string path) { - var fileInfo = SavePackage.Files.FirstOrDefault(p => p.Name.ToLowerInvariant() == path); - if (fileInfo == null) - { - throw new ArgumentException($"Could not locate file in package: '{path}"); - } + ArgumentNullException.ThrowIfNull(_savePackage); - Resource resource; - using var rsrcStream = fileInfo.CreateContentReader(); - using (var rsrcReader = new LSFReader(rsrcStream)) - { - resource = rsrcReader.Read(); - } + var fileInfo = _savePackage.Files.FirstOrDefault(p => p.Name.Equals(path, StringComparison.OrdinalIgnoreCase)) + ?? throw new ArgumentException($"Could not locate file in package: '{path}'"); - return resource; + using var rsrcStream = fileInfo.CreateContentReader(); + using var rsrcReader = new LSFReader(rsrcStream); + return rsrcReader.Read(); } private void DumpMods(string outputPath) { - using (var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read)) - using (var writer = new StreamWriter(outputStream)) + ArgumentNullException.ThrowIfNull(_saveMeta); + + using var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read); + using var writer = new StreamWriter(outputStream); + + if (!_saveMeta.Regions.TryGetValue("MetaData", out var metaRegion)) return; + if (!metaRegion.Children.TryGetValue("MetaData", out var metaChildrenList) || metaChildrenList.Count == 0) return; + + var meta = metaChildrenList[0]; + if (!meta.Children.TryGetValue("ModuleSettings", out var settingsList) || settingsList.Count == 0) return; + if (!settingsList[0].Children.TryGetValue("Mods", out var modsList) || modsList.Count == 0) return; + if (!modsList[0].Children.TryGetValue("ModuleShortDesc", out var moduleDescs)) return; + + foreach (var modDesc in moduleDescs) { - var meta = SaveMeta.Regions["MetaData"].Children["MetaData"][0]; - var moduleDescs = meta.Children["ModuleSettings"][0].Children["Mods"][0].Children["ModuleShortDesc"]; - foreach (var modDesc in moduleDescs) - { - var folder = (string)modDesc.Attributes["Folder"].Value; - var name = (string)modDesc.Attributes["Name"].Value; - PackedVersion version; - if (modDesc.Attributes.ContainsKey("Version64")) - { - var versionNum = (Int64)modDesc.Attributes["Version64"].Value; - version = PackedVersion.FromInt64(versionNum); - } - else - { - var versionNum = (Int32)modDesc.Attributes["Version"].Value; - version = PackedVersion.FromInt32(versionNum); - } + string folder = modDesc.Attributes.TryGetValue("Folder", out var fAttr) && fAttr.Value is string folderName ? folderName : string.Empty; + string name = modDesc.Attributes.TryGetValue("Name", out var nAttr) && nAttr.Value is string modName ? modName : string.Empty; - writer.WriteLine($"{name} (v{version.Major}.{version.Minor}.{version.Revision}.{version.Build}) @ {folder}"); - } + var version = modDesc.Attributes.TryGetValue("Version64", out var v64) && v64.Value is long packed64 + ? PackedVersion.FromInt64(packed64) + : (modDesc.Attributes.TryGetValue("Version", out var v32) && v32.Value is int packed32 + ? PackedVersion.FromInt32(packed32) + : PackedVersion.FromInt32(0)); + + writer.WriteLine($"{name} (v{version.Major}.{version.Minor}.{version.Revision}.{version.Build}) @ {folder}"); } } private void DumpVariables(string outputPath, bool globals, bool characters, bool items) { - using (var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - var varDumper = new VariableDumper(outputStream); - varDumper.IncludeDeletedVars = IncludeDeletedVars; - varDumper.IncludeLocalScopes = IncludeLocalScopes; - if (varDumper.Load(SaveGlobals)) - { - if (globals) - { - varDumper.DumpGlobals(); - } + ArgumentNullException.ThrowIfNull(_saveGlobals); - if (characters) - { - varDumper.DumpCharacters(); - } + using var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read); + var varDumper = new VariableDumper(outputStream) + { + IncludeDeletedVars = IncludeDeletedVars, + IncludeLocalScopes = IncludeLocalScopes + }; - if (items) - { - varDumper.DumpItems(); - } - } + if (varDumper.Load(_saveGlobals)) + { + if (globals) varDumper.DumpGlobals(); + if (characters) varDumper.DumpCharacters(); + if (items) varDumper.DumpItems(); } } private void DumpGoals() { + ArgumentNullException.ThrowIfNull(_saveStory); + ReportProgress(80, "Dumping story ..."); string debugPath = Path.Combine(DataDumpPath, "GoalsDebug.log"); using (var debugFile = new FileStream(debugPath, FileMode.Create, FileAccess.Write)) using (var writer = new StreamWriter(debugFile)) { - SaveStory.DebugDump(writer); + _saveStory.DebugDump(writer); } ReportProgress(85, "Dumping story goals ..."); @@ -179,132 +172,139 @@ private void DumpGoals() using (var goalFile = new FileStream(unassignedPath, FileMode.Create, FileAccess.Write)) using (var writer = new StreamWriter(goalFile)) { - var dummyGoal = new Goal(SaveStory) + var dummyGoal = new Goal(_saveStory) { - ExitCalls = new List(), - InitCalls = new List(), - ParentGoals = new List(), - SubGoals = new List(), + ExitCalls = [], + InitCalls = [], + ParentGoals = [], + SubGoals = [], Name = "UNASSIGNED_RULES", Index = 0 }; - dummyGoal.MakeScript(writer, SaveStory); + dummyGoal.MakeScript(writer, _saveStory); } - foreach (KeyValuePair goal in SaveStory.Goals) + foreach (var goalEntry in _saveStory.Goals) { - string filePath = Path.Combine(goalsPath, $"{goal.Value.Name}.txt"); - using (var goalFile = new FileStream(filePath, FileMode.Create, FileAccess.Write)) - using (var writer = new StreamWriter(goalFile)) - { - goal.Value.MakeScript(writer, SaveStory); - } + var goal = goalEntry.Value; + string filePath = Path.Combine(goalsPath, $"{goal.Name}.txt"); + using var goalFile = new FileStream(filePath, FileMode.Create, FileAccess.Write); + using var writer = new StreamWriter(goalFile); + goal.MakeScript(writer, _saveStory); } } private void RunTasks() { - if (ExtractAll) - { - DoExtractPackage(); - } + ArgumentNullException.ThrowIfNull(_savePackage); - if (ConvertToLsx) - { - DoLsxConversion(); - } + if (ExtractAll) DoExtractPackage(); + if (ConvertToLsx) DoLsxConversion(); FileManager.TryToCreateDirectory(Path.Combine(DataDumpPath, "Dummy")); ReportProgress(50, "Loading meta.lsf ..."); - SaveMeta = LoadPackagedResource("meta.lsf"); + _saveMeta = LoadPackagedResource("meta.lsf"); ReportProgress(52, "Loading globals.lsf ..."); - SaveGlobals = LoadPackagedResource("globals.lsf"); + _saveGlobals = LoadPackagedResource("globals.lsf"); - ReportProgress(60, "Dumping mod list ..."); if (DumpModList) { - var modListPath = Path.Combine(DataDumpPath, "ModList.txt"); - DumpMods(modListPath); + ReportProgress(60, "Dumping mod list ..."); + DumpMods(Path.Combine(DataDumpPath, "ModList.txt")); } ReportProgress(62, "Dumping variables ..."); - if (DumpGlobalVars) - { - var varsPath = Path.Combine(DataDumpPath, "GlobalVars.txt"); - DumpVariables(varsPath, true, false, false); - } - - if (DumpCharacterVars) - { - var varsPath = Path.Combine(DataDumpPath, "CharacterVars.txt"); - DumpVariables(varsPath, false, true, false); - } - - if (DumpItemVars) - { - var varsPath = Path.Combine(DataDumpPath, "ItemVars.txt"); - DumpVariables(varsPath, false, false, true); - } + if (DumpGlobalVars) DumpVariables(Path.Combine(DataDumpPath, "GlobalVars.txt"), true, false, false); + if (DumpCharacterVars) DumpVariables(Path.Combine(DataDumpPath, "CharacterVars.txt"), false, true, false); + if (DumpItemVars) DumpVariables(Path.Combine(DataDumpPath, "ItemVars.txt"), false, false, true); ReportProgress(70, "Loading story ..."); - var storySave = SavePackage.Files.FirstOrDefault(p => p.Name == "StorySave.bin"); - Stream storyStream; + var storySave = _savePackage.Files.FirstOrDefault(p => p.Name.Equals("StorySave.bin", StringComparison.OrdinalIgnoreCase)); + + using var storyStream = new MemoryStream(); if (storySave != null) { - var bin = storySave.CreateContentReader(); - storyStream = new MemoryStream(); + using var bin = storySave.CreateContentReader(); bin.CopyTo(storyStream); - storyStream.Position = 0; } else { - LSLib.LS.Node storyNode = SaveGlobals.Regions["Story"].Children["Story"][0]; - storyStream = new MemoryStream(storyNode.Attributes["Story"].Value as byte[]); - } - - var reader = new StoryReader(); - SaveStory = reader.Read(storyStream); - - if (DumpStoryGoals) - { - DumpGoals(); - } - - if (DumpStoryDatabases) - { - ReportProgress(90, "Dumping databases ..."); - var dbDumpPath = Path.Combine(DataDumpPath, "Databases.txt"); - using (var dbDumpStream = new FileStream(dbDumpPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + if (_saveGlobals.Regions.TryGetValue("Story", out var storyRegion) && + storyRegion.Children.TryGetValue("Story", out var storyChildrenList) && +storyChildrenList.Count > 0) { - var dbDumper = new DatabaseDumper(dbDumpStream); - dbDumper.DumpUnnamedDbs = IncludeUnnamedDatabases; - dbDumper.DumpAll(SaveStory); + var storyNode = storyChildrenList[0]; + if (storyNode.Attributes.TryGetValue("Story", out var storyAttr) && storyAttr.Value is byte[] byteData) + { + storyStream.Write(byteData, 0, byteData.Length); + } + else + { + throw new InvalidDataException("Story element stream attribute could not be extracted or was not a valid byte array."); + } + } + else + { + throw new InvalidDataException("The specified globals resource does not contain an active Story save node tree."); } } - - ReportProgress(100, ""); + storyStream.Position = 0; + _saveStory = StoryReader.Read(storyStream); + if (DumpStoryGoals) DumpGoals(); + if (DumpStoryDatabases) DumpStoryDatabasesTask(); + ReportProgress(100, "Done"); + TaskDiagnostics.Add(new Diagnostic(null, MessageLevel.Info, "SUCCESS", "All requested data blocks dumped completely.")); } - - public void Run() + private void DumpStoryDatabasesTask() { - ReportProgress(0, "Reading package ..."); - - var packageReader = new PackageReader(); - using var savePackage = packageReader.Read(SaveFilePath); - - SavePackage = savePackage; - var abstractFileInfo = SavePackage.Files.FirstOrDefault(p => p.Name.ToLowerInvariant() == "globals.lsf"); - if (abstractFileInfo == null) + ArgumentNullException.ThrowIfNull(_saveStory); + ReportProgress(90, "Dumping databases ..."); + var dbDumpPath = Path.Combine(DataDumpPath, "Databases.txt"); + using var dbDumpStream = new FileStream(dbDumpPath, FileMode.Create, FileAccess.Write, FileShare.Read); + var dbDumper = new DatabaseDumper(dbDumpStream) + { + DumpUnnamedDbs = IncludeUnnamedDatabases + }; + dbDumper.DumpAll(_saveStory); + } + public async Task RunAsync() + { + TaskDiagnostics.Clear(); + if (string.IsNullOrWhiteSpace(SaveFilePath) || !File.Exists(SaveFilePath)) { - MessageBox.Show("The specified package is not a valid savegame (globals.lsf not found)", "Load Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + ReportProgress(0, "Execution Aborted: Source package target is blank or inaccessible."); + TaskDiagnostics.Add(new Diagnostic(null, MessageLevel.Error, "FILE01", "The specified archive path is null or target file does not exist.")); return; } - - RunTasks(); - SavePackage = null; - - MessageBox.Show($"Savegame dumped to {DataDumpPath}."); + ReportProgress(0, "Reading package metadata structure components..."); + await Task.Run(() => + { + var packageReader = new PackageReader(); + try + { + _savePackage = packageReader.Read(SaveFilePath); + bool hasGlobals = _savePackage.Files.Any(p => p.Name.Equals("globals.lsf", StringComparison.OrdinalIgnoreCase)); + if (!hasGlobals) + { + throw new InvalidDataException("The specified package is not a valid savegame (globals.lsf not found)."); + } + RunTasks(); + } + catch (Exception ex) + { + ReportProgress(0, $"Processing Interrupted: {ex.Message}"); + TaskDiagnostics.Add(new Diagnostic(null, MessageLevel.Error, "CRIT01", ex.Message)); + } + finally + { + _savePackage?.Dispose(); + _savePackage = null; + _saveMeta = null; + _saveGlobals = null; + _saveStory = null; + } + }); } -} +} \ No newline at end of file diff --git a/ConverterApp/DebugPane.Designer.cs b/ConverterApp/DebugPane.Designer.cs deleted file mode 100644 index 05283a2d..00000000 --- a/ConverterApp/DebugPane.Designer.cs +++ /dev/null @@ -1,315 +0,0 @@ -namespace ConverterApp -{ - partial class DebugPane - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.dumpVariablesBtn = new System.Windows.Forms.Button(); - this.saveFilePath = new System.Windows.Forms.TextBox(); - this.savePathLbl = new System.Windows.Forms.Label(); - this.saveFileBrowseBtn = new System.Windows.Forms.Button(); - this.savePathDlg = new System.Windows.Forms.OpenFileDialog(); - this.dumpGlobalVars = new System.Windows.Forms.CheckBox(); - this.variableDumperBox = new System.Windows.Forms.GroupBox(); - this.includeLocalScopes = new System.Windows.Forms.CheckBox(); - this.includeUnnamedDbs = new System.Windows.Forms.CheckBox(); - this.dumpDatabases = new System.Windows.Forms.CheckBox(); - this.includeDeleted = new System.Windows.Forms.CheckBox(); - this.dumpItemVars = new System.Windows.Forms.CheckBox(); - this.dumpCharacterVars = new System.Windows.Forms.CheckBox(); - this.lblProgressStatus = new System.Windows.Forms.Label(); - this.dumpProgressBar = new System.Windows.Forms.ProgressBar(); - this.lblProgressText = new System.Windows.Forms.Label(); - this.dumpGoals = new System.Windows.Forms.CheckBox(); - this.extractPackage = new System.Windows.Forms.CheckBox(); - this.exportModList = new System.Windows.Forms.CheckBox(); - this.convertLsf = new System.Windows.Forms.CheckBox(); - this.variableDumperBox.SuspendLayout(); - this.SuspendLayout(); - // - // dumpVariablesBtn - // - this.dumpVariablesBtn.Location = new System.Drawing.Point(234, 111); - this.dumpVariablesBtn.Name = "dumpVariablesBtn"; - this.dumpVariablesBtn.Size = new System.Drawing.Size(174, 23); - this.dumpVariablesBtn.TabIndex = 72; - this.dumpVariablesBtn.Text = "Dump savegame"; - this.dumpVariablesBtn.UseVisualStyleBackColor = true; - this.dumpVariablesBtn.Click += new System.EventHandler(this.dumpVariablesBtn_Click); - // - // saveFilePath - // - this.saveFilePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.saveFilePath.Location = new System.Drawing.Point(13, 29); - this.saveFilePath.Name = "saveFilePath"; - this.saveFilePath.Size = new System.Drawing.Size(777, 20); - this.saveFilePath.TabIndex = 74; - // - // savePathLbl - // - this.savePathLbl.AutoSize = true; - this.savePathLbl.Location = new System.Drawing.Point(10, 13); - this.savePathLbl.Name = "savePathLbl"; - this.savePathLbl.Size = new System.Drawing.Size(101, 13); - this.savePathLbl.TabIndex = 73; - this.savePathLbl.Text = "Savegame file path:"; - // - // saveFileBrowseBtn - // - this.saveFileBrowseBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.saveFileBrowseBtn.Location = new System.Drawing.Point(796, 28); - this.saveFileBrowseBtn.Name = "saveFileBrowseBtn"; - this.saveFileBrowseBtn.Size = new System.Drawing.Size(41, 22); - this.saveFileBrowseBtn.TabIndex = 75; - this.saveFileBrowseBtn.Text = "..."; - this.saveFileBrowseBtn.UseVisualStyleBackColor = true; - this.saveFileBrowseBtn.Click += new System.EventHandler(this.saveFileBrowseBtn_Click); - // - // savePathDlg - // - this.savePathDlg.Filter = "LS savegame files|*.lsv"; - // - // dumpGlobalVars - // - this.dumpGlobalVars.AutoSize = true; - this.dumpGlobalVars.Checked = true; - this.dumpGlobalVars.CheckState = System.Windows.Forms.CheckState.Checked; - this.dumpGlobalVars.Location = new System.Drawing.Point(16, 25); - this.dumpGlobalVars.Name = "dumpGlobalVars"; - this.dumpGlobalVars.Size = new System.Drawing.Size(133, 17); - this.dumpGlobalVars.TabIndex = 77; - this.dumpGlobalVars.Text = "Dump global variables "; - this.dumpGlobalVars.UseVisualStyleBackColor = true; - // - // variableDumperBox - // - this.variableDumperBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.variableDumperBox.Controls.Add(this.extractPackage); - this.variableDumperBox.Controls.Add(this.exportModList); - this.variableDumperBox.Controls.Add(this.convertLsf); - this.variableDumperBox.Controls.Add(this.dumpGoals); - this.variableDumperBox.Controls.Add(this.includeLocalScopes); - this.variableDumperBox.Controls.Add(this.includeUnnamedDbs); - this.variableDumperBox.Controls.Add(this.dumpDatabases); - this.variableDumperBox.Controls.Add(this.includeDeleted); - this.variableDumperBox.Controls.Add(this.dumpItemVars); - this.variableDumperBox.Controls.Add(this.dumpCharacterVars); - this.variableDumperBox.Controls.Add(this.dumpVariablesBtn); - this.variableDumperBox.Controls.Add(this.dumpGlobalVars); - this.variableDumperBox.Location = new System.Drawing.Point(13, 68); - this.variableDumperBox.Name = "variableDumperBox"; - this.variableDumperBox.Size = new System.Drawing.Size(824, 149); - this.variableDumperBox.TabIndex = 78; - this.variableDumperBox.TabStop = false; - this.variableDumperBox.Text = "Dump Settings"; - // - // includeLocalScopes - // - this.includeLocalScopes.AutoSize = true; - this.includeLocalScopes.Location = new System.Drawing.Point(16, 117); - this.includeLocalScopes.Name = "includeLocalScopes"; - this.includeLocalScopes.Size = new System.Drawing.Size(123, 17); - this.includeLocalScopes.TabIndex = 83; - this.includeLocalScopes.Text = "Include local scopes"; - this.includeLocalScopes.UseVisualStyleBackColor = true; - // - // includeUnnamedDbs - // - this.includeUnnamedDbs.AutoSize = true; - this.includeUnnamedDbs.Location = new System.Drawing.Point(235, 71); - this.includeUnnamedDbs.Name = "includeUnnamedDbs"; - this.includeUnnamedDbs.Size = new System.Drawing.Size(173, 17); - this.includeUnnamedDbs.TabIndex = 82; - this.includeUnnamedDbs.Text = "Include intermediate databases"; - this.includeUnnamedDbs.UseVisualStyleBackColor = true; - // - // dumpDatabases - // - this.dumpDatabases.AutoSize = true; - this.dumpDatabases.Checked = true; - this.dumpDatabases.CheckState = System.Windows.Forms.CheckState.Checked; - this.dumpDatabases.Location = new System.Drawing.Point(235, 48); - this.dumpDatabases.Name = "dumpDatabases"; - this.dumpDatabases.Size = new System.Drawing.Size(106, 17); - this.dumpDatabases.TabIndex = 81; - this.dumpDatabases.Text = "Dump databases"; - this.dumpDatabases.UseVisualStyleBackColor = true; - // - // includeDeleted - // - this.includeDeleted.AutoSize = true; - this.includeDeleted.Location = new System.Drawing.Point(16, 94); - this.includeDeleted.Name = "includeDeleted"; - this.includeDeleted.Size = new System.Drawing.Size(133, 17); - this.includeDeleted.TabIndex = 80; - this.includeDeleted.Text = "Include deleted entries"; - this.includeDeleted.UseVisualStyleBackColor = true; - // - // dumpItemVars - // - this.dumpItemVars.AutoSize = true; - this.dumpItemVars.Checked = true; - this.dumpItemVars.CheckState = System.Windows.Forms.CheckState.Checked; - this.dumpItemVars.Location = new System.Drawing.Point(16, 71); - this.dumpItemVars.Name = "dumpItemVars"; - this.dumpItemVars.Size = new System.Drawing.Size(124, 17); - this.dumpItemVars.TabIndex = 79; - this.dumpItemVars.Text = "Dump item variables "; - this.dumpItemVars.UseVisualStyleBackColor = true; - // - // dumpCharacterVars - // - this.dumpCharacterVars.AutoSize = true; - this.dumpCharacterVars.Checked = true; - this.dumpCharacterVars.CheckState = System.Windows.Forms.CheckState.Checked; - this.dumpCharacterVars.Location = new System.Drawing.Point(16, 48); - this.dumpCharacterVars.Name = "dumpCharacterVars"; - this.dumpCharacterVars.Size = new System.Drawing.Size(150, 17); - this.dumpCharacterVars.TabIndex = 78; - this.dumpCharacterVars.Text = "Dump character variables "; - this.dumpCharacterVars.UseVisualStyleBackColor = true; - // - // lblProgressStatus - // - this.lblProgressStatus.AutoSize = true; - this.lblProgressStatus.Location = new System.Drawing.Point(77, 231); - this.lblProgressStatus.Name = "lblProgressStatus"; - this.lblProgressStatus.Size = new System.Drawing.Size(0, 13); - this.lblProgressStatus.TabIndex = 81; - // - // dumpProgressBar - // - this.dumpProgressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.dumpProgressBar.Location = new System.Drawing.Point(13, 247); - this.dumpProgressBar.Name = "dumpProgressBar"; - this.dumpProgressBar.Size = new System.Drawing.Size(824, 23); - this.dumpProgressBar.TabIndex = 79; - // - // lblProgressText - // - this.lblProgressText.AutoSize = true; - this.lblProgressText.Location = new System.Drawing.Point(10, 231); - this.lblProgressText.Name = "lblProgressText"; - this.lblProgressText.Size = new System.Drawing.Size(51, 13); - this.lblProgressText.TabIndex = 80; - this.lblProgressText.Text = "Progress:"; - // - // dumpGoals - // - this.dumpGoals.AutoSize = true; - this.dumpGoals.Checked = true; - this.dumpGoals.CheckState = System.Windows.Forms.CheckState.Checked; - this.dumpGoals.Location = new System.Drawing.Point(235, 25); - this.dumpGoals.Name = "dumpGoals"; - this.dumpGoals.Size = new System.Drawing.Size(82, 17); - this.dumpGoals.TabIndex = 84; - this.dumpGoals.Text = "Dump goals"; - this.dumpGoals.UseVisualStyleBackColor = true; - // - // extractPackage - // - this.extractPackage.AutoSize = true; - this.extractPackage.Checked = true; - this.extractPackage.CheckState = System.Windows.Forms.CheckState.Checked; - this.extractPackage.Location = new System.Drawing.Point(443, 25); - this.extractPackage.Name = "extractPackage"; - this.extractPackage.Size = new System.Drawing.Size(111, 17); - this.extractPackage.TabIndex = 87; - this.extractPackage.Text = "Extract savegame"; - this.extractPackage.UseVisualStyleBackColor = true; - // - // exportModList - // - this.exportModList.AutoSize = true; - this.exportModList.Checked = true; - this.exportModList.CheckState = System.Windows.Forms.CheckState.Checked; - this.exportModList.Location = new System.Drawing.Point(443, 71); - this.exportModList.Name = "exportModList"; - this.exportModList.Size = new System.Drawing.Size(94, 17); - this.exportModList.TabIndex = 86; - this.exportModList.Text = "Export mod list"; - this.exportModList.UseVisualStyleBackColor = true; - // - // convertLsf - // - this.convertLsf.AutoSize = true; - this.convertLsf.Checked = true; - this.convertLsf.CheckState = System.Windows.Forms.CheckState.Checked; - this.convertLsf.Location = new System.Drawing.Point(443, 48); - this.convertLsf.Name = "convertLsf"; - this.convertLsf.Size = new System.Drawing.Size(125, 17); - this.convertLsf.TabIndex = 85; - this.convertLsf.Text = "Convert LSFs to LSX"; - this.convertLsf.UseVisualStyleBackColor = true; - // - // DebugPane - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.lblProgressStatus); - this.Controls.Add(this.dumpProgressBar); - this.Controls.Add(this.lblProgressText); - this.Controls.Add(this.variableDumperBox); - this.Controls.Add(this.saveFilePath); - this.Controls.Add(this.savePathLbl); - this.Controls.Add(this.saveFileBrowseBtn); - this.Name = "DebugPane"; - this.Size = new System.Drawing.Size(856, 475); - this.variableDumperBox.ResumeLayout(false); - this.variableDumperBox.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button dumpVariablesBtn; - private System.Windows.Forms.TextBox saveFilePath; - private System.Windows.Forms.Label savePathLbl; - private System.Windows.Forms.Button saveFileBrowseBtn; - private System.Windows.Forms.OpenFileDialog savePathDlg; - private System.Windows.Forms.CheckBox dumpGlobalVars; - private System.Windows.Forms.GroupBox variableDumperBox; - private System.Windows.Forms.CheckBox includeUnnamedDbs; - private System.Windows.Forms.CheckBox dumpDatabases; - private System.Windows.Forms.CheckBox includeDeleted; - private System.Windows.Forms.CheckBox dumpItemVars; - private System.Windows.Forms.CheckBox dumpCharacterVars; - private System.Windows.Forms.CheckBox includeLocalScopes; - private System.Windows.Forms.Label lblProgressStatus; - private System.Windows.Forms.ProgressBar dumpProgressBar; - private System.Windows.Forms.Label lblProgressText; - private System.Windows.Forms.CheckBox extractPackage; - private System.Windows.Forms.CheckBox exportModList; - private System.Windows.Forms.CheckBox convertLsf; - private System.Windows.Forms.CheckBox dumpGoals; - } -} diff --git a/ConverterApp/DebugPane.axaml b/ConverterApp/DebugPane.axaml new file mode 100644 index 00000000..2856506c --- /dev/null +++ b/ConverterApp/DebugPane.axaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConverterApp/LocalizationPane.axaml.cs b/ConverterApp/LocalizationPane.axaml.cs new file mode 100644 index 00000000..93c5a65d --- /dev/null +++ b/ConverterApp/LocalizationPane.axaml.cs @@ -0,0 +1,157 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Platform.Storage; +using Avalonia.Threading; // Required for safe UI thread updates +using LSLib.LS; +using LSLib.LS.Enums; +using ReactiveUI; +using ReactiveUI.Avalonia; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; // Required for ObservableCollection +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reactive; +using System.Threading.Tasks; + +namespace LSTools.DivineGUI; + +public class LocalizationEntryItem +{ + public string Key { get; set; } = string.Empty; + public string Version { get; set; } = string.Empty; + public string Value { get; set; } = string.Empty; +} + +public partial class LocalizationPane : ReactiveUserControl, IGameSettingsTarget, INotifyPropertyChanged +{ + private Game _targetGameVersion = Game.BaldursGate3; + + public ObservableCollection LocalizationEntries { get; } = []; + + public string LocaInputPath { get; set { if (field != value) { field = value; InvokeLocalProperty(nameof(LocaInputPath)); } } } = string.Empty; + public string LocaOutputPath { get; set { if (field != value) { field = value; InvokeLocalProperty(nameof(LocaOutputPath)); } } } = string.Empty; + + public string ProgressText { get; set { if (field != value) { field = value; InvokeLocalProperty(nameof(ProgressText)); } } } = string.Empty; + + public ReactiveCommand BrowseInputLocationCommand { get; } + public ReactiveCommand BrowseOutputLocationCommand { get; } + public ReactiveCommand ConvertLocalizationCommand { get; } + + private static readonly FilePickerFileType LocaFileTypes = new("Localization files") + { + Patterns = ["*.loca", "*.xml"] + }; + + public LocalizationPane() + { + InitializeComponent(); + DataContext = this; + ViewModel = this; + + BrowseInputLocationCommand = ReactiveCommand.CreateFromTask(BrowseInputLocationAsync); + BrowseOutputLocationCommand = ReactiveCommand.CreateFromTask(BrowseOutputLocationAsync); + ConvertLocalizationCommand = ReactiveCommand.CreateFromTask(ExecuteLocalizationConversionAsync); + } + + private void InitializeComponent() => AvaloniaXamlLoader.Load(this); + + public void SetGame(Game game) + { + _targetGameVersion = game; + } + + private async Task BrowseInputLocationAsync() + { + var provider = TopLevel.GetTopLevel(this)?.StorageProvider; + if (provider is null) return; + + var files = await provider.OpenFilePickerAsync(new() + { + Title = "Select Input File", + AllowMultiple = false, + FileTypeFilter = [LocaFileTypes] + }); + + if (files.Count > 0) LocaInputPath = files[0].Path.LocalPath; + } + + private async Task BrowseOutputLocationAsync() + { + var provider = TopLevel.GetTopLevel(this)?.StorageProvider; + if (provider is null) return; + + var file = await provider.SaveFilePickerAsync(new() + { + Title = "Select Output File", + FileTypeChoices = [LocaFileTypes], + DefaultExtension = "loca" + }); + + if (file is not null) LocaOutputPath = file.Path.LocalPath; + } + + private async Task ExecuteLocalizationConversionAsync() + { + if (string.IsNullOrWhiteSpace(LocaInputPath) || !File.Exists(LocaInputPath)) return; + if (string.IsNullOrWhiteSpace(LocaOutputPath)) return; + + ProgressText = "Parsing and translating localization parameters..."; + Dispatcher.UIThread.Post(() => LocalizationEntries.Clear()); + + try + { + string input = LocaInputPath; + string output = LocaOutputPath; + + await Task.Run(() => + { + var resource = LocaUtils.Load(input); + var format = LocaUtils.ExtensionToFileFormat(output); + LocaUtils.Save(resource, output, format); + + if (resource != null) + { + var parsedGridItems = new List(); + + foreach (var entry in resource.Entries) + { + parsedGridItems.Add(new LocalizationEntryItem + { + Key = entry.Key ?? string.Empty, + Version = entry.Version.ToString(), + Value = entry.Text ?? string.Empty + }); + } + Dispatcher.UIThread.Post(() => + { + foreach (var item in parsedGridItems) + { + LocalizationEntries.Add(item); + } + }); + } + }); + + ProgressText = "Localization file converted and saved successfully."; + } + catch (Exception exc) + { + ProgressText = $"Conversion Failed!\n\nInternal error:\n{exc.Message}"; + } + } + + private PropertyChangedEventHandler? _localPropertyChanged; + + event PropertyChangedEventHandler? INotifyPropertyChanged.PropertyChanged + { + add => _localPropertyChanged += value; + remove => _localPropertyChanged -= value; + } + + private void InvokeLocalProperty(string propertyName) + { + _localPropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} diff --git a/ConverterApp/LocalizationPane.cs b/ConverterApp/LocalizationPane.cs deleted file mode 100644 index ce72948a..00000000 --- a/ConverterApp/LocalizationPane.cs +++ /dev/null @@ -1,55 +0,0 @@ -using LSLib.LS.Enums; -using LSLib.LS; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace ConverterApp -{ - public partial class LocalizationPane : UserControl - { - public LocalizationPane() - { - InitializeComponent(); - } - - private void resourceInputBrowseBtn_Click(object sender, EventArgs e) - { - if (locaInputFileDlg.ShowDialog(this) == DialogResult.OK) - { - locaInputPath.Text = locaInputFileDlg.FileName; - } - } - - private void locaOutputBrowseBtn_Click(object sender, EventArgs e) - { - if (locaOutputFileDlg.ShowDialog(this) == DialogResult.OK) - { - locaOutputPath.Text = locaOutputFileDlg.FileName; - } - } - - private void locaConvertBtn_Click(object sender, EventArgs e) - { - try - { - var resource = LocaUtils.Load(locaInputPath.Text); - var format = LocaUtils.ExtensionToFileFormat(locaOutputPath.Text); - LocaUtils.Save(resource, locaOutputPath.Text, format); - - MessageBox.Show("Localization file saved successfully."); - } - catch (Exception exc) - { - MessageBox.Show($"Internal error!{Environment.NewLine}{Environment.NewLine}{exc}", "Conversion Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); - - } - } - } -} diff --git a/ConverterApp/LocalizationPane.resx b/ConverterApp/LocalizationPane.resx deleted file mode 100644 index 41c8e0bf..00000000 --- a/ConverterApp/LocalizationPane.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 572, 59 - - - 770, 54 - - \ No newline at end of file diff --git a/ConverterApp/MainForm.Designer.cs b/ConverterApp/MainForm.Designer.cs deleted file mode 100644 index 6d09e9af..00000000 --- a/ConverterApp/MainForm.Designer.cs +++ /dev/null @@ -1,194 +0,0 @@ -namespace ConverterApp -{ - sealed partial class MainForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.tabControl = new System.Windows.Forms.TabControl(); - this.gr2Tab = new System.Windows.Forms.TabPage(); - this.packageTab = new System.Windows.Forms.TabPage(); - this.resourceTab = new System.Windows.Forms.TabPage(); - this.virtualTextureTab = new System.Windows.Forms.TabPage(); - this.osirisTab = new System.Windows.Forms.TabPage(); - this.debugTab = new System.Windows.Forms.TabPage(); - this.gr2Game = new System.Windows.Forms.ComboBox(); - this.label7 = new System.Windows.Forms.Label(); - this.locaTab = new System.Windows.Forms.TabPage(); - this.tabControl.SuspendLayout(); - this.SuspendLayout(); - // - // tabControl - // - this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tabControl.Controls.Add(this.gr2Tab); - this.tabControl.Controls.Add(this.packageTab); - this.tabControl.Controls.Add(this.resourceTab); - this.tabControl.Controls.Add(this.virtualTextureTab); - this.tabControl.Controls.Add(this.locaTab); - this.tabControl.Controls.Add(this.osirisTab); - this.tabControl.Controls.Add(this.debugTab); - this.tabControl.Location = new System.Drawing.Point(16, 52); - this.tabControl.Margin = new System.Windows.Forms.Padding(4); - this.tabControl.Name = "tabControl"; - this.tabControl.SelectedIndex = 0; - this.tabControl.Size = new System.Drawing.Size(1223, 763); - this.tabControl.TabIndex = 0; - // - // gr2Tab - // - this.gr2Tab.Location = new System.Drawing.Point(4, 25); - this.gr2Tab.Margin = new System.Windows.Forms.Padding(4); - this.gr2Tab.Name = "gr2Tab"; - this.gr2Tab.Padding = new System.Windows.Forms.Padding(4); - this.gr2Tab.Size = new System.Drawing.Size(1215, 734); - this.gr2Tab.TabIndex = 0; - this.gr2Tab.Text = "GR2 Tools"; - this.gr2Tab.UseVisualStyleBackColor = true; - // - // packageTab - // - this.packageTab.Location = new System.Drawing.Point(4, 25); - this.packageTab.Margin = new System.Windows.Forms.Padding(4); - this.packageTab.Name = "packageTab"; - this.packageTab.Padding = new System.Windows.Forms.Padding(4); - this.packageTab.Size = new System.Drawing.Size(1215, 734); - this.packageTab.TabIndex = 1; - this.packageTab.Text = "PAK / LSV Tools"; - this.packageTab.UseVisualStyleBackColor = true; - // - // resourceTab - // - this.resourceTab.Location = new System.Drawing.Point(4, 25); - this.resourceTab.Margin = new System.Windows.Forms.Padding(4); - this.resourceTab.Name = "resourceTab"; - this.resourceTab.Padding = new System.Windows.Forms.Padding(4); - this.resourceTab.Size = new System.Drawing.Size(1215, 734); - this.resourceTab.TabIndex = 2; - this.resourceTab.Text = "LSX / LSB / LSF / LSJ Tools"; - this.resourceTab.UseVisualStyleBackColor = true; - // - // virtualTextureTab - // - this.virtualTextureTab.Location = new System.Drawing.Point(4, 25); - this.virtualTextureTab.Name = "virtualTextureTab"; - this.virtualTextureTab.Padding = new System.Windows.Forms.Padding(3); - this.virtualTextureTab.Size = new System.Drawing.Size(1215, 734); - this.virtualTextureTab.TabIndex = 5; - this.virtualTextureTab.Text = "Virtual Textures"; - this.virtualTextureTab.UseVisualStyleBackColor = true; - // - // osirisTab - // - this.osirisTab.Location = new System.Drawing.Point(4, 25); - this.osirisTab.Margin = new System.Windows.Forms.Padding(4); - this.osirisTab.Name = "osirisTab"; - this.osirisTab.Padding = new System.Windows.Forms.Padding(4); - this.osirisTab.Size = new System.Drawing.Size(1215, 734); - this.osirisTab.TabIndex = 3; - this.osirisTab.Text = "Story (OSI) tools"; - this.osirisTab.UseVisualStyleBackColor = true; - // - // debugTab - // - this.debugTab.Location = new System.Drawing.Point(4, 25); - this.debugTab.Margin = new System.Windows.Forms.Padding(4); - this.debugTab.Name = "debugTab"; - this.debugTab.Size = new System.Drawing.Size(1215, 734); - this.debugTab.TabIndex = 4; - this.debugTab.Text = "Savegame Debugging"; - this.debugTab.UseVisualStyleBackColor = true; - // - // gr2Game - // - this.gr2Game.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.gr2Game.FormattingEnabled = true; - this.gr2Game.Items.AddRange(new object[] { - "Divinity: Original Sin (32-bit)", - "Divinity: Original Sin EE (64-bit)", - "Divinity: Original Sin 2 (64-bit)", - "Divinity: Original Sin 2 DE (64-bit)", - "Baldur\'s Gate 3 (64-bit)"}); - this.gr2Game.Location = new System.Drawing.Point(99, 15); - this.gr2Game.Margin = new System.Windows.Forms.Padding(4); - this.gr2Game.Name = "gr2Game"; - this.gr2Game.Size = new System.Drawing.Size(473, 24); - this.gr2Game.TabIndex = 30; - this.gr2Game.SelectedIndexChanged += new System.EventHandler(this.gr2Game_SelectedIndexChanged); - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(16, 17); - this.label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(47, 16); - this.label7.TabIndex = 29; - this.label7.Text = "Game:"; - // - // locaTab - // - this.locaTab.Location = new System.Drawing.Point(4, 25); - this.locaTab.Name = "locaTab"; - this.locaTab.Padding = new System.Windows.Forms.Padding(3); - this.locaTab.Size = new System.Drawing.Size(1215, 734); - this.locaTab.TabIndex = 6; - this.locaTab.Text = "Localization"; - this.locaTab.UseVisualStyleBackColor = true; - // - // MainForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1255, 826); - this.Controls.Add(this.gr2Game); - this.Controls.Add(this.label7); - this.Controls.Add(this.tabControl); - this.Margin = new System.Windows.Forms.Padding(4); - this.Name = "MainForm"; - this.Text = "LSLib Toolkit"; - this.tabControl.ResumeLayout(false); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - private System.Windows.Forms.TabControl tabControl; - private System.Windows.Forms.TabPage gr2Tab; - private System.Windows.Forms.TabPage packageTab; - private System.Windows.Forms.TabPage resourceTab; - private System.Windows.Forms.TabPage virtualTextureTab; - private System.Windows.Forms.TabPage osirisTab; - private System.Windows.Forms.ComboBox gr2Game; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.TabPage debugTab; - private System.Windows.Forms.TabPage locaTab; - } -} - diff --git a/ConverterApp/MainForm.cs b/ConverterApp/MainForm.cs deleted file mode 100644 index fd173ebd..00000000 --- a/ConverterApp/MainForm.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Windows.Forms; -using LSLib.LS; -using LSLib.LS.Enums; -using Newtonsoft.Json; -using System.ComponentModel; -using System.IO; - -namespace ConverterApp -{ - public sealed partial class MainForm : Form, ISettingsDataSource - { - PackagePane packagePane; - ResourcePane resourcePane; - VirtualTexturesPane virtualTexturesPane; - LocalizationPane localizationPane; - OsirisPane osirisPane; - DebugPane debugPane; - - public ConverterAppSettings Settings { get; set; } - - public MainForm() - { - InitializeComponent(); - - Settings = new ConverterAppSettings(); - - try - { - if (File.Exists("settings.json")) - { - using (System.IO.StreamReader file = File.OpenText("settings.json")) - { - JsonSerializer serializer = new JsonSerializer(); - Settings = (ConverterAppSettings)serializer.Deserialize(file, typeof(ConverterAppSettings)); - } - } - } - catch (Exception ex) - { - MessageBox.Show($"Error reading settings: {ex.ToString()}"); - } - - var gr2Pane = new GR2Pane(this) - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = gr2Tab.ClientSize - }; - gr2Tab.Controls.Add(gr2Pane); - - packagePane = new PackagePane(this) - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = packageTab.ClientSize - }; - packageTab.Controls.Add(packagePane); - - resourcePane = new ResourcePane(this) - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = resourceTab.ClientSize - }; - resourceTab.Controls.Add(resourcePane); - - virtualTexturesPane = new VirtualTexturesPane(this) - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = resourceTab.ClientSize - }; - virtualTextureTab.Controls.Add(virtualTexturesPane); - - localizationPane = new LocalizationPane() - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = resourceTab.ClientSize - }; - locaTab.Controls.Add(localizationPane); - - osirisPane = new OsirisPane(this) - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = osirisTab.ClientSize - }; - osirisTab.Controls.Add(osirisPane); - - debugPane = new DebugPane(this) - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = debugTab.ClientSize - }; - debugTab.Controls.Add(debugPane); - - Text += $" (LSLib v{Common.LibraryVersion()})"; - - gr2Game.SelectedIndex = gr2Game.Items.Count - 1; - gr2Game.DataBindings.Add("SelectedIndex", Settings, "SelectedGame", true, DataSourceUpdateMode.OnPropertyChanged); - - Settings.Version = Common.LibraryVersion(); - Settings.SetPropertyChangedEvent(SaveSettings); - } - - private void SaveSettings(object sender, PropertyChangedEventArgs e) - { - try - { - File.WriteAllText("settings.json", JsonConvert.SerializeObject(Settings, Formatting.Indented)); - } - catch (Exception ex) - { - MessageBox.Show($"Error saving settings: {ex.ToString()}"); - } - } - - public Game GetGame() - { - switch (gr2Game.SelectedIndex) - { - case 0: return Game.DivinityOriginalSin; - case 1: return Game.DivinityOriginalSinEE; - case 2: return Game.DivinityOriginalSin2; - case 3: return Game.DivinityOriginalSin2DE; - case 4: return Game.BaldursGate3; - default: throw new InvalidOperationException(); - } - } - - private void gr2Game_SelectedIndexChanged(object sender, EventArgs e) - { - Game game = GetGame(); - if (gr2Tab.Controls[0] is GR2Pane pane) - { - pane.flipMeshes.Checked = game.IsFW3(); - } - - packagePane.SetGame(game); - osirisPane.Game = game; - debugPane.Game = game; - } - } -} diff --git a/ConverterApp/MainForm.resx b/ConverterApp/MainForm.resx deleted file mode 100644 index 1af7de15..00000000 --- a/ConverterApp/MainForm.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/ConverterApp/MainWindow.axaml b/ConverterApp/MainWindow.axaml new file mode 100644 index 00000000..75ffaf24 --- /dev/null +++ b/ConverterApp/MainWindow.axaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConverterApp/MainWindow.axaml.cs b/ConverterApp/MainWindow.axaml.cs new file mode 100644 index 00000000..1e065314 --- /dev/null +++ b/ConverterApp/MainWindow.axaml.cs @@ -0,0 +1,165 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using LSLib.LS; +using LSLib.LS.Enums; +using ReactiveUI; +using ReactiveUI.Avalonia; +using System.ComponentModel; +using System.Reactive; +using System.Reactive.Concurrency; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace LSTools.DivineGUI; + +public partial class MainWindow : ReactiveWindow, INotifyPropertyChanged +{ + public ConverterAppSettings Settings + { + get; + set + { + if (field != value) + { + field = value; + InvokeLocalProperty(nameof(Settings)); + } + } + } = null!; + + public string AppTitle + { + get; + set { if (field != value) { field = value; InvokeLocalProperty(nameof(AppTitle)); } } + } = "LSLib Toolkit"; + + public string GlobalAlertLog + { + get; + set { if (field != value) { field = value; InvokeLocalProperty(nameof(GlobalAlertLog)); } } + } = string.Empty; + + public string[] DynamicGameOptions { get; } = + [ + "Divinity: Original Sin (32-bit)", + "Divinity: Original Sin EE (64-bit)", + "Divinity: Original Sin 2 (64-bit)", + "Divinity: Original Sin 2 DE (64-bit)", + "Baldur's Gate 3 (64-bit)" + ]; + + public ReactiveCommand GameSelectionChangedCommand { get; } + + public MainWindow() + { + InitializeComponent(); + + GameSelectionChangedCommand = ReactiveCommand.Create(targetIndex => + { + if (Settings == null) return; + Settings.SelectedGame = targetIndex; + + Game mappedGame = (Game)targetIndex; + + var gr2Control = this.Find("gr2PaneControl"); + var packageControl = this.Find("packagePaneControl"); + var osirisControl = this.Find("osirisPaneControl"); + var debugControl = this.Find("debugPaneControl"); + + if (gr2Control is IGameSettingsTarget gr2Target) gr2Target.SetGame(mappedGame); + if (packageControl is IGameSettingsTarget packageTarget) packageTarget.SetGame(mappedGame); + if (osirisControl is IGameSettingsTarget osirisTarget) osirisTarget.SetGame(mappedGame); + if (debugControl is IGameSettingsTarget debugTarget) debugTarget.SetGame(mappedGame); + + gr2Control?.FlipMeshes = mappedGame.IsFW3(); + }); + } + + public MainWindow(ISettingsDataSource settingsDataSource) : this() + { + ArgumentNullException.ThrowIfNull(settingsDataSource); + Settings = settingsDataSource.Settings; + ViewModel = this; + + LoadSettingsProfile(); + + AppTitle = $"LSLib Toolkit (LSLib v{Common.LibraryVersion()})"; + Settings.Version = Common.LibraryVersion(); + + Settings.SetPropertyChangedEvent(OnSettingsProfileMutated); + + Settings.PropertyChanged += (sender, e) => + { + if (e.PropertyName == nameof(ConverterAppSettings.SelectedGame)) + { + RxSchedulers.MainThreadScheduler.Schedule(() => + { + GameSelectionChangedCommand.Execute(Settings.SelectedGame).Subscribe(); + }); + } + }; + + GameSelectionChangedCommand.Execute(Settings.SelectedGame).Subscribe(); + } + + private void InitializeComponent() => AvaloniaXamlLoader.Load(this); + + private void LoadSettingsProfile() + { + try + { + string profilePath = Path.Combine(AppContext.BaseDirectory, "settings.json"); + if (File.Exists(profilePath)) + { + byte[] jsonBytes = File.ReadAllBytes(profilePath); + + var context = new AppSettingsJsonContext(); + var resolvedProfile = JsonSerializer.Deserialize(jsonBytes, context.ConverterAppSettings); + if (resolvedProfile != null) Settings = resolvedProfile; + } + } + catch (Exception ex) + { + GlobalAlertLog = $"Failed to restore settings configuration: {ex.Message}"; + } + } + + private void OnSettingsProfileMutated(object? sender, PropertyChangedEventArgs e) + { + Task.Run(() => + { + try + { + string profilePath = Path.Combine(AppContext.BaseDirectory, "settings.json"); + var context = new AppSettingsJsonContext(); + + byte[] jsonBytes = JsonSerializer.SerializeToUtf8Bytes(Settings, context.ConverterAppSettings); + File.WriteAllBytes(profilePath, jsonBytes); + } + catch (Exception ex) + { + Dispatcher.UIThread.Post(() => + { + GlobalAlertLog = $"Failed to serialize configuration properties to file: {ex.Message}"; + }); + } + }); + } + + private PropertyChangedEventHandler? _localPropertyChanged; + + public new event PropertyChangedEventHandler? PropertyChanged + { + add => _localPropertyChanged += value; + remove => _localPropertyChanged -= value; + } + + private void InvokeLocalProperty(string propertyName) + { + _localPropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} + +[JsonSerializable(typeof(ConverterAppSettings))] +internal partial class AppSettingsJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/ConverterApp/OsirisPane.Designer.cs b/ConverterApp/OsirisPane.Designer.cs deleted file mode 100644 index a6152cf3..00000000 --- a/ConverterApp/OsirisPane.Designer.cs +++ /dev/null @@ -1,287 +0,0 @@ -namespace ConverterApp -{ - partial class OsirisPane - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.saveStoryBtn = new System.Windows.Forms.Button(); - this.groupBox3 = new System.Windows.Forms.GroupBox(); - this.databaseGrid = new System.Windows.Forms.DataGridView(); - this.databaseSelectorCb = new System.Windows.Forms.ComboBox(); - this.label18 = new System.Windows.Forms.Label(); - this.loadStoryBtn = new System.Windows.Forms.Button(); - this.decompileStoryBtn = new System.Windows.Forms.Button(); - this.storyFilePath = new System.Windows.Forms.TextBox(); - this.goalPathBrowseBtn = new System.Windows.Forms.Button(); - this.label9 = new System.Windows.Forms.Label(); - this.goalPath = new System.Windows.Forms.TextBox(); - this.storyFileBrowseBtn = new System.Windows.Forms.Button(); - this.label10 = new System.Windows.Forms.Label(); - this.storyPathDlg = new System.Windows.Forms.OpenFileDialog(); - this.goalPathDlg = new System.Windows.Forms.FolderBrowserDialog(); - this.btnDebugExport = new System.Windows.Forms.Button(); - this.lblFilter = new System.Windows.Forms.Label(); - this.tbFilter = new System.Windows.Forms.TextBox(); - this.btnFilterMatchCase = new System.Windows.Forms.Button(); - this.groupBox3.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.databaseGrid)).BeginInit(); - this.SuspendLayout(); - // - // saveStoryBtn - // - this.saveStoryBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.saveStoryBtn.Location = new System.Drawing.Point(728, 50); - this.saveStoryBtn.Name = "saveStoryBtn"; - this.saveStoryBtn.Size = new System.Drawing.Size(121, 23); - this.saveStoryBtn.TabIndex = 69; - this.saveStoryBtn.Text = "Save"; - this.saveStoryBtn.UseVisualStyleBackColor = true; - this.saveStoryBtn.Click += new System.EventHandler(this.saveStoryBtn_Click); - // - // groupBox3 - // - this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox3.Controls.Add(this.databaseGrid); - this.groupBox3.Controls.Add(this.databaseSelectorCb); - this.groupBox3.Controls.Add(this.label18); - this.groupBox3.Controls.Add(this.lblFilter); - this.groupBox3.Controls.Add(this.tbFilter); - this.groupBox3.Controls.Add(this.btnFilterMatchCase); - this.groupBox3.Location = new System.Drawing.Point(5, 147); - this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(849, 441); - this.groupBox3.TabIndex = 68; - this.groupBox3.TabStop = false; - this.groupBox3.Text = "Database Editor"; - // - // lblFilter - // - this.lblFilter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.lblFilter.AutoSize = true; - this.lblFilter.Location = new System.Drawing.Point(554, 22); - this.lblFilter.Name = "lblFilter"; - this.lblFilter.Size = new System.Drawing.Size(32, 13); - this.lblFilter.TabIndex = 4; - this.lblFilter.Text = "Filter:"; - // - // tbFilter - // - this.tbFilter.AcceptsReturn = true; - this.tbFilter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.tbFilter.Location = new System.Drawing.Point(594, 18); - this.tbFilter.Name = "tbFilter"; - this.tbFilter.Size = new System.Drawing.Size(197, 20); - this.tbFilter.TabIndex = 3; - this.tbFilter.KeyUp += new System.Windows.Forms.KeyEventHandler(this.databaseFilter_KeyUp); - // - // btnFilterMatchCase - // - this.btnFilterMatchCase.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnFilterMatchCase.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnFilterMatchCase.Location = new System.Drawing.Point(797, 17); - this.btnFilterMatchCase.Name = "btnFilterMatchCase"; - this.btnFilterMatchCase.Size = new System.Drawing.Size(41, 22); - this.btnFilterMatchCase.TabIndex = 5; - this.btnFilterMatchCase.Text = "Aa"; - this.btnFilterMatchCase.UseVisualStyleBackColor = true; - this.btnFilterMatchCase.Click += new System.EventHandler(this.btnDatabaseFilterMatchCase_Click); - // - // databaseGrid - // - this.databaseGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.databaseGrid.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.AllCells; - this.databaseGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.databaseGrid.Location = new System.Drawing.Point(9, 47); - this.databaseGrid.Name = "databaseGrid"; - this.databaseGrid.Size = new System.Drawing.Size(829, 380); - this.databaseGrid.TabIndex = 2; - // - // databaseSelectorCb - // - this.databaseSelectorCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.databaseSelectorCb.FormattingEnabled = true; - this.databaseSelectorCb.Location = new System.Drawing.Point(67, 18); - this.databaseSelectorCb.Name = "databaseSelectorCb"; - this.databaseSelectorCb.Size = new System.Drawing.Size(471, 21); - this.databaseSelectorCb.TabIndex = 1; - this.databaseSelectorCb.SelectedIndexChanged += new System.EventHandler(this.databaseSelectorCb_SelectedIndexChanged); - // - // label18 - // - this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(6, 22); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(56, 13); - this.label18.TabIndex = 0; - this.label18.Text = "Database:"; - // - // loadStoryBtn - // - this.loadStoryBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.loadStoryBtn.Location = new System.Drawing.Point(728, 21); - this.loadStoryBtn.Name = "loadStoryBtn"; - this.loadStoryBtn.Size = new System.Drawing.Size(121, 23); - this.loadStoryBtn.TabIndex = 67; - this.loadStoryBtn.Text = "Load"; - this.loadStoryBtn.UseVisualStyleBackColor = true; - this.loadStoryBtn.Click += new System.EventHandler(this.loadStoryBtn_Click); - // - // decompileStoryBtn - // - this.decompileStoryBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.decompileStoryBtn.Location = new System.Drawing.Point(728, 92); - this.decompileStoryBtn.Name = "decompileStoryBtn"; - this.decompileStoryBtn.Size = new System.Drawing.Size(121, 23); - this.decompileStoryBtn.TabIndex = 66; - this.decompileStoryBtn.Text = "Extract"; - this.decompileStoryBtn.UseVisualStyleBackColor = true; - this.decompileStoryBtn.Click += new System.EventHandler(this.decompileStoryBtn_Click); - // - // storyFilePath - // - this.storyFilePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.storyFilePath.Location = new System.Drawing.Point(7, 22); - this.storyFilePath.Name = "storyFilePath"; - this.storyFilePath.Size = new System.Drawing.Size(678, 20); - this.storyFilePath.TabIndex = 61; - // - // goalPathBrowseBtn - // - this.goalPathBrowseBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.goalPathBrowseBtn.Location = new System.Drawing.Point(683, 92); - this.goalPathBrowseBtn.Name = "goalPathBrowseBtn"; - this.goalPathBrowseBtn.Size = new System.Drawing.Size(41, 22); - this.goalPathBrowseBtn.TabIndex = 65; - this.goalPathBrowseBtn.Text = "..."; - this.goalPathBrowseBtn.UseVisualStyleBackColor = true; - this.goalPathBrowseBtn.Click += new System.EventHandler(this.goalPathBrowseBtn_Click); - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(4, 6); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(128, 13); - this.label9.TabIndex = 60; - this.label9.Text = "Story/savegame file path:"; - // - // goalPath - // - this.goalPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.goalPath.Location = new System.Drawing.Point(7, 93); - this.goalPath.Name = "goalPath"; - this.goalPath.Size = new System.Drawing.Size(678, 20); - this.goalPath.TabIndex = 64; - // - // storyFileBrowseBtn - // - this.storyFileBrowseBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.storyFileBrowseBtn.Location = new System.Drawing.Point(683, 21); - this.storyFileBrowseBtn.Name = "storyFileBrowseBtn"; - this.storyFileBrowseBtn.Size = new System.Drawing.Size(41, 22); - this.storyFileBrowseBtn.TabIndex = 62; - this.storyFileBrowseBtn.Text = "..."; - this.storyFileBrowseBtn.UseVisualStyleBackColor = true; - this.storyFileBrowseBtn.Click += new System.EventHandler(this.storyFileBrowseBtn_Click); - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(4, 77); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(89, 13); - this.label10.TabIndex = 63; - this.label10.Text = "Goal output path:"; - // - // storyPathDlg - // - this.storyPathDlg.CheckFileExists = false; - this.storyPathDlg.Filter = "LS story/savegame files|*.osi;*.lsv"; - // - // btnDebugExport - // - this.btnDebugExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnDebugExport.Location = new System.Drawing.Point(728, 121); - this.btnDebugExport.Name = "btnDebugExport"; - this.btnDebugExport.Size = new System.Drawing.Size(121, 23); - this.btnDebugExport.TabIndex = 70; - this.btnDebugExport.Text = "Debug Export"; - this.btnDebugExport.UseVisualStyleBackColor = true; - this.btnDebugExport.Click += new System.EventHandler(this.btnDebugExport_Click); - // - // OsirisPane - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.btnDebugExport); - this.Controls.Add(this.saveStoryBtn); - this.Controls.Add(this.groupBox3); - this.Controls.Add(this.loadStoryBtn); - this.Controls.Add(this.decompileStoryBtn); - this.Controls.Add(this.storyFilePath); - this.Controls.Add(this.goalPathBrowseBtn); - this.Controls.Add(this.label9); - this.Controls.Add(this.goalPath); - this.Controls.Add(this.storyFileBrowseBtn); - this.Controls.Add(this.label10); - this.Name = "OsirisPane"; - this.Size = new System.Drawing.Size(863, 588); - this.groupBox3.ResumeLayout(false); - this.groupBox3.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.databaseGrid)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button saveStoryBtn; - private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.DataGridView databaseGrid; - private System.Windows.Forms.ComboBox databaseSelectorCb; - private System.Windows.Forms.Label label18; - private System.Windows.Forms.Button loadStoryBtn; - private System.Windows.Forms.Button decompileStoryBtn; - private System.Windows.Forms.TextBox storyFilePath; - private System.Windows.Forms.Button goalPathBrowseBtn; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.TextBox goalPath; - private System.Windows.Forms.Button storyFileBrowseBtn; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.OpenFileDialog storyPathDlg; - private System.Windows.Forms.FolderBrowserDialog goalPathDlg; - private System.Windows.Forms.Button btnDebugExport; - private System.Windows.Forms.Label lblFilter; - private System.Windows.Forms.TextBox tbFilter; - private System.Windows.Forms.Button btnFilterMatchCase; - } -} diff --git a/ConverterApp/OsirisPane.axaml b/ConverterApp/OsirisPane.axaml new file mode 100644 index 00000000..0f26ad8e --- /dev/null +++ b/ConverterApp/OsirisPane.axaml @@ -0,0 +1,82 @@ + + + + + + + + + +