diff --git a/.github/workflows/dotnet-desktop.yml b/.github/workflows/dotnet-desktop.yml
index d57388a..52ad60e 100644
--- a/.github/workflows/dotnet-desktop.yml
+++ b/.github/workflows/dotnet-desktop.yml
@@ -34,10 +34,8 @@ jobs:
with:
repository: PlatinumMaster/NitroSharp
path: NitroSharp
- - run: dotnet restore SwissArmyKnife
- - run: dotnet build SwissArmyKnife --configuration Release --no-restore
+ - run: dotnet build SwissArmyKnife --configuration Release
- run: dotnet publish -c Release SwissArmyKnife
-
- name: Upload build artifacts (Windows)
if: ${{ matrix.os == 'windows-latest' }}
uses: actions/upload-artifact@v2
@@ -68,10 +66,10 @@ jobs:
filename: SAK-${{matrix.os}}-${{ env.TAG }}.zip
- name: Make release
uses: ncipollo/release-action@v1
+ if: github.ref == 'refs/heads/master'
with:
allowUpdates: true
- prerelease: true
tag: ${{ env.TAG }}
commit: ${{ github.sha }}
- name: Nightly ${{ github.sha }}
+ name: Release ${{ github.sha }}
artifacts: SAK-${{matrix.os}}-${{ env.TAG }}.zip
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 083a15d..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: csharp
-mono: none
-dotnet: 5.0.302
-solution: SwissArmyKnife.sln
-install:
- - sudo dosomething
- - nuget restore solution-name.sln
\ No newline at end of file
diff --git a/App.axaml b/App.axaml
index 057b5b2..936b369 100644
--- a/App.axaml
+++ b/App.axaml
@@ -1,12 +1,17 @@
+ xmlns:local="using:SwissArmyKnife"
+ xmlns:themes="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"
+ xmlns:avalonia="clr-namespace:SwissArmyKnife"
+ x:Class="SwissArmyKnife.App">
+
+
+
-
-
-
-
-
-
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/App.axaml.cs b/App.axaml.cs
index 09dadeb..c5a60dd 100644
--- a/App.axaml.cs
+++ b/App.axaml.cs
@@ -1,19 +1,28 @@
-using Avalonia;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Markup.Xaml;
-using SwissArmyKnife.Avalonia.Views;
-
-namespace SwissArmyKnife.Avalonia {
- public class App : Application {
- public override void Initialize() {
- AvaloniaXamlLoader.Load(this);
- }
-
- public override void OnFrameworkInitializationCompleted() {
- if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- desktop.MainWindow = new ProjectManagementWindow();
-
- base.OnFrameworkInitializationCompleted();
- }
- }
+using System.IO;
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.Handlers;
+using SwissArmyKnife.ViewModels.Main;
+using SwissArmyKnife.Views;
+
+namespace SwissArmyKnife {
+ public partial class App : Application {
+ public override void Initialize() {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted() {
+ Logging.InitializeLogger();
+ Net.Initialize();
+ Preferences.ReadPreferences(Path.Combine("Configuration", "Preferences.yml"));
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) {
+ desktop.MainWindow = new StartupWindow {
+ DataContext = new StartupViewModel()
+ };
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+ }
}
\ No newline at end of file
diff --git a/Assets/BattleCategory.png b/Assets/BattleCategory.png
new file mode 100644
index 0000000..688c8d0
Binary files /dev/null and b/Assets/BattleCategory.png differ
diff --git a/Assets/MapEditor.png b/Assets/MapEditor.png
index 7e3f5ac..060cac6 100644
Binary files a/Assets/MapEditor.png and b/Assets/MapEditor.png differ
diff --git a/Assets/sak-icon.ico b/Assets/ProgramIcon.ico
similarity index 100%
rename from Assets/sak-icon.ico
rename to Assets/ProgramIcon.ico
diff --git a/Assets/ScriptEditor.png b/Assets/ScriptEditor.png
index 35a94ac..51945ef 100644
Binary files a/Assets/ScriptEditor.png and b/Assets/ScriptEditor.png differ
diff --git a/Assets/TextEditor.png b/Assets/TextEditor.png
index 86d8ccb..2468ef5 100644
Binary files a/Assets/TextEditor.png and b/Assets/TextEditor.png differ
diff --git a/Assets/TrainerEditor.png b/Assets/TrainerEditor.png
new file mode 100644
index 0000000..8b58f82
Binary files /dev/null and b/Assets/TrainerEditor.png differ
diff --git a/Assets/WildEditor.png b/Assets/WildEditor.png
new file mode 100644
index 0000000..b02b5a3
Binary files /dev/null and b/Assets/WildEditor.png differ
diff --git a/Assets/ZoneEditor.png b/Assets/ZoneEditor.png
new file mode 100644
index 0000000..a288b1b
Binary files /dev/null and b/Assets/ZoneEditor.png differ
diff --git a/Assets/ZoneEntitiesEditor.png b/Assets/ZoneEntitiesEditor.png
index 25274a6..7544c27 100644
Binary files a/Assets/ZoneEntitiesEditor.png and b/Assets/ZoneEntitiesEditor.png differ
diff --git a/Assets/avalonia-logo.ico b/Assets/avalonia-logo.ico
deleted file mode 100644
index da8d49f..0000000
Binary files a/Assets/avalonia-logo.ico and /dev/null differ
diff --git a/Assets/icon.png b/Assets/icon.png
deleted file mode 100644
index a03bbac..0000000
Binary files a/Assets/icon.png and /dev/null differ
diff --git a/Converters/MapMatrixRowConverter.cs b/Converters/MapMatrixRowConverter.cs
deleted file mode 100644
index 8556a65..0000000
--- a/Converters/MapMatrixRowConverter.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Data;
-using System.Globalization;
-using Avalonia.Data.Converters;
-using BeaterLibrary.Formats.Maps;
-
-namespace SwissArmyKnife.Avalonia.Converters;
-
-public class MapMatrixRowConverter : IValueConverter {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
- var matrix = value as ObservableCollection;
- if (matrix != null) {
- int nRows, nColumns;
- if ((nRows = matrix.Count) > 0 && (nColumns = matrix[0].Count) > 0) {
- DataTable t = new DataTable();
- for (int index = 0; index < nColumns; ++index) {
- t.Columns.Add(new DataColumn(index.ToString()));
- }
- for (int row = 0; row < nRows; ++row) {
- DataRow newRow = t.NewRow();
- for (int column = 0; column < nColumns; ++column) {
- newRow[column] = matrix[row][column];
- }
- t.Rows.Add(newRow);
- }
-
- return t.DefaultView;
- }
- }
- return null;
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
- return null;
- }
-}
\ No newline at end of file
diff --git a/Handlers/CommandUpdateHandler.cs b/Handlers/CommandUpdateHandler.cs
deleted file mode 100644
index f067a43..0000000
--- a/Handlers/CommandUpdateHandler.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using SwissArmyKnife.Avalonia.Utils;
-
-namespace SwissArmyKnife.Avalonia.Handlers {
- public static class CommandUpdateHandler {
- public static bool FetchScriptCommands() {
- using (var w = new WebClient()) {
- if (!DownloadYml(w, "Base", Path.Combine("Resources", "Scripts", UI.GameInfo.title, "Base.yml")))
- throw new WebException("Failed to download script commands");
- foreach (var plugin in UI.GameInfo.scriptPlugins)
- if (!DownloadYml(w, $"Overlay {plugin}",
- Path.Combine("Resources", "Scripts", UI.GameInfo.title, $"Overlay {plugin}.yml")))
- throw new WebException($"Failed to download script plugin {plugin}.");
-
- return true;
- }
- }
-
- public static bool DownloadYml(WebClient w, string ymlName, string expPath) {
- DirectoryInfo reqPath = Directory.GetParent(expPath);
- if (!reqPath.Exists) {
- reqPath.Create();
- }
- w.DownloadFile(new Uri(GetLinkToYml(ymlName)), expPath);
- return true;
- }
-
- public static string GetLinkToYml(string ymlName) {
- return $"{PreferencesHandler.Prefs.ScriptCommandsLink}{UI.GameInfo.title}/{ymlName}.yml";
- }
- }
-}
\ No newline at end of file
diff --git a/Handlers/Commands.cs b/Handlers/Commands.cs
new file mode 100644
index 0000000..4f825e8
--- /dev/null
+++ b/Handlers/Commands.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace SwissArmyKnife.Handlers {
+ public class Commands {
+ public static async Task Fetch() {
+ string ScriptResBase = Path.Combine("Resources", "Scripts", GameWork.Project.GameInfo.Codename);
+ string NetWkPath = Path.Combine("Resources", "NetWk");
+
+ DirectoryInfo BaseDir = new DirectoryInfo(ScriptResBase), NetWkDir = new DirectoryInfo(NetWkPath);
+ if (!BaseDir.Exists) {
+ BaseDir.Create();
+ }
+
+ if (!NetWkDir.Exists) {
+ NetWkDir.Create();
+ }
+
+ if (!await Net.DownloadFile(GetLinkToYML("Base.yml"), Path.Combine(NetWkPath, "Base.yml"))) {
+ NetWkDir.Delete(true);
+ return false;
+ }
+
+ foreach (KeyValuePair PluginMap in GameWork.Project.GameInfo.ScriptPlugins) {
+ string OVLYML = $"Overlay {PluginMap.Key}.yml";
+ if (!await Net.DownloadFile(GetLinkToYML(OVLYML), Path.Combine(NetWkPath, OVLYML))) {
+ NetWkDir.Delete(true);
+ return false;
+ }
+ }
+
+ foreach (FileInfo File in NetWkDir.GetFiles()) {
+ File.CopyTo(Path.Combine(ScriptResBase, $"{File.Name}"), true);
+ }
+
+ NetWkDir.Delete(true);
+ return true;
+ }
+
+ public static string GetLinkToYML(string ymlName) => $"{Preferences.Prefs.ScriptCommandsLink}{GameWork.Project.GameInfo.Codename}/{ymlName}";
+ }
+}
\ No newline at end of file
diff --git a/Handlers/GameWork.cs b/Handlers/GameWork.cs
new file mode 100644
index 0000000..62bd829
--- /dev/null
+++ b/Handlers/GameWork.cs
@@ -0,0 +1,18 @@
+using Hotswap;
+using Hotswap.Project;
+
+namespace SwissArmyKnife.Handlers;
+
+public class GameWork {
+ public static Patcher? Patcher { get; private set; }
+ public static IProject? Project { get; private set; }
+ public static void Init(string BaseROMConfigurationPath) {
+ Patcher = new Patcher(BaseROMConfigurationPath);
+ }
+
+ public static bool HandleProject(IProject Configuration) {
+ Project = Configuration;
+ Patcher?.LoadProject(Configuration);
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Handlers/IO.cs b/Handlers/IO.cs
new file mode 100644
index 0000000..a8f030c
--- /dev/null
+++ b/Handlers/IO.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+
+namespace SwissArmyKnife.Handlers;
+
+public class IO {
+ private static async Task HandleFolderFileChoice(bool saving, bool isFile, Window parentInstance, List dialogFilter) {
+ string? result;
+ if (isFile) {
+ if (saving) {
+ result = await new SaveFileDialog {
+ Filters = dialogFilter
+ }.ShowAsync(parentInstance);
+ }
+ else {
+ string[]? resultArray = await new OpenFileDialog {
+ Filters = dialogFilter
+ }.ShowAsync(parentInstance);
+ result = resultArray != null && resultArray.Length != 0 ? resultArray[0] : null;
+ }
+ } else {
+ result = await new OpenFolderDialog().ShowAsync(parentInstance);
+ }
+
+ return string.IsNullOrEmpty(result) ? String.Empty : result;
+ }
+
+ public static async Task OpenFolder(Window parentInstance) => await HandleFolderFileChoice(false, false, parentInstance, null);
+ public static async Task OpenFile(Window parentInstance, List dialogFilter) => await HandleFolderFileChoice(false, true, parentInstance, dialogFilter);
+ public static async Task SaveFile(Window parentInstance, List dialogFilter) => await HandleFolderFileChoice(true, true, parentInstance, dialogFilter);
+
+ public static async Task TryReadBinaryFile(Window Instance, List Filters) {
+ string? FilePath = await OpenFile(Instance, Filters);
+ if (!FilePath.Equals("")) {
+ return await File.ReadAllBytesAsync(FilePath);
+ }
+ return null;
+ }
+
+ public static async Task TryWriteBinaryFile(Window Instance, byte[] Buffer, List Filters) {
+ string? FilePath = await SaveFile(Instance, Filters);
+ if (!FilePath.Equals("")) {
+ await File.WriteAllBytesAsync(FilePath, Buffer);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Handlers/Logging.cs b/Handlers/Logging.cs
new file mode 100644
index 0000000..da5741c
--- /dev/null
+++ b/Handlers/Logging.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+using Avalonia.Controls;
+
+namespace SwissArmyKnife.Handlers;
+
+public static class Logging {
+ private static TextWriter loggerStream;
+ private static string logFileName;
+
+ private static void Log(string Message) {
+ if (!Design.IsDesignMode) {
+ using (loggerStream = File.AppendText(logFileName)) {
+ loggerStream.WriteLine($"[{DateTime.Now}] {Message}");
+ loggerStream.Flush();
+ loggerStream.Close();
+ }
+ }
+ }
+
+ public static void LogWarning(string Message) => Log($": {Message}");
+ public static void LogError(string Message) => Log($": {Message}");
+ public static void LogStandard(string Message) => Log($"{Message}");
+
+ public static void StopLogger() => loggerStream.Close();
+
+ public static void InitializeLogger() {
+ if (!Design.IsDesignMode) {
+ string baseName = $"SAKLog-{DateTime.Today.Year}{DateTime.Today.Month}{DateTime.Today.Day}";
+ int sessionNumber = 0;
+
+ Directory.CreateDirectory("Logs");
+ while (File.Exists(logFileName = Path.Combine("Logs", $"{baseName}-{sessionNumber}.log"))) {
+ sessionNumber++;
+ }
+ Log($"# SwissArmyKnife - (Commit Version Here) - Log File");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Handlers/MessageHandler.cs b/Handlers/MessageHandler.cs
deleted file mode 100644
index 2e11d41..0000000
--- a/Handlers/MessageHandler.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Threading.Tasks;
-using MessageBox.Avalonia;
-using MessageBox.Avalonia.DTO;
-using MessageBox.Avalonia.Enums;
-
-namespace SwissArmyKnife.Avalonia.Handlers {
- internal class MessageHandler {
- public static void ErrorMessage(string title, string caption) {
- MessageBoxManager.GetMessageBoxStandardWindow(new MessageBoxStandardParams {
- ButtonDefinitions = ButtonEnum.Ok,
- ContentTitle = $"Error: {title}",
- ContentMessage = caption,
- Icon = Icon.Error,
- Style = Style.None
- }).Show();
- }
-
- public static Task YesNoMessage(string title, string caption) {
- return MessageBoxManager.GetMessageBoxStandardWindow(new MessageBoxStandardParams {
- ButtonDefinitions = ButtonEnum.YesNo,
- ContentTitle = title,
- ContentMessage = caption,
- Icon = Icon.Success,
- Style = Style.Windows
- }).Show();
- }
- }
-}
\ No newline at end of file
diff --git a/Handlers/Messages.cs b/Handlers/Messages.cs
new file mode 100644
index 0000000..7625730
--- /dev/null
+++ b/Handlers/Messages.cs
@@ -0,0 +1,47 @@
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Material.Dialog;
+using Material.Icons;
+using Material.Icons.Avalonia;
+
+namespace SwissArmyKnife.Handlers;
+
+public class Messages {
+ private static async Task DoMessage(IClassicDesktopStyleApplicationLifetime Desktop, string Header, string SupportingText, DialogButton[] Buttons, MaterialIconExt MsgIcon) {
+ Logging.LogStandard($"MessageBox (Icon {nameof(MsgIcon)} spawned, with title \"${Header}\" and content \"{SupportingText}\"");
+ return await DialogHelper.CreateAlertDialog(
+ new AlertDialogBuilderParams {
+ ContentHeader = Header,
+ SupportingText = SupportingText,
+ StartupLocation = WindowStartupLocation.CenterOwner,
+ NegativeResult = new DialogResult("No"),
+ Borderless = true,
+ DialogButtons = Buttons,
+ }).ShowDialog(Desktop.MainWindow);
+ }
+ public static Task YesNo(IClassicDesktopStyleApplicationLifetime Desktop, string Header, string SupportingText) => DoMessage(Desktop, Header, SupportingText, new[] {
+ new DialogButton {
+ Content = "Yes",
+ Result = "Confirm"
+ },
+ new DialogButton {
+ Content = "No",
+ Result = "Cancel"
+ }
+ }, new MaterialIconExt(MaterialIconKind.Warning));
+
+ public static Task Generic(IClassicDesktopStyleApplicationLifetime Desktop, string Header, string SupportingText) => DoMessage(Desktop, Header, SupportingText, new[] {
+ new DialogButton {
+ Content = "Okay",
+ Result = "Confirm"
+ },
+ }, new MaterialIconExt(MaterialIconKind.Information));
+
+ public static Task Error(IClassicDesktopStyleApplicationLifetime Desktop, string Header, string SupportingText) => DoMessage(Desktop, Header, SupportingText, new[] {
+ new DialogButton {
+ Content = "Okay",
+ Result = "Confirm"
+ },
+ }, new MaterialIconExt(MaterialIconKind.Error));
+}
\ No newline at end of file
diff --git a/Handlers/Net.cs b/Handlers/Net.cs
new file mode 100644
index 0000000..baed3fb
--- /dev/null
+++ b/Handlers/Net.cs
@@ -0,0 +1,27 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace SwissArmyKnife.Handlers {
+ public class Net {
+ private static HttpClient Client;
+
+ public static void Initialize () {
+ Client = new HttpClient(new SocketsHttpHandler {
+ PooledConnectionLifetime = TimeSpan.FromSeconds(30)
+ });
+ }
+
+ public static async Task DownloadFile(string URL, string SavePath) {
+ HttpResponseMessage Message = await Client.GetAsync(URL);
+ if (Message.IsSuccessStatusCode) {
+ using (FileStream fs = new FileStream(SavePath, FileMode.OpenOrCreate)) {
+ await Message.Content.CopyToAsync(fs);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Handlers/Preferences.cs b/Handlers/Preferences.cs
new file mode 100644
index 0000000..ed5a2a2
--- /dev/null
+++ b/Handlers/Preferences.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using YamlDotNet.Serialization;
+
+namespace SwissArmyKnife.Handlers;
+
+public class Preferences {
+ public static Models.Preferences Prefs;
+ public static void ReadPreferences(string path) {
+ Dictionary Preferences = new Dictionary {
+ { "ScriptCommandsLink", "https://raw.githubusercontent.com/HelloOO7/PokeScriptSDK5/master/yml/" },
+ { "BaseROMConfigurationPath", Path.Combine("Configuration", "BaseROM.yml") }
+ };
+
+ Dictionary ScriptEditorColors = new Dictionary {
+ { "Method", "Cyan" },
+ { "Comment", "Green" },
+ { "Operator", "Fuchsia" },
+ { "Parameter", "Orange" }
+ };
+
+ Dictionary TextEditorColors = new Dictionary {
+ { "Command", "" },
+ { "Comment", "" },
+ { "Operator", "" },
+ { "Parameter", "" }
+ };
+
+ if (!File.Exists(path)) {
+ Logging.LogWarning($"Preferences file not found at path \"{path}\"; using default configuration.");
+ } else {
+ Logging.LogStandard($"Loading preferences from {path}...");
+ Dictionary DeserializedPreferences =
+ new Deserializer().Deserialize>(new StringReader(File.ReadAllText(path)));
+ if (DeserializedPreferences.ContainsKey("ScriptCommandsRepository")) {
+ var NewScriptRepository = DeserializedPreferences["ScriptCommandsRepository"] as string;
+ if (NewScriptRepository != null) {
+ Preferences["ScriptCommandsLink"] = NewScriptRepository;
+ Logging.LogStandard($"Changed script repository to {NewScriptRepository}.");
+ }
+ else {
+ Logging.LogWarning($"Invalid script repository link. Using the default.");
+ }
+ }
+
+ if (DeserializedPreferences.ContainsKey("BaseROMConfigurationPath")) {
+ var NewBaseRomConfigurationPath = DeserializedPreferences["BaseROMConfigurationPath"] as string;
+ if (NewBaseRomConfigurationPath != null) {
+ Preferences["BaseROMConfigurationPath"] = NewBaseRomConfigurationPath;
+ Logging.LogStandard($"Changed BaseROM configuration path to {NewBaseRomConfigurationPath}.");
+ }
+ else {
+ Logging.LogWarning($"Invalid BaseROM configuration path. Using the default.");
+ }
+ }
+
+ if (DeserializedPreferences.ContainsKey("ScriptEditorColors")) {
+ Dictionary? NewScriptEditorColors = DeserializedPreferences["ScriptEditorColors"] as Dictionary;
+ if (NewScriptEditorColors != null) {
+ foreach (KeyValuePair KVP in NewScriptEditorColors)
+ if (ScriptEditorColors.ContainsKey(KVP.Key)) {
+ ScriptEditorColors[KVP.Key] = KVP.Value;
+ Logging.LogStandard($"Changed the script editor's {KVP.Key} color to {KVP.Value}.");
+ }
+ }
+ else {
+ Logging.LogWarning($"Invalid script editor color configuration. Using the default.");
+ }
+ }
+
+ if (DeserializedPreferences.ContainsKey("TextEditorColors")) {
+ Dictionary? NewTextEditorColors =
+ DeserializedPreferences["TextEditorColors"] as Dictionary;
+ if (NewTextEditorColors != null) {
+ foreach (KeyValuePair KVP in NewTextEditorColors)
+ if (TextEditorColors.ContainsKey(KVP.Key)) {
+ TextEditorColors[KVP.Key] = KVP.Value;
+ Logging.LogStandard($"Changed the text editor's {KVP.Key} color to {KVP.Value}.");
+ }
+ }
+ else {
+ Logging.LogWarning($"Invalid text editor color configuration. Using the default.");
+ }
+ }
+ }
+
+ Prefs = new Models.Preferences {
+ ScriptCommandsLink = Preferences["ScriptCommandsLink"],
+ BaseROMConfigurationPath = Preferences["BaseROMConfigurationPath"],
+ ScriptEditorColors = ScriptEditorColors,
+ TextEditorColors = TextEditorColors
+ };
+
+ Logging.LogStandard($"Done loading preferences.");
+ }
+
+ public static void Serialize(string path) { }
+}
\ No newline at end of file
diff --git a/Handlers/PreferencesHandler.cs b/Handlers/PreferencesHandler.cs
deleted file mode 100644
index 38d5f1c..0000000
--- a/Handlers/PreferencesHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using SwissArmyKnife.Avalonia.Models;
-
-namespace SwissArmyKnife.Avalonia.Handlers {
- public class PreferencesHandler {
- public static Preferences Prefs = new();
-
- public static void ReadPreferences() {
- }
-
- public static void Serialize(Preferences prefs, string path) {
- }
- }
-}
\ No newline at end of file
diff --git a/Handlers/Scripts.cs b/Handlers/Scripts.cs
new file mode 100644
index 0000000..0988670
--- /dev/null
+++ b/Handlers/Scripts.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using Avalonia.Markup.Xaml.Templates;
+using BeaterLibrary;
+using BeaterLibrary.Formats.Scripts;
+
+namespace SwissArmyKnife.Handlers;
+
+public class Scripts {
+ private static List ParsedJumpOffsets = new List();
+ public static string PrintMethod(ScriptMethod Method, int ScriptIndex = -1, bool IsAnonymous = false) {
+ StringBuilder ConvertedMethod = new StringBuilder();
+ ConvertedMethod.AppendLine(IsAnonymous ? $"AnonymousScriptMethod_{Method.Address}:"
+ : $"Script_{ScriptIndex}:");
+ List JumpAddresses = Method.Commands.FindAll(Commands => Commands.Type.Equals(Commands.Type == CommandTypes.Jump)).Select(Command => (int)Command.Parameters[^1]).ToList();
+ int BaseAddress = Method.Address;
+ foreach (Command Cmd in Method.Commands) {
+ if (JumpAddresses.Contains(BaseAddress) && !ParsedJumpOffsets.Contains(BaseAddress)) {
+ ConvertedMethod.AppendLine($"AnonymousScriptMethod_{BaseAddress}:");
+ ParsedJumpOffsets.Append(BaseAddress);
+ } else {
+ ConvertedMethod.AppendLine($"\t{Cmd}");
+ }
+ BaseAddress += Cmd.Size();
+ }
+ return ConvertedMethod.ToString();
+ }
+
+ public static void Reset() {
+ ParsedJumpOffsets.Clear();
+ }
+
+ public static void Assemble(string ExportPath, string Script, int Plugin) {
+ // Generate include.
+ StringBuilder s = new StringBuilder();
+ Util.GenerateIncludes(GameWork.Project.GameInfo.Abbreviation, "Resources/Scripts", Plugin);
+
+ // Generate headers.
+ s.AppendLine($".include \"{GameWork.Project.GameInfo.Abbreviation}.s\"");
+ s.AppendLine($"Header:");
+ Regex r = new Regex(@".*Script_\w+:.*");
+ foreach (Match m in r.Matches(Script)) {
+ s.AppendLine($"\tscript {m.Value.Split(':')[0]}");
+ }
+ s.AppendLine("EndHeader");
+ using (StreamWriter sw = new StreamWriter("Temp.s")) {
+ sw.Write(string.Join(Environment.NewLine, s.ToString(), Script));
+ }
+
+ Assembler("Temp.s", "Temp.o");
+ ObjectCopy("Temp.o", ExportPath);
+ }
+
+ private static void Subprocess(string program, string args) {
+ var proc = new Process();
+ proc.StartInfo = new ProcessStartInfo {
+ FileName = program,
+ Arguments = args,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ };
+
+ proc.Start();
+ proc.WaitForExit();
+
+ var errorOutput = proc.StandardError.ReadToEnd();
+
+ if (proc.ExitCode != 0) {
+ throw new Exception(errorOutput);
+ }
+ }
+
+ public static void Assembler(string path, string output) {
+ Subprocess("arm-none-eabi-as", $"-mthumb -c \"{path}\" -o \"{output}\"");
+ }
+
+ public static void ObjectCopy(string path, string output) {
+ Subprocess("arm-none-eabi-objcopy", $"-O binary \"{path}\" \"{output}\"");
+ }
+}
\ No newline at end of file
diff --git a/Models/Editors/MapEditorModel.cs b/Models/Editors/MapEditorModel.cs
new file mode 100644
index 0000000..89fd529
--- /dev/null
+++ b/Models/Editors/MapEditorModel.cs
@@ -0,0 +1,83 @@
+using System;
+using BeaterLibrary.Formats.Maps;
+using BeaterLibrary.Formats.Nitro;
+using ReactiveUI;
+
+namespace SwissArmyKnife.Models.Editors;
+
+public class MapEditorModel : ReactiveObject {
+ private MapContainer _Container;
+ public MapContainer Container {
+ get => _Container;
+ set {
+ this.RaiseAndSetIfChanged(ref _Container, value);
+ UpdateContainerType();
+ this.RaisePropertyChanged(nameof(ModelName));
+ this.RaisePropertyChanged(nameof(ContainerType));
+ this.RaisePropertyChanged(nameof(MapModel));
+ this.RaisePropertyChanged(nameof(Permissions));
+ this.RaisePropertyChanged(nameof(Permissions2));
+ this.RaisePropertyChanged(nameof(BuildingPositions));
+ }
+ }
+
+ public ushort ContainerType {
+ get => (ushort) Array.IndexOf(MapContainer.MapContainerType.GetValues(Container.ContainerType.GetType()), Container.ContainerType);
+ }
+
+ public string ModelName {
+ get => Container.Model.Name;
+ }
+
+ public NSBMD MapModel {
+ get => Container.Model;
+ set {
+ Container.Model = value;
+ }
+ }
+
+ public byte[] Permissions {
+ get => Container.Permissions;
+ set {
+ Container.Permissions = value;
+ UpdateContainerType();
+ }
+ }
+
+ public bool HasPermissions => Permissions != null && Permissions.Length > 0;
+
+ public byte[] Permissions2 {
+ get => Container.Permissions2;
+ set {
+ Container.Permissions2 = value;
+ UpdateContainerType();
+ }
+ }
+
+ public bool HasPermissions2 => Permissions2 != null && Permissions2.Length > 0;
+
+ public byte[] BuildingPositions {
+ get => Container.BuildingPositions;
+ set {
+ Container.BuildingPositions = value;
+ }
+ }
+
+ public bool HasBuildingPositions => BuildingPositions != null && BuildingPositions.Length > 0;
+
+ public void UpdateContainerType() {
+ // Assume model & building positions are set.
+ if (Permissions != null && Permissions2 == null) {
+ // WB or RD chunk. My tool does not support RD natively.
+ Container.ContainerType = MapContainer.MapContainerType.WB;
+ } else if (Permissions != null && Permissions2 != null) {
+ // GC Chunk
+ Container.ContainerType = MapContainer.MapContainerType.GC;
+ } else {
+ // NG Chunk
+ Container.ContainerType = MapContainer.MapContainerType.NG;
+ }
+ }
+
+ public int Index { get; set; }
+}
\ No newline at end of file
diff --git a/Models/Editors/MatrixEditorModel.cs b/Models/Editors/MatrixEditorModel.cs
new file mode 100644
index 0000000..bcb542e
--- /dev/null
+++ b/Models/Editors/MatrixEditorModel.cs
@@ -0,0 +1,10 @@
+using System.Data;
+using ReactiveUI;
+
+namespace SwissArmyKnife.Models.Editors;
+
+public class MatrixEditorModel : ReactiveObject {
+ public int Index { get; set; }
+ public DataView MapFiles { get; set; }
+ public DataView MapHeaders { get; set; }
+}
\ No newline at end of file
diff --git a/Models/Editors/ZoneEntitiesModel.cs b/Models/Editors/ZoneEntitiesModel.cs
new file mode 100644
index 0000000..15acd8b
--- /dev/null
+++ b/Models/Editors/ZoneEntitiesModel.cs
@@ -0,0 +1,13 @@
+using BeaterLibrary.Formats.Zone;
+using ReactiveUI;
+
+namespace SwissArmyKnife.Models.Editors;
+
+public class ZoneEntitiesModel : ReactiveObject {
+ private ZoneEntities _Container;
+ public ZoneEntities Container {
+ get => _Container;
+ set => this.RaiseAndSetIfChanged(ref _Container, value);
+ }
+ public int Index { get; set; }
+}
\ No newline at end of file
diff --git a/Models/NewProjectModel.cs b/Models/NewProjectModel.cs
new file mode 100644
index 0000000..8630b41
--- /dev/null
+++ b/Models/NewProjectModel.cs
@@ -0,0 +1,28 @@
+using System;
+using ReactiveUI;
+
+namespace SwissArmyKnife.Models;
+
+public class NewProjectModel : ReactiveObject {
+ private string _projectName, _projectTitle, _projectROMCode;
+
+ public NewProjectModel() {
+ ProjectName = String.Empty;
+ ProjectROMCode = String.Empty;
+ Path = String.Empty;
+ }
+ public string ProjectName {
+ get => _projectName;
+ set => this.RaiseAndSetIfChanged(ref _projectName, value);
+ }
+
+ public string Path {
+ get => _projectTitle;
+ set => this.RaiseAndSetIfChanged(ref _projectTitle, value);
+ }
+
+ public string ProjectROMCode {
+ get => _projectROMCode;
+ set => this.RaiseAndSetIfChanged(ref _projectROMCode, value);
+ }
+}
\ No newline at end of file
diff --git a/Models/Preferences.cs b/Models/Preferences.cs
index bcf61ea..b508c1e 100644
--- a/Models/Preferences.cs
+++ b/Models/Preferences.cs
@@ -1,11 +1,15 @@
-namespace SwissArmyKnife.Avalonia.Models {
- public class Preferences {
- public Preferences() {
- ScriptCommandsLink = "https://raw.githubusercontent.com/HelloOO7/PokeScriptSDK5/master/yml/";
- BaseRomConfiguration = "Configuration/BaseROM.yml";
- }
+using System.Collections.Generic;
- public string ScriptCommandsLink { get; }
- public string BaseRomConfiguration { get; }
+namespace SwissArmyKnife.Models;
+
+public class Preferences {
+ public Preferences() {
+ ScriptCommandsLink = "https://raw.githubusercontent.com/PlatinumMaster/PokeScriptSDK5/master/yml/";
+ BaseROMConfigurationPath = "Configuration/BaseROM.yml";
}
+
+ public string ScriptCommandsLink { get; set; }
+ public string BaseROMConfigurationPath { get; set; }
+ public Dictionary ScriptEditorColors { get; set; }
+ public Dictionary TextEditorColors { get; set; }
}
\ No newline at end of file
diff --git a/Pages/Battle/TrainerEditor.axaml b/Pages/Battle/TrainerEditor.axaml
new file mode 100644
index 0000000..2f9bddd
--- /dev/null
+++ b/Pages/Battle/TrainerEditor.axaml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Battle/TrainerEditor.axaml.cs b/Pages/Battle/TrainerEditor.axaml.cs
new file mode 100644
index 0000000..4c06d6b
--- /dev/null
+++ b/Pages/Battle/TrainerEditor.axaml.cs
@@ -0,0 +1,16 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Battle;
+
+public partial class TrainerEditor : UserControl {
+ public TrainerEditor() {
+ DataContext = new TrainerEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/Pages/Battle/WildPokemonEditor.axaml b/Pages/Battle/WildPokemonEditor.axaml
new file mode 100644
index 0000000..76e043d
--- /dev/null
+++ b/Pages/Battle/WildPokemonEditor.axaml
@@ -0,0 +1,1812 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Battle/WildPokemonEditor.axaml.cs b/Pages/Battle/WildPokemonEditor.axaml.cs
new file mode 100644
index 0000000..024818c
--- /dev/null
+++ b/Pages/Battle/WildPokemonEditor.axaml.cs
@@ -0,0 +1,17 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Battle;
+
+public partial class WildEncounterEditor : UserControl {
+ public WildEncounterEditor() {
+ if (!Design.IsDesignMode)
+ DataContext = new WildEncounterEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/Pages/Field/MapEditor.axaml b/Pages/Field/MapEditor.axaml
new file mode 100644
index 0000000..6c61b96
--- /dev/null
+++ b/Pages/Field/MapEditor.axaml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Field/MapEditor.axaml.cs b/Pages/Field/MapEditor.axaml.cs
new file mode 100644
index 0000000..746925e
--- /dev/null
+++ b/Pages/Field/MapEditor.axaml.cs
@@ -0,0 +1,16 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Field;
+
+public partial class MapEditor : UserControl {
+ public MapEditor() {
+ DataContext = new MapEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/Pages/Field/MatrixEditor.axaml b/Pages/Field/MatrixEditor.axaml
new file mode 100644
index 0000000..b876d45
--- /dev/null
+++ b/Pages/Field/MatrixEditor.axaml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Pages/Field/MatrixEditor.axaml.cs b/Pages/Field/MatrixEditor.axaml.cs
new file mode 100644
index 0000000..283595b
--- /dev/null
+++ b/Pages/Field/MatrixEditor.axaml.cs
@@ -0,0 +1,49 @@
+using System.Data;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Field;
+
+public partial class MatrixEditor : UserControl {
+ public MatrixEditor() {
+ InitializeComponent();
+ DataContext = new MatrixEditorViewModel();
+ // MapMatrixHeaders = this.Get("MapMatrixHeaders");
+ // MapMatrixMaps = this.Get("MapMatrixMaps");
+ // MapMatrixHeaders.PropertyChanged += MapMatrix_PropertyChange;
+ // MapMatrixMaps.PropertyChanged += MapMatrix_PropertyChange;
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private void MapMatrixMaps_OnLoadingRow(object? sender, DataGridRowEventArgs e) {
+ e.Row.Header = e.Row.GetIndex() + 1;
+ }
+
+ private void MapMatrix_PropertyChange(object? sender, AvaloniaPropertyChangedEventArgs e) {
+ DataGrid? Current = sender as DataGrid;
+ if (Current == null) {
+ return;
+ }
+
+ if (e.Property.Name.Equals("Items")) {
+ Current.Columns.Clear();
+ DataView? Table = e.NewValue as DataView;
+ if (Table.Table != null) {
+ DataColumnCollection Columns = Table.Table.Columns;
+ for (int y = 0; y < Columns.Count; ++y) {
+ Current.Columns.Add(new DataGridTextColumn {
+ Header = Columns[y].ColumnName,
+ Binding = new Binding($"Row.ItemArray[{y}]"),
+ IsReadOnly = false
+ });
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pages/Field/ScriptEditor.axaml b/Pages/Field/ScriptEditor.axaml
new file mode 100644
index 0000000..47853a2
--- /dev/null
+++ b/Pages/Field/ScriptEditor.axaml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Field/ScriptEditor.axaml.cs b/Pages/Field/ScriptEditor.axaml.cs
new file mode 100644
index 0000000..b149b57
--- /dev/null
+++ b/Pages/Field/ScriptEditor.axaml.cs
@@ -0,0 +1,27 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Field;
+
+public partial class ScriptEditor : UserControl {
+ public ScriptEditor() {
+ DataContext = new ScriptEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ ScriptEditorTextbox = this.Get(nameof(ScriptEditorTextbox));
+ }
+
+ private void ScriptEditor_OnKeyDown(object? sender, KeyEventArgs e) {
+ if (e.Key == Key.OemPlus && (e.KeyModifiers & KeyModifiers.Control) != 0) {
+ ScriptEditorTextbox.FontSize++;
+ } else if (e.Key == Key.OemMinus && (e.KeyModifiers & KeyModifiers.Control) != 0) {
+ ScriptEditorTextbox.FontSize--;
+ }
+ e.Handled = true;
+ }
+}
\ No newline at end of file
diff --git a/Pages/Field/TextEditor.axaml b/Pages/Field/TextEditor.axaml
new file mode 100644
index 0000000..a931e44
--- /dev/null
+++ b/Pages/Field/TextEditor.axaml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Field/TextEditor.axaml.cs b/Pages/Field/TextEditor.axaml.cs
new file mode 100644
index 0000000..51d56bb
--- /dev/null
+++ b/Pages/Field/TextEditor.axaml.cs
@@ -0,0 +1,27 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Field;
+
+public partial class TextEditor : UserControl {
+ public TextEditor() {
+ DataContext = new TextEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ // TextEditorTextbox = this.Get(nameof(TextEditorTextbox));
+ }
+
+ private void TextEditor_OnKeyDown(object? sender, KeyEventArgs e) {
+ // if (e.Key == Key.OemPlus && (e.KeyModifiers & KeyModifiers.Control) != 0) {
+ // TextEditorTextbox.FontSize++;
+ // } else if (e.Key == Key.OemMinus && (e.KeyModifiers & KeyModifiers.Control) != 0) {
+ // TextEditorTextbox.FontSize--;
+ // }
+ e.Handled = true;
+ }
+}
\ No newline at end of file
diff --git a/Pages/Field/ZoneEditor.axaml b/Pages/Field/ZoneEditor.axaml
new file mode 100644
index 0000000..3644a8d
--- /dev/null
+++ b/Pages/Field/ZoneEditor.axaml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Field/ZoneEditor.axaml.cs b/Pages/Field/ZoneEditor.axaml.cs
new file mode 100644
index 0000000..b9e6414
--- /dev/null
+++ b/Pages/Field/ZoneEditor.axaml.cs
@@ -0,0 +1,16 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Field;
+
+public partial class ZoneEditor : UserControl {
+ public ZoneEditor() {
+ DataContext = new ZoneEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/Pages/Field/ZoneEntitiesEditor.axaml b/Pages/Field/ZoneEntitiesEditor.axaml
new file mode 100644
index 0000000..8a00cf4
--- /dev/null
+++ b/Pages/Field/ZoneEntitiesEditor.axaml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pages/Field/ZoneEntitiesEditor.axaml.cs b/Pages/Field/ZoneEntitiesEditor.axaml.cs
new file mode 100644
index 0000000..aff97c4
--- /dev/null
+++ b/Pages/Field/ZoneEntitiesEditor.axaml.cs
@@ -0,0 +1,16 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SwissArmyKnife.ViewModels.Editors;
+
+namespace SwissArmyKnife.Pages.Field;
+
+public partial class ZoneEntitiesEditor : UserControl {
+ public ZoneEntitiesEditor() {
+ DataContext = new ZoneEntitiesEditorViewModel();
+ InitializeComponent();
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/Pages/MapEditor.axaml b/Pages/MapEditor.axaml
deleted file mode 100644
index 77f788f..0000000
--- a/Pages/MapEditor.axaml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/MapEditor.axaml.cs b/Pages/MapEditor.axaml.cs
deleted file mode 100644
index cc7c17c..0000000
--- a/Pages/MapEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages;
-
-public class MapEditor : ReactiveUserControl {
- public MapEditor() {
- if (!Design.IsDesignMode)
- DataContext = new MapEditorViewModel();
- InitializeComponent();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/Pages/MatrixEditor.axaml b/Pages/MatrixEditor.axaml
deleted file mode 100644
index ce0baf3..0000000
--- a/Pages/MatrixEditor.axaml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/MatrixEditor.axaml.cs b/Pages/MatrixEditor.axaml.cs
deleted file mode 100644
index d18a88e..0000000
--- a/Pages/MatrixEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages;
-
-public class MatrixEditor : ReactiveUserControl {
- public MatrixEditor() {
- if (!Design.IsDesignMode)
- DataContext = new MatrixEditorViewModel();
- InitializeComponent();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/Pages/ScriptEditor.axaml b/Pages/ScriptEditor.axaml
deleted file mode 100644
index 8570de3..0000000
--- a/Pages/ScriptEditor.axaml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/ScriptEditor.axaml.cs b/Pages/ScriptEditor.axaml.cs
deleted file mode 100644
index b1ce9d1..0000000
--- a/Pages/ScriptEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages {
- public class ScriptEditor : ReactiveUserControl {
- public ScriptEditor() {
- InitializeComponent();
- if (!Design.IsDesignMode)
- DataContext = new ScriptEditorViewModel();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
- }
-}
\ No newline at end of file
diff --git a/Pages/TextEditor.axaml b/Pages/TextEditor.axaml
deleted file mode 100644
index d42e574..0000000
--- a/Pages/TextEditor.axaml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/TextEditor.axaml.cs b/Pages/TextEditor.axaml.cs
deleted file mode 100644
index 6c8d042..0000000
--- a/Pages/TextEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages {
- public class TextEditor : ReactiveUserControl {
- public TextEditor() {
- InitializeComponent();
- if (!Design.IsDesignMode)
- DataContext = new TextEditorViewModel();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
- }
-}
\ No newline at end of file
diff --git a/Pages/TrainerEditor.axaml b/Pages/TrainerEditor.axaml
deleted file mode 100644
index 051ad9e..0000000
--- a/Pages/TrainerEditor.axaml
+++ /dev/null
@@ -1,280 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/TrainerEditor.axaml.cs b/Pages/TrainerEditor.axaml.cs
deleted file mode 100644
index 09158e7..0000000
--- a/Pages/TrainerEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages;
-
-public class TrainerEditor : ReactiveUserControl {
- public TrainerEditor() {
- InitializeComponent();
- if (!Design.IsDesignMode)
- DataContext = new TrainerEditorViewModel();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/Pages/WildPokemonEditor.axaml b/Pages/WildPokemonEditor.axaml
deleted file mode 100644
index 538217a..0000000
--- a/Pages/WildPokemonEditor.axaml
+++ /dev/null
@@ -1,439 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/WildPokemonEditor.axaml.cs b/Pages/WildPokemonEditor.axaml.cs
deleted file mode 100644
index 32f0c43..0000000
--- a/Pages/WildPokemonEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages;
-
-public class WildPokemonEditor : ReactiveUserControl {
- public WildPokemonEditor() {
- if (!Design.IsDesignMode)
- DataContext = new WildPokemonViewModel();
- InitializeComponent();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/Pages/ZoneEntitiesEditor.axaml b/Pages/ZoneEntitiesEditor.axaml
deleted file mode 100644
index c7c27db..0000000
--- a/Pages/ZoneEntitiesEditor.axaml
+++ /dev/null
@@ -1,214 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/ZoneEntitiesEditor.axaml.cs b/Pages/ZoneEntitiesEditor.axaml.cs
deleted file mode 100644
index c7df44b..0000000
--- a/Pages/ZoneEntitiesEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages {
- public class ZoneEntitiesEditor : ReactiveUserControl {
- public ZoneEntitiesEditor() {
- InitializeComponent();
- if (!Design.IsDesignMode)
- DataContext = new ZoneEntitiesViewModel();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
- }
-}
\ No newline at end of file
diff --git a/Pages/ZoneHeaderEditor.axaml b/Pages/ZoneHeaderEditor.axaml
deleted file mode 100644
index 3e6050e..0000000
--- a/Pages/ZoneHeaderEditor.axaml
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pages/ZoneHeaderEditor.axaml.cs b/Pages/ZoneHeaderEditor.axaml.cs
deleted file mode 100644
index 3eff197..0000000
--- a/Pages/ZoneHeaderEditor.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using SwissArmyKnife.Avalonia.ViewModels.Editors;
-
-namespace SwissArmyKnife.Avalonia.Pages;
-
-public class HeaderEditor : ReactiveUserControl {
- public HeaderEditor() {
- if (!Design.IsDesignMode)
- DataContext = new ZoneHeaderViewModel();
- InitializeComponent();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
index ab2ad50..1930004 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,7 +1,7 @@
using Avalonia;
using Avalonia.ReactiveUI;
-namespace SwissArmyKnife.Avalonia {
+namespace SwissArmyKnife {
internal class Program {
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
diff --git a/Styles/Border.axaml b/Styles/Border.axaml
deleted file mode 100644
index bc5f5b9..0000000
--- a/Styles/Border.axaml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/Styles/Navbar.axaml b/Styles/Navbar.axaml
new file mode 100644
index 0000000..3595331
--- /dev/null
+++ b/Styles/Navbar.axaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Styles/Sidebar.axaml b/Styles/Sidebar.axaml
index dfcae5d..e33d878 100644
--- a/Styles/Sidebar.axaml
+++ b/Styles/Sidebar.axaml
@@ -1,66 +1,8 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
diff --git a/Styles/Spinner.axaml b/Styles/Spinner.axaml
new file mode 100644
index 0000000..90e5e83
--- /dev/null
+++ b/Styles/Spinner.axaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/SwissArmyKnife.Avalonia.csproj b/SwissArmyKnife.Avalonia.csproj
deleted file mode 100644
index 5c39f1c..0000000
--- a/SwissArmyKnife.Avalonia.csproj
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
- WinExe
- net6.0
- enable
- true
- true
- true
- 10
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ZoneEntitiesEditor.axaml
-
-
-
-
-
-
-
-
- PreserveNewest
-
-
- Always
-
-
-
-
-
-
-
diff --git a/SwissArmyKnife.csproj b/SwissArmyKnife.csproj
new file mode 100644
index 0000000..a71a57b
--- /dev/null
+++ b/SwissArmyKnife.csproj
@@ -0,0 +1,40 @@
+
+
+ WinExe
+ net6.0
+ enable
+ true
+ true
+ true
+ 10
+ SwissArmyKnife
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
diff --git a/SwissArmyKnife.Avalonia.sln b/SwissArmyKnife.sln
similarity index 95%
rename from SwissArmyKnife.Avalonia.sln
rename to SwissArmyKnife.sln
index 087056b..735b25a 100644
--- a/SwissArmyKnife.Avalonia.sln
+++ b/SwissArmyKnife.sln
@@ -1,48 +1,48 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31019.35
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SwissArmyKnife.Avalonia", "SwissArmyKnife.Avalonia.csproj", "{ECFFF592-B177-44C1-820A-B085DE4788C0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeaterLibrary", "..\BeaterLibrary\BeaterLibrary.csproj", "{64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3B7E414C-8F10-4D07-B644-52D13B46DDDF}"
- ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- EndProjectSection
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotswap", "..\Hotswap\Hotswap.csproj", "{A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NitroSharp", "..\NitroSharp\NitroSharp.csproj", "{8035A4B2-A497-4594-91DA-5E962A949117}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {ECFFF592-B177-44C1-820A-B085DE4788C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {ECFFF592-B177-44C1-820A-B085DE4788C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {ECFFF592-B177-44C1-820A-B085DE4788C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {ECFFF592-B177-44C1-820A-B085DE4788C0}.Release|Any CPU.Build.0 = Release|Any CPU
- {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Release|Any CPU.Build.0 = Release|Any CPU
- {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Release|Any CPU.Build.0 = Release|Any CPU
- {8035A4B2-A497-4594-91DA-5E962A949117}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8035A4B2-A497-4594-91DA-5E962A949117}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8035A4B2-A497-4594-91DA-5E962A949117}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8035A4B2-A497-4594-91DA-5E962A949117}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {DF58AF4C-8362-489E-8A10-BFB85F8BD391}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31019.35
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SwissArmyKnife", "SwissArmyKnife.csproj", "{ECFFF592-B177-44C1-820A-B085DE4788C0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeaterLibrary", "..\BeaterLibrary\BeaterLibrary.csproj", "{64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3B7E414C-8F10-4D07-B644-52D13B46DDDF}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotswap", "..\Hotswap\Hotswap.csproj", "{A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NitroSharp", "..\NitroSharp\NitroSharp.csproj", "{8035A4B2-A497-4594-91DA-5E962A949117}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ECFFF592-B177-44C1-820A-B085DE4788C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ECFFF592-B177-44C1-820A-B085DE4788C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ECFFF592-B177-44C1-820A-B085DE4788C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ECFFF592-B177-44C1-820A-B085DE4788C0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {64D08D87-3E35-4646-ABA6-45BDE4FF7ECA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A9C3B44D-3AF1-416F-A2B2-3AE93B50B28F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8035A4B2-A497-4594-91DA-5E962A949117}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8035A4B2-A497-4594-91DA-5E962A949117}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8035A4B2-A497-4594-91DA-5E962A949117}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8035A4B2-A497-4594-91DA-5E962A949117}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DF58AF4C-8362-489E-8A10-BFB85F8BD391}
+ EndGlobalSection
+EndGlobal
diff --git a/Util.cs b/Util.cs
deleted file mode 100644
index fef60c2..0000000
--- a/Util.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Avalonia.Controls;
-using BeaterLibrary;
-using BeaterLibrary.GameInfo;
-using Hotswap;
-using SwissArmyKnife.Avalonia.Handlers;
-
-namespace SwissArmyKnife.Avalonia.Utils {
- public class UI {
- public static AbstractGameInformation GameInfo;
- public static Patcher Patcher { get; set; }
-
- public static void InitializePatcher(string baseRomConfigurationPath, string configurationPath) {
- Patcher = new Patcher(baseRomConfigurationPath, configurationPath);
- GameInfo = GameInformation.getGameConfiguration(Patcher.getGameCode());
- if (!CommandUpdateHandler.FetchScriptCommands()) {
- throw new Exception("Something is wrong!");
- }
- }
-
- public static void ScriptToAssembler(string path, string game, string script, int scriptPlugins) {
- StringBuilder s = new();
- Util.generateCommandAsm(game, "Resources/Scripts", scriptPlugins);
- s.Append($".include \"{game}.s\"{Environment.NewLine}");
- s.Append($"Header:{Environment.NewLine}");
- Regex r = new(@".*Script_\w+:.*");
- foreach (Match m in r.Matches(script))
- s.Append($"\tscript {m.Value.Split(':')[0]}{Environment.NewLine}");
- s.Append($"EndHeader{Environment.NewLine}");
-
- using (StreamWriter sw = new(path)) {
- var output = string.Join(Environment.NewLine, s.ToString(), script);
- sw.Write(output);
- }
- }
-
- private static void Subprocess(string program, string args) {
- var proc = new Process();
- proc.StartInfo = new ProcessStartInfo {
- FileName = program,
- Arguments = args,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- proc.Start();
- proc.WaitForExit();
-
- var errorOutput = proc.StandardError.ReadToEnd();
-
- if (proc.ExitCode != 0) {
- throw new Exception(errorOutput);
- }
- }
-
- public static void Assembler(string path, string output) {
- Subprocess("arm-none-eabi-as", $"-mthumb -c \"{path}\" -o \"{output}\"");
- }
-
- public static void ObjectCopy(string path, string output) {
- Subprocess("arm-none-eabi-objcopy", $"-O binary \"{path}\" \"{output}\"");
- }
-
- private static async Task HandleFolderFileChoice(bool saving, bool isFile, Window parentInstance,
- List dialogFilter) {
- string result;
- if (isFile) {
- if (saving) {
- result = await new SaveFileDialog() { Filters = dialogFilter }.ShowAsync(parentInstance);
- }
- else {
- string[] resultArray =
- await new OpenFileDialog {Filters = dialogFilter, AllowMultiple = false}.ShowAsync(
- parentInstance);
- result = resultArray.Length != 0 ? resultArray[0] : null;
- }
- }
- else {
- result = await new OpenFolderDialog().ShowAsync(parentInstance);
- }
-
- if (result == null || result == string.Empty) throw new OperationCanceledException("Operation canceled!");
-
- if (result.Length > 0) return result;
-
- return null;
- }
-
- public static async Task OpenFolder(Window parentInstance) {
- return await HandleFolderFileChoice(false, false, parentInstance, null);
- }
-
- public static async Task OpenFile(Window parentInstance, List dialogFilter) {
- return await HandleFolderFileChoice(false, true, parentInstance, dialogFilter);
- }
-
- public static async Task SaveFile(Window parentInstance, List dialogFilter) {
- return await HandleFolderFileChoice(true, true, parentInstance, dialogFilter);
- }
- }
-}
\ No newline at end of file
diff --git a/ViewModels/Base/EditorViewModelBase.cs b/ViewModels/Base/EditorViewModelBase.cs
new file mode 100644
index 0000000..4cc2a36
--- /dev/null
+++ b/ViewModels/Base/EditorViewModelBase.cs
@@ -0,0 +1,53 @@
+using System.Collections.ObjectModel;
+using System.Reactive;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Material.Dialog;
+using ReactiveUI;
+using SwissArmyKnife.Handlers;
+
+namespace SwissArmyKnife.ViewModels.Base;
+
+public abstract class EditorViewModelBase : ViewModelBase {
+ public ObservableCollection Tabs { get; set; }
+ public ReactiveCommand AddNew { get; }
+ public ReactiveCommand RemoveSelected { get; }
+ public ReactiveCommand LoadFile { get; }
+ public ReactiveCommand SaveChanges { get; }
+ public int SelectedIndex { get; set; }
+ public int Max { get; set; }
+ private int _CurrentTab;
+ public int CurrentTab {
+ get => _CurrentTab;
+ set {
+ this.RaiseAndSetIfChanged(ref _CurrentTab, value);
+ TryShowTabControl();
+ }
+ }
+ protected int ARC { get; set; }
+
+ public EditorViewModelBase() {
+ SelectedIndex = 0;
+ AddNew = ReactiveCommand.Create(OnAddNew);
+ RemoveSelected = ReactiveCommand.Create(OnRemoveSelected);
+ LoadFile = ReactiveCommand.Create(OnLoadFile);
+ SaveChanges = ReactiveCommand.Create(OnSaveChanges);
+ Tabs = new ObservableCollection();
+ }
+
+ public abstract void OnAddNew();
+ public abstract void OnRemoveSelected();
+ public abstract void OnLoadFile();
+ public abstract void OnSaveChanges();
+ protected abstract void TryShowTabControl();
+
+ protected async Task RefreshPromptConfirm(string Header, string Supporting) {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ DialogResult Result = await Messages.YesNo(Desktop, Header, Supporting);
+ return Result.GetResult.Equals("No");
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/Base/ViewModelBase.cs b/ViewModels/Base/ViewModelBase.cs
new file mode 100644
index 0000000..2bf5e41
--- /dev/null
+++ b/ViewModels/Base/ViewModelBase.cs
@@ -0,0 +1,5 @@
+using ReactiveUI;
+
+namespace SwissArmyKnife.ViewModels.Base;
+
+public class ViewModelBase : ReactiveObject { }
\ No newline at end of file
diff --git a/ViewModels/Editors/MapEditorViewModel.cs b/ViewModels/Editors/MapEditorViewModel.cs
index 33eda27..b723b4e 100644
--- a/ViewModels/Editors/MapEditorViewModel.cs
+++ b/ViewModels/Editors/MapEditorViewModel.cs
@@ -1,258 +1,215 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reactive;
using System.Threading.Tasks;
+using Avalonia;
using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using AvaloniaEdit.Document;
using BeaterLibrary.Formats.Maps;
using BeaterLibrary.Formats.Nitro;
+using DynamicData;
using ReactiveUI;
-using SwissArmyKnife.Avalonia.Utils;
-using SwissArmyKnife.Avalonia.Views;
+using SwissArmyKnife.Handlers;
+using SwissArmyKnife.Models.Editors;
+using SwissArmyKnife.ViewModels.Base;
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors;
+namespace SwissArmyKnife.ViewModels.Editors;
-public class MapEditorViewModel : ViewModelTemplate {
- private int _selectedIndex;
- private MapContainer _currentMapContainer;
+public class MapEditorViewModel : EditorViewModelBase {
+ private Dictionary LoadedMapContainers;
+ public ReactiveCommand ImportModel { get; }
+ public ReactiveCommand ExportModel { get; }
+ public ReactiveCommand ImportPermissions { get; }
+ public ReactiveCommand ExportPermissions { get; }
+ public ReactiveCommand RemovePermissions { get; }
+ public ReactiveCommand ImportPermissions2 { get; }
+ public ReactiveCommand ExportPermissions2 { get; }
+ public ReactiveCommand RemovePermissions2 { get; }
+ public ReactiveCommand ImportBuildingPos { get; }
+ public ReactiveCommand ExportBuildingPos { get; }
+ public ReactiveCommand RemoveBuildingPos { get; }
+ public MapEditorModel Current { get; private set; }
+ public bool AnyContainers => LoadedMapContainers.Count > 0;
- public MapContainer CurrentMapContainer {
- get => _currentMapContainer;
- private set {
- this.RaiseAndSetIfChanged(ref _currentMapContainer, value);
- this.RaisePropertyChanged(nameof(CurrentMapContainerType));
- this.RaisePropertyChanged(nameof(HasPerms));
- this.RaisePropertyChanged(nameof(HasPerms2));
- this.RaisePropertyChanged(nameof(HasBldPos));
- this.RaisePropertyChanged(nameof(ModelName));
- this.RaisePropertyChanged();
- }
+ public MapEditorViewModel() {
+ ARC = GameWork.Project.GameInfo.ARCs["Map Containers"];
+ Max = GameWork.Patcher.GetARCMax(ARC);
+ Current = new MapEditorModel {
+ Container = new MapContainer(MapContainer.MapContainerType.NG)
+ };
+ Tabs = new ObservableCollection();
+ LoadedMapContainers = new Dictionary();
+ ImportModel = ReactiveCommand.Create(ImportModelFromDisk);
+ ExportModel = ReactiveCommand.Create(ExportModelToDisk);
+ ImportPermissions = ReactiveCommand.Create(ImportPermissionsFromDisk);
+ ExportPermissions = ReactiveCommand.Create(ExportPermissionsToDisk);
+ RemovePermissions = ReactiveCommand.Create(RemovePermissionsFromContainer);
+ ImportPermissions2 = ReactiveCommand.Create(ImportPermissions2FromDisk);
+ ExportPermissions2 = ReactiveCommand.Create(ExportPermissions2ToDisk);
+ RemovePermissions2 = ReactiveCommand.Create(RemovePermissions2FromContainer);
+ ImportBuildingPos = ReactiveCommand.Create(ImportBuildingPositionsFromDisk);
+ ExportBuildingPos = ReactiveCommand.Create(ExportBuildingPositionsToDisk);
+ RemoveBuildingPos = ReactiveCommand.Create(RemoveBuildingPositionsFromContainer);
+ }
+
+ public override void OnAddNew() {
+ throw new NotImplementedException();
+ }
+
+ public override void OnRemoveSelected() {
+ throw new NotImplementedException();
}
- public int CurrentMapContainerType {
- get {
- switch (CurrentMapContainer.containerType) {
- case MapContainer.MagicLabels.Ng:
- return 0;
- case MapContainer.MagicLabels.Rd:
- return 1;
- case MapContainer.MagicLabels.Wb:
- return 2;
- case MapContainer.MagicLabels.Gc:
- return 3;
- default:
- return -1;
+ public async override void OnLoadFile() {
+ if (GameWork.Patcher != null && SelectedIndex >= 0 && SelectedIndex <= Max) {
+ if (LoadedMapContainers.ContainsKey(SelectedIndex)) {
+ // File already loaded, prompt.
+ if (!await RefreshPromptConfirm("Reload Map Container", "This map container is already open. Would you like to reload it anyway? All unsaved changes will be lost.")) {
+ return;
+ }
}
+
+ MapContainer LoadedContainer = GetMapContainerFromARC(SelectedIndex);
+ LoadedMapContainers.Add(SelectedIndex, new MapEditorModel {
+ Container = LoadedContainer,
+ Index = SelectedIndex
+ });
+
+ Tabs.Add(new TabItem {
+ Header = $"Map Container {SelectedIndex}",
+ });
+
+ CurrentTab = LoadedMapContainers.Keys.IndexOf(SelectedIndex);
}
}
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
+ public override void OnSaveChanges() {
+ throw new NotImplementedException();
}
- public bool HasPerms => CurrentMapContainer.permissions.Length > 0;
- public bool HasPerms2 => CurrentMapContainer.permissions2.Length > 0;
- public bool HasBldPos => CurrentMapContainer.buildingPositions.Length > 0;
- public string ModelName => CurrentMapContainer.model.name;
-
- public ReactiveCommand ImportModel { get; }
- public ReactiveCommand ExportModel { get; }
- public ReactiveCommand ImportPerms { get; }
- public ReactiveCommand ExportPerms { get; }
- public ReactiveCommand RemovePerms { get; }
- public ReactiveCommand ImportPerms2 { get; }
- public ReactiveCommand ExportPerms2 { get; }
- public ReactiveCommand RemovePerms2 { get; }
- public ReactiveCommand ImportBuildingPos { get; }
- public ReactiveCommand ExportBuildingPos { get; }
- public ReactiveCommand RemoveBuildingPos { get; }
- public ReactiveCommand LoadMapContainer { get; }
+ protected override void TryShowTabControl() {
+ this.RaisePropertyChanged(nameof(AnyContainers));
+ if (AnyContainers) {
+ Current = LoadedMapContainers[SelectedIndex];
+ this.RaisePropertyChanged(nameof(Current));
+ this.RaisePropertyChanged(nameof(Current.ModelName));
+ this.RaisePropertyChanged(nameof(Current.HasPermissions));
+ this.RaisePropertyChanged(nameof(Current.HasPermissions2));
+ this.RaisePropertyChanged(nameof(Current.HasBuildingPositions));
+ }
+ }
- public ObservableCollection MapTypes { get; }
+ private MapContainer GetMapContainerFromARC(int ID) {
+ return new MapContainer(GameWork.Patcher.GetARCFile(ARC, ID));
+ }
- public MapEditorViewModel() {
- LoadMapContainer = ReactiveCommand.Create(() => {
- CurrentMapContainer = new MapContainer(UI.Patcher.fetchFileFromNarc(UI.GameInfo.maps, SelectedIndex));
- });
- MapTypes = new() {
- "NG", "RD", "WB", "GC"
- };
- ImportModel = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.OpenFile(ProjectManagementWindow.Instance, new List() {
- new FileDialogFilter() {
- Name = "NITRO System Binary Model",
- Extensions = new List() {
- "nsbmd",
- "bmd0",
- "bin"
- }
- }
- });
- CurrentMapContainer.model = new NitroSystemBinaryModel(File.ReadAllBytes(path));
- this.RaisePropertyChanged(nameof(ModelName));
- }
- catch (OperationCanceledException ex) {
- }
- });
- ExportModel = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.SaveFile(ProjectManagementWindow.Instance, new List() {
- new() {
- Name = "NITRO System Binary Model",
- Extensions = new List() {
- "nsbmd",
- "bmd0",
- "bin"
- }
- }
- });
- File.WriteAllBytes(path, CurrentMapContainer.model.data);
- }
- catch (OperationCanceledException ex) {
- }
- });
- ImportPerms = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.OpenFile(ProjectManagementWindow.Instance, new List() {
- new FileDialogFilter() {
- Name = "Permissions",
- Extensions = new List() {
- "per",
- "bin"
- }
- }
- });
- CurrentMapContainer.permissions = File.ReadAllBytes(path);
- CurrentMapContainer.updateContainerType();
- this.RaisePropertyChanged(nameof(CurrentMapContainerType));
- this.RaisePropertyChanged(nameof(HasPerms));
+ private async void ImportModelFromDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null && !FilePath.Equals("")) {
+ try {
+ Current.MapModel = new NSBMD(File.ReadAllBytes(FilePath));
+ }
+ catch (Exception e) {
+ Messages.Error(Desktop, "Error when importing model", $"An error occurred when importing your model, and the process has been aborted.\nThe error is as follows:\n{e}");
+ }
+ this.RaisePropertyChanged(nameof(Current.ModelName));
}
- catch (OperationCanceledException ex) {
- }
- });
- ExportPerms = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.SaveFile(ProjectManagementWindow.Instance, new List() {
- new() {
- Name = "Permissions",
- Extensions = new List() {
- "per",
- "bin"
- }
- }
- });
- File.WriteAllBytes(path, CurrentMapContainer.permissions);
- }
- catch (OperationCanceledException ex) {
- }
- });
- RemovePerms = ReactiveCommand.Create(async () => {
- CurrentMapContainer.permissions = Array.Empty();
- CurrentMapContainer.updateContainerType();
- this.RaisePropertyChanged(nameof(CurrentMapContainerType));
- this.RaisePropertyChanged(nameof(HasPerms));
- });
- ImportPerms2 = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.OpenFile(ProjectManagementWindow.Instance, new List() {
- new FileDialogFilter() {
- Name = "Permissions",
- Extensions = new List() {
- "per",
- "bin"
- }
- }
- });
- CurrentMapContainer.permissions2 = File.ReadAllBytes(path);
- CurrentMapContainer.updateContainerType();
- this.RaisePropertyChanged(nameof(CurrentMapContainerType));
- this.RaisePropertyChanged(nameof(HasPerms2));
- }
- catch (OperationCanceledException ex) {
- }
- });
- ExportPerms2 = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.SaveFile(ProjectManagementWindow.Instance, new List() {
- new() {
- Name = "Permissions",
- Extensions = new List() {
- "per",
- "bin"
- }
- }
- });
- File.WriteAllBytes(path, CurrentMapContainer.permissions2);
- }
- catch (OperationCanceledException ex) {
+ }
+ }
+
+ private async void ExportModelToDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.SaveFile(Desktop.MainWindow, new List() {
+ new FileDialogFilter() {
+
+ }
+ });
+ if (FilePath != null) {
+ // TODO
}
- });
- RemovePerms2 = ReactiveCommand.Create(async () => {
- CurrentMapContainer.permissions2 = Array.Empty();
- CurrentMapContainer.updateContainerType();
- this.RaisePropertyChanged(nameof(CurrentMapContainerType));
- this.RaisePropertyChanged(nameof(HasPerms2));
- });
- ImportBuildingPos = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.OpenFile(ProjectManagementWindow.Instance, new List() {
- new() {
- Name = "Building Positions",
- Extensions = new List() {
- "bld",
- "bin"
- }
- }
- });
- CurrentMapContainer.buildingPositions = File.ReadAllBytes(path);
- this.RaisePropertyChanged(nameof(HasBldPos));
+ }
+ }
+
+ private async void ImportPermissionsFromDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null) {
+ // TODO
+ this.RaisePropertyChanged(nameof(Current.HasPermissions));
}
- catch (OperationCanceledException ex) {
+ }
+ }
+
+ private async void ExportPermissionsToDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null) {
+ // TODO
}
- });
- ExportBuildingPos = ReactiveCommand.Create(async () => {
- try {
- string path = await UI.SaveFile(ProjectManagementWindow.Instance, new List() {
- new() {
- Name = "Building Positions",
- Extensions = new List() {
- "bld",
- "bin"
- }
- }
- });
- File.WriteAllBytes(path, CurrentMapContainer.buildingPositions);
+ }
+ }
+
+ private async void RemovePermissionsFromContainer() {
+ Current.Permissions = Array.Empty();
+ this.RaisePropertyChanged(nameof(Current.HasPermissions));
+ }
+
+ private async void ImportPermissions2FromDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null) {
+ // TODO
+ this.RaisePropertyChanged(nameof(Current.HasPermissions2));
}
- catch (OperationCanceledException ex) {
+ }
+ }
+
+ private async void ExportPermissions2ToDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null) {
+ // TODO
}
- });
- RemoveBuildingPos = ReactiveCommand.Create(async () => {
- CurrentMapContainer.buildingPositions = Array.Empty();
- this.RaisePropertyChanged(nameof(HasBldPos));
- });
- SelectedIndex = 0;
- CurrentMapContainer = new MapContainer(UI.Patcher.fetchFileFromNarc(UI.GameInfo.maps, SelectedIndex));
+ }
}
- public override void OnAddNew() {
- throw new System.NotImplementedException();
+ private async void RemovePermissions2FromContainer() {
+ Current.Permissions2 = Array.Empty();
+ this.RaisePropertyChanged(nameof(Current.HasPermissions2));
}
-
- public override void OnRemoveSelected(int index) {
- throw new System.NotImplementedException();
+
+ private async void ImportBuildingPositionsFromDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null) {
+ // TODO
+ this.RaisePropertyChanged(nameof(Current.HasBuildingPositions));
+ }
+ }
}
-
- public override void OnIndexChange(int newValue) {
- if (newValue >= 0 && newValue < UI.Patcher.getNarcEntryCount(UI.GameInfo.maps)) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
- this.RaisePropertyChanged(nameof(SelectedIndex));
+
+ private async void ExportBuildingPositionsToDisk() {
+ if (Application.Current != null && Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? FilePath = await IO.OpenFile(Desktop.MainWindow, new List() {
+ });
+ if (FilePath != null) {
+ // TODO
+ }
}
}
-
- public override void OnSaveChanges() {
- UI.Patcher.saveToNarcFolder(UI.GameInfo.maps, SelectedIndex, x => CurrentMapContainer.serialize(x));
+
+ private async void RemoveBuildingPositionsFromContainer() {
+ Current.BuildingPositions = Array.Empty();
+ this.RaisePropertyChanged(nameof(Current));
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/ViewModels/Editors/MatrixEditorViewModel.cs b/ViewModels/Editors/MatrixEditorViewModel.cs
index 85a3d90..47623d5 100644
--- a/ViewModels/Editors/MatrixEditorViewModel.cs
+++ b/ViewModels/Editors/MatrixEditorViewModel.cs
@@ -1,45 +1,25 @@
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Data;
-using BeaterLibrary.Formats.Maps;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Utils;
+using SwissArmyKnife.ViewModels.Base;
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors;
+namespace SwissArmyKnife.ViewModels.Editors;
-public class MatrixEditorViewModel : ViewModelTemplate {
- private int _selectedIndex;
- private MapMatrix _currentMatrix;
- public ObservableCollection CurrentMapFileMatrix { get; set; }
- public ObservableCollection CurrentMapHeaderDataTable { get; set; }
-
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
-
- public MatrixEditorViewModel() {
- SelectedIndex = 0;
- }
-
+public class MatrixEditorViewModel : EditorViewModelBase {
public override void OnAddNew() {
throw new System.NotImplementedException();
}
- public override void OnRemoveSelected(int index) {
+ public override void OnRemoveSelected() {
throw new System.NotImplementedException();
}
- public override void OnIndexChange(int newValue) {
- if (newValue >= 0 && newValue < UI.Patcher.getNarcEntryCount(UI.GameInfo.matrix)) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
- _currentMatrix = new MapMatrix(UI.Patcher.fetchFileFromNarc(UI.GameInfo.matrix, newValue));
- CurrentMapFileMatrix = new ObservableCollection(_currentMatrix.mapFilesMatrix);
- this.RaisePropertyChanged(nameof(CurrentMapFileMatrix));
- }
+ public override void OnLoadFile() {
+ throw new System.NotImplementedException();
}
public override void OnSaveChanges() {
throw new System.NotImplementedException();
}
+
+ protected override void TryShowTabControl() {
+ throw new System.NotImplementedException();
+ }
}
\ No newline at end of file
diff --git a/ViewModels/Editors/ScriptEditorViewModel.cs b/ViewModels/Editors/ScriptEditorViewModel.cs
index fa581c4..474716d 100644
--- a/ViewModels/Editors/ScriptEditorViewModel.cs
+++ b/ViewModels/Editors/ScriptEditorViewModel.cs
@@ -1,78 +1,117 @@
-using System;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.IO;
-using System.Reactive;
+using System.Linq;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
using AvaloniaEdit.Document;
-using BeaterLibrary;
using BeaterLibrary.Formats.Scripts;
+using Material.Dialog;
using ReactiveUI;
-using SwissArmyKnife.Avalonia.Utils;
+using SwissArmyKnife.Handlers;
+using SwissArmyKnife.ViewModels.Base;
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public class ScriptEditorViewModel : ViewModelTemplate {
- private int _selectedIndex;
- private TextDocument _textDoc;
+namespace SwissArmyKnife.ViewModels.Editors;
- public ScriptEditorViewModel() {
- TextDoc = new TextDocument();
- LoadScript = ReactiveCommand.Create(() => ChangeScript(SelectedIndex));
- SelectedIndex = 0;
- ChangeScript(SelectedIndex);
- }
-
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
+public class ScriptEditorViewModel : EditorViewModelBase {
+ private List Documents;
+ private TextDocument? _Current;
+ public bool AnyDocuments => Documents.Count > 0;
+ public int FontSize { get; set; }
+ private int ScriptPlugin = -1;
+ public ObservableCollection Tabs { get; set; }
+ public TextDocument? Current {
+ get => _Current;
+ set => this.RaiseAndSetIfChanged(ref _Current, value);
+ }
+
+ public ScriptEditorViewModel() {
+ Max = GameWork.Patcher.GetARCMax(GameWork.Project.GameInfo.ARCs["Events"]);
+ Current = new TextDocument();
+ Tabs = new ObservableCollection();
+ Documents = new List();
+ FontSize = 16;
+ }
- public TextDocument TextDoc {
- get => _textDoc;
- set => this.RaiseAndSetIfChanged(ref _textDoc, value);
- }
+ public override void OnAddNew() {
+ throw new NotImplementedException();
+ }
- public ReactiveCommand LoadScript { get; }
+ public override void OnRemoveSelected() {
+ throw new NotImplementedException();
+ }
- public override void OnAddNew() {
+ public override async void OnLoadFile() {
+ if (GameWork.Patcher != null && SelectedIndex >= 0 && SelectedIndex <= Max) {
+ TextDocument? Document = await TryOpenOrCreateDocument();
+ ScriptContainer Script = GetScriptFromARC(SelectedIndex);
+ Document.FileName = SelectedIndex.ToString();
+ Document.Text = String.Empty;
+ Scripts.Reset();
- }
+ Script.Scripts.ForEach(s => {
+ Document.Text += Scripts.PrintMethod(s, ScriptIndex: Script.Scripts.IndexOf(s) + 1);
+ });
+
+ Script.Calls.ForEach(s => {
+ Document.Text += Scripts.PrintMethod(s.Data, IsAnonymous: true);
+ });
+
+ Script.Actions.ForEach(s => {
+ Document.Text += $"ActionSequence {s.GetDataToString()}";
+ });
- private void ChangeScript(int index) {
- try {
- TextDoc.Text = Util.unpackScriptContainer(
- new ScriptContainer(
- UI.Patcher.fetchFileFromNarc(UI.GameInfo.scripts, index),
- Path.Combine("Resources", "Scripts"),
- UI.GameInfo.title,
- UI.GameInfo.getScriptPluginsByScrId(SelectedIndex)
- ));
- }
- catch (Exception ex) {
- TextDoc.Text = "Something went wrong when decompiling this script.\n" + ex;
- }
+ CurrentTab = Documents.IndexOf(Document);
}
+ }
- public override void OnIndexChange(int newValue) {
- if (newValue >= 0 && newValue < UI.Patcher.getNarcEntryCount(UI.GameInfo.scripts))
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
+ public override void OnSaveChanges() {
+ if (AnyDocuments && CurrentTab >= 0 && CurrentTab < Tabs.Count) {
+ int FileIndex = int.Parse(Current.FileName);
+ GameWork.Patcher.WriteARCViaVFS(GameWork.Project.GameInfo.ARCs["Events"], FileIndex, Path => {
+ Scripts.Assemble(Path, Current.Text, ScriptPlugin);
+ });
}
+ }
- public override void OnRemoveSelected(int index) {
-
+ protected override void TryShowTabControl() {
+ this.RaisePropertyChanged(nameof(AnyDocuments));
+ if (AnyDocuments) {
+ Current = Documents[CurrentTab];
}
+ }
+
+ private ScriptContainer GetScriptFromARC(int ID) {
+ ScriptPlugin = -1;
+ foreach (KeyValuePair KVP in GameWork.Project.GameInfo.ScriptPlugins) {
+ if (KVP.Value.Contains(ID)) {
+ // Script plugins enabled for this script container.
+ ScriptPlugin = KVP.Key;
+ break;
+ }
+ }
+ return new ScriptContainer(
+ GameWork.Patcher.GetARCFile(GameWork.Project.GameInfo.ARCs["Events"], ID),
+ Path.Combine("Resources", "Scripts"),
+ GameWork.Project.GameInfo.Abbreviation,
+ ScriptPlugin);
+ }
- public override void OnSaveChanges() {
- UI.Patcher.saveToNarcFolder(
- UI.GameInfo.scripts,
- _selectedIndex,
- x => {
- UI.Patcher.saveToNarcFolder(UI.GameInfo.scripts, SelectedIndex, x => {
- UI.ScriptToAssembler("Temp.s", UI.GameInfo.title, TextDoc.Text,
- UI.GameInfo.getScriptPluginsByScrId(SelectedIndex));
- UI.Assembler("Temp.s", "Temp.o");
- UI.ObjectCopy("Temp.o", x);
- File.Delete("Temp.s");
- File.Delete("Temp.o");
- });
- });
+ private async Task TryOpenOrCreateDocument() {
+ TextDocument? Existing = Documents.Find(x => x.FileName.Equals(SelectedIndex.ToString()));
+ if (Existing != null) {
+ return await RefreshPromptConfirm("Reload Script", "This script is already open. Would you like to reload it anyway? All unsaved changes will be lost.") ? Existing : null;
}
+ Existing = new TextDocument() {
+ FileName = SelectedIndex.ToString()
+ };
+ Tabs.Add(new TabItem {
+ Header = $"Script Container {SelectedIndex}",
+ });
+ Documents.Add(Existing);
+ return Existing;
}
}
\ No newline at end of file
diff --git a/ViewModels/Editors/TextEditorViewModel.cs b/ViewModels/Editors/TextEditorViewModel.cs
index 215e551..c0d00f7 100644
--- a/ViewModels/Editors/TextEditorViewModel.cs
+++ b/ViewModels/Editors/TextEditorViewModel.cs
@@ -1,68 +1,99 @@
-using System;
-using System.IO;
-using System.Reactive;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Reflection.Metadata;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
using AvaloniaEdit.Document;
+using BeaterLibrary.Formats.Scripts;
using BeaterLibrary.Formats.Text;
+using Material.Dialog;
using ReactiveUI;
-using SwissArmyKnife.Avalonia.Utils;
+using SwissArmyKnife.Handlers;
+using SwissArmyKnife.ViewModels.Base;
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public class TextEditorViewModel : ViewModelTemplate {
- private int _selectedIndex;
- private TextDocument _textDoc;
- private bool _useMapText;
- private TextContainer _currentContainer;
+namespace SwissArmyKnife.ViewModels.Editors;
- public bool UseMapText {
- get => _useMapText;
- set => OnUseMapTextChange(value);
- }
-
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
-
- public TextDocument TextDoc {
- get => _textDoc;
- set => this.RaiseAndSetIfChanged(ref _textDoc, value);
- }
-
- public ReactiveCommand LoadText { get; }
- public TextEditorViewModel() {
- TextDoc = new TextDocument();
- LoadText = ReactiveCommand.Create(() => ChangeText(SelectedIndex));
- UseMapText = true;
- }
-
- public override void OnAddNew() {
-
- }
+public class TextEditorViewModel : EditorViewModelBase {
+ private List Documents;
+ private TextDocument? _Current;
+ private List GFTextData;
+ public bool AnyDocuments => Documents.Count > 0;
+ public int FontSize { get; set; }
+ public int TextGroup { get; set;}
+ public TextDocument? Current {
+ get => _Current;
+ set => this.RaiseAndSetIfChanged(ref _Current, value);
+ }
- private void ChangeText(int newValue) {
- _currentContainer = new TextContainer(UI.Patcher.fetchFileFromNarc(UseMapText ? UI.GameInfo.mapText : UI.GameInfo.systemsText, newValue));
- TextDoc.Text = _currentContainer.fetchTextAsString(true, true);
- }
-
- public override void OnIndexChange(int newValue) {
- if (newValue >= 0 && newValue <
- UI.Patcher.getNarcEntryCount(UseMapText ? UI.GameInfo.mapText : UI.GameInfo.systemsText)) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
+ public TextEditorViewModel() {
+ Max = GameWork.Patcher.GetARCMax(GameWork.Project.GameInfo.ARCs["Events"]);
+ GFTextData = new List();
+ Current = new TextDocument();
+ Tabs = new ObservableCollection();
+ Documents = new List();
+ FontSize = 16;
+ this.WhenAnyValue(vm => vm.TextGroup).Subscribe(async newGroup => {
+ if (newGroup >= 0) {
+ ARC = GameWork.Project.GameInfo.ARCs[newGroup == 0 ? "System Text" : "Event Text"];
+ Max = GameWork.Patcher.GetARCMax(ARC);
}
- }
+ });
+ }
+
+ public override void OnAddNew() {
+ throw new System.NotImplementedException();
+ }
- public override void OnRemoveSelected(int index) {
-
- }
+ public override void OnRemoveSelected() {
+ throw new System.NotImplementedException();
+ }
- public override void OnSaveChanges() {
- UI.Patcher.saveToNarcFolder(UseMapText ? UI.GameInfo.mapText : UI.GameInfo.systemsText, SelectedIndex,
- x => _currentContainer.serialize(TextDoc.Text, x));
+ public override async void OnLoadFile() {
+ if (GameWork.Patcher != null && SelectedIndex >= 0 && SelectedIndex <= Max) {
+ TextDocument Document = await TryOpenOrCreateDocument();
+ GFText Text = GetTextFromARC(SelectedIndex);
+ Document.FileName = SelectedIndex.ToString();
+ Document.Text = Text.FetchTextAsString(true, true);
+ GFTextData.Add(Text);
+ CurrentTab = Documents.IndexOf(Document);
}
+ }
+
+ public override void OnSaveChanges() {
+ if (AnyDocuments && CurrentTab >= 0 && CurrentTab < Tabs.Count) {
+ int FileIndex = int.Parse(Current.FileName);
+ GameWork.Patcher.WriteARCViaVFS(ARC, FileIndex, Path => {
+ GFTextData[CurrentTab].Serialize(Current.Text, Path);
+ });
+ }
+ }
- private void OnUseMapTextChange(bool newValue) {
- this.RaiseAndSetIfChanged(ref _useMapText, newValue);
- SelectedIndex = 0;
+ protected override void TryShowTabControl() {
+ this.RaisePropertyChanged(nameof(AnyDocuments));
+ if (AnyDocuments) {
+ Current = Documents[CurrentTab];
}
}
+
+ private async Task TryOpenOrCreateDocument() {
+ TextDocument Existing = Documents.Find(x => x.FileName.Equals(SelectedIndex.ToString()));
+ if (Existing != null) {
+ return await RefreshPromptConfirm("Reload Text Container", "This text container is already open. Would you like to reload it anyway? All unsaved changes will be lost.") ? Existing : null;
+ }
+ Existing = new TextDocument() {
+ FileName = SelectedIndex.ToString()
+ };
+ Tabs.Add(new TabItem {
+ Header = $"Text Container {SelectedIndex}",
+ });
+ Documents.Add(Existing);
+ return Existing;
+ }
+
+ private GFText GetTextFromARC(int ID) {
+ return new GFText(GameWork.Patcher.GetARCFile(ARC, ID));
+ }
}
\ No newline at end of file
diff --git a/ViewModels/Editors/TrainerEditorViewModel.cs b/ViewModels/Editors/TrainerEditorViewModel.cs
index 4136373..754df31 100644
--- a/ViewModels/Editors/TrainerEditorViewModel.cs
+++ b/ViewModels/Editors/TrainerEditorViewModel.cs
@@ -1,174 +1,25 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Reactive;
-using System.Security.Cryptography;
-using BeaterLibrary.Formats.Text;
-using BeaterLibrary.Formats.Trainer;
-using BeaterLibrary.GameInfo;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.Utils;
+using SwissArmyKnife.ViewModels.Base;
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public class TrainerEditorViewModel : ViewModelTemplate {
- private TrainerPokémonEntries _currentPkmnEntries;
- private TrainerData _currentTrainer;
- private int _selectedIndex;
- private int _selectedPkmnEntryIndex;
- private bool[] _aiFlags;
- public ObservableCollection TrainerClasses { get; private set; }
- public ObservableCollection TrainerNames { get; private set; }
- public ObservableCollection BattleTypes { get; private set; }
- public ObservableCollection ItemNames { get; private set; }
- public ObservableCollection MoveNames { get; private set; }
- public ObservableCollection PokémonNames { get; private set; }
+namespace SwissArmyKnife.ViewModels.Editors;
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
-
- public int SelectedPkmnEntryIndex {
- get => _selectedPkmnEntryIndex;
- set => OnPkmnIndexChange(value);
- }
-
- public bool SetPkmnMoves {
- get => CurrentTrainer.setPkmnMoves;
- set {
- CurrentTrainer.setPkmnMoves = value;
- this.RaisePropertyChanged();
- }
- }
-
- public bool SetPkmnHeldItem {
- get => CurrentTrainer.setPkmnHeldItem;
- set {
- CurrentTrainer.setPkmnHeldItem = value;
- this.RaisePropertyChanged();
- }
- }
-
- public bool[] AiFlags {
- get => _aiFlags;
- set {
- this.RaiseAndSetIfChanged(ref _aiFlags, value);
- this.RaisePropertyChanged();
- }
- }
-
- public TrainerData CurrentTrainer {
- get => _currentTrainer;
- private set => this.RaiseAndSetIfChanged(ref _currentTrainer, value);
- }
-
- public ObservableCollection CurrentPkmnEntries { get; set; }
- public ReactiveCommand AddNewTrainerPoke { get; }
- public ReactiveCommand RemoveSelectedTrainerPoke { get; }
- public ReactiveCommand LoadTrainer { get; }
- public ReactiveCommand ReloadTextBanks { get; }
- public TrainerEditorViewModel() {
- FetchAllTextArchives();
- AddNewTrainerPoke = ReactiveCommand.Create(OnAddNewTrainerPoke);
- RemoveSelectedTrainerPoke = ReactiveCommand.Create(OnRemoveTrainerPoke);
- LoadTrainer = ReactiveCommand.Create(OnLoadTrainer);
- ReloadTextBanks = ReactiveCommand.Create(FetchAllTextArchives);
- SelectedIndex = 0;
- OnLoadTrainer();
- }
-
- private void OnLoadTrainer() {
- FetchTrainerData(SelectedIndex);
- SelectedPkmnEntryIndex = 0;
- }
- public void OnAddNewTrainerPoke() {
- if (CurrentPkmnEntries.Count == 6) {
- MessageHandler.ErrorMessage("Ghetsis detected", "You can only have 6 Pokémon.");
- return;
- }
-
- if (SelectedPkmnEntryIndex > 0) {
- CurrentPkmnEntries.Insert(SelectedPkmnEntryIndex + 1, new TrainerPokémonEntry());
- } else {
- CurrentPkmnEntries.Add(new TrainerPokémonEntry());
- }
- this.RaisePropertyChanged(nameof(CurrentPkmnEntries));
- }
-
- public void OnRemoveTrainerPoke() {
- if (CurrentPkmnEntries.Count == 0) {
- MessageHandler.ErrorMessage("No Pokémon", "You need to have a Pokémon in order to remove it.");
- return;
- }
-
- if (SelectedPkmnEntryIndex == -1) {
- MessageHandler.ErrorMessage("No Pokémon selected", "You need to select a Pokémon entry to remove.");
- return;
- }
- CurrentPkmnEntries.RemoveAt(SelectedPkmnEntryIndex--);
- this.RaisePropertyChanged(nameof(CurrentPkmnEntries));
- }
-
- public override void OnAddNew() {}
-
- public override void OnIndexChange(int newValue) {
- if (newValue < TrainerNames.Count && newValue >= 0) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
- this.RaisePropertyChanged(nameof(SelectedIndex));
- }
- }
-
- public override void OnRemoveSelected(int index) {}
-
- public override void OnSaveChanges() {
- CurrentTrainer.ai = 0;
- for (int index = 0; index < 8; ++index) {
- CurrentTrainer.ai |= (uint)(AiFlags[index] ? 1 : 0) << index;
- }
- UI.Patcher.saveToNarcFolder(UI.GameInfo.trainerPokemon, SelectedIndex, x => TrainerPokémonEntries.serialize(new List(CurrentPkmnEntries), SetPkmnMoves, SetPkmnHeldItem, x));
- UI.Patcher.saveToNarcFolder(UI.GameInfo.trainerData, SelectedIndex, x => CurrentTrainer.serialize(new List(CurrentPkmnEntries), x));
- }
+public class TrainerEditorViewModel : EditorViewModelBase {
+ public override void OnAddNew() {
+ throw new System.NotImplementedException();
+ }
- public void OnPkmnIndexChange(int newValue) {
- if (newValue < CurrentTrainer.numberOfPokemon && newValue >= 0) {
- this.RaiseAndSetIfChanged(ref _selectedPkmnEntryIndex, newValue);
- }
- }
+ public override void OnRemoveSelected() {
+ throw new System.NotImplementedException();
+ }
- private ObservableCollection FetchTextArchive(int bank) {
- return new ObservableCollection(new TextContainer(UI.Patcher.fetchFileFromNarc(UI.GameInfo.systemsText, bank)).fetchTextAsStringArray());
- }
+ public override void OnLoadFile() {
+ throw new System.NotImplementedException();
+ }
- private void FetchTrainerData(int Index) {
- CurrentTrainer = new TrainerData(UI.Patcher.fetchFileFromNarc(UI.GameInfo.trainerData, Index));
- CurrentPkmnEntries = new ObservableCollection(new TrainerPokémonEntries(
- UI.Patcher.fetchFileFromNarc(UI.GameInfo.trainerPokemon, Index),
- CurrentTrainer.setPkmnMoves, CurrentTrainer.numberOfPokemon, CurrentTrainer.setPkmnHeldItem
- ).pokémonEntries);
- this.RaisePropertyChanged(nameof(CurrentPkmnEntries));
- this.RaisePropertyChanged(nameof(SetPkmnMoves));
- this.RaisePropertyChanged(nameof(SetPkmnHeldItem));
- var flags = new bool[8];
- for (int index = 0; index < 8; ++index) {
- flags[index] = (CurrentTrainer.ai & (1 << index)) == 1 << index;
- }
- AiFlags = flags;
- }
+ public override void OnSaveChanges() {
+ throw new System.NotImplementedException();
+ }
- private void FetchAllTextArchives() {
- TrainerNames = FetchTextArchive(UI.GameInfo.ImportantSystemText["TrainerNames"]);
- TrainerClasses = FetchTextArchive(UI.GameInfo.ImportantSystemText["TrainerClasses"]);
- BattleTypes = FetchTextArchive(UI.GameInfo.ImportantSystemText["BattleTypes"]);
- ItemNames = FetchTextArchive(UI.GameInfo.ImportantSystemText["ItemNames"]);
- MoveNames = FetchTextArchive(UI.GameInfo.ImportantSystemText["MoveNames"]);
- PokémonNames = FetchTextArchive(UI.GameInfo.ImportantSystemText["PokémonNames"]);
- this.RaisePropertyChanged(nameof(TrainerNames));
- this.RaisePropertyChanged(nameof(TrainerClasses));
- this.RaisePropertyChanged(nameof(BattleTypes));
- this.RaisePropertyChanged(nameof(ItemNames));
- this.RaisePropertyChanged(nameof(MoveNames));
- this.RaisePropertyChanged(nameof(PokémonNames));
- }
+ protected override void TryShowTabControl() {
+ throw new System.NotImplementedException();
}
}
\ No newline at end of file
diff --git a/ViewModels/Editors/ViewModelTemplate.cs b/ViewModels/Editors/ViewModelTemplate.cs
deleted file mode 100644
index 0c11e62..0000000
--- a/ViewModels/Editors/ViewModelTemplate.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Reactive;
-using ReactiveUI;
-
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public abstract class ViewModelTemplate : ReactiveObject {
- public abstract int SelectedIndex { get; set; }
- public ReactiveCommand AddNew => ReactiveCommand.Create(() => OnAddNew());
-
- public ReactiveCommand RemoveSelected =>
- ReactiveCommand.Create(() => OnRemoveSelected(SelectedIndex));
-
- public ReactiveCommand SaveChanges => ReactiveCommand.Create(() => OnSaveChanges());
-
- public abstract void OnAddNew();
- public abstract void OnRemoveSelected(int index);
- public abstract void OnIndexChange(int newValue);
- public abstract void OnSaveChanges();
- }
-}
\ No newline at end of file
diff --git a/ViewModels/Editors/WildEncounterEditorViewModel.cs b/ViewModels/Editors/WildEncounterEditorViewModel.cs
new file mode 100644
index 0000000..31aaa6d
--- /dev/null
+++ b/ViewModels/Editors/WildEncounterEditorViewModel.cs
@@ -0,0 +1,25 @@
+using SwissArmyKnife.ViewModels.Base;
+
+namespace SwissArmyKnife.ViewModels.Editors;
+
+public class WildEncounterEditorViewModel : EditorViewModelBase {
+ public override void OnAddNew() {
+ throw new System.NotImplementedException();
+ }
+
+ public override void OnRemoveSelected() {
+ throw new System.NotImplementedException();
+ }
+
+ public override void OnLoadFile() {
+ throw new System.NotImplementedException();
+ }
+
+ public override void OnSaveChanges() {
+ throw new System.NotImplementedException();
+ }
+
+ protected override void TryShowTabControl() {
+ throw new System.NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/Editors/WildPokemonViewModel.cs b/ViewModels/Editors/WildPokemonViewModel.cs
deleted file mode 100644
index 817f37d..0000000
--- a/ViewModels/Editors/WildPokemonViewModel.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
-using System.Linq;
-using System.Reactive;
-using BeaterLibrary.Formats.Pokémon;
-using BeaterLibrary.Formats.Text;
-using BeaterLibrary.GameInfo;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.Utils;
-
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public class WildPokemonViewModel : ViewModelTemplate {
- private int _selectedIndex;
- private int _selectedSubEntry;
- private int _numberOfEntries;
-
- private List> _containerGrassEntries, _containerGrassDoubleEntries, _containerGrassSpecialEntries;
- private List> _containerSurfEntries, _containerSurfSpecialEntries;
- private List> _containerFishEntries, _containerFishSpecialEntries;
-
- public ObservableCollection GrassSingleEntries { get; set; }
- public ObservableCollection GrassDoubleEntries { get; set; }
- public ObservableCollection GrassSpecialEntries { get; set; }
- public ObservableCollection SurfEntries { get; set; }
- public ObservableCollection SurfSpecialEntries { get; set; }
- public ObservableCollection FishEntries { get; set; }
- public ObservableCollection FishSpecialEntries { get; set; }
- public ObservableCollection SpeciesNames { get; set; }
- public ReactiveCommand LoadContainer { get; }
- public ReactiveCommand LoadSubentry { get; }
-
- public WildPokemonViewModel() {
- SpeciesNames = new ObservableCollection(
- new TextContainer(UI.Patcher.fetchFileFromNarc(UI.GameInfo.systemsText,
- UI.GameInfo.ImportantSystemText["PokémonNames"])).fetchTextAsStringArray());
- this.RaisePropertyChanged(nameof(SpeciesNames));
- LoadContainer = ReactiveCommand.Create(() => ChangeWildContainer(SelectedIndex));
- LoadSubentry = ReactiveCommand.Create(() => OnSelectedSubentryChange(SelectedSubentryIndex));
- _containerGrassEntries = new List>();
- _containerGrassDoubleEntries = new List>();
- _containerGrassSpecialEntries = new List>();
- _containerFishEntries = new List>();
- _containerFishSpecialEntries = new List>();
- _containerSurfEntries = new List>();
- _containerSurfSpecialEntries = new List>();
- }
-
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
-
- public int SelectedSubentryIndex {
- get => _selectedSubEntry;
- set => OnSelectedSubentryChange(value);
- }
-
- public override void OnIndexChange(int newValue) {
- if (newValue >= 0 && newValue < UI.Patcher.getNarcEntryCount(UI.GameInfo.wildEncounters)) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
- }
- }
-
- private void OnSelectedSubentryChange(int newValue) {
- if (newValue >= 0 && newValue < _numberOfEntries) {
- this.RaiseAndSetIfChanged(ref _selectedSubEntry, newValue);
- }
- GrassSingleEntries = _containerGrassEntries[SelectedSubentryIndex];
- GrassDoubleEntries = _containerGrassDoubleEntries[SelectedSubentryIndex];
- GrassSpecialEntries = _containerGrassSpecialEntries[SelectedSubentryIndex];
- SurfEntries = _containerSurfEntries[SelectedSubentryIndex];
- SurfSpecialEntries = _containerSurfSpecialEntries[SelectedSubentryIndex];
- FishEntries = _containerFishEntries[SelectedSubentryIndex];
- FishSpecialEntries = _containerFishSpecialEntries[SelectedSubentryIndex];
-
- this.RaisePropertyChanged(nameof(GrassSingleEntries));
- this.RaisePropertyChanged(nameof(GrassDoubleEntries));
- this.RaisePropertyChanged(nameof(GrassSpecialEntries));
- this.RaisePropertyChanged(nameof(SurfEntries));
- this.RaisePropertyChanged(nameof(SurfSpecialEntries));
- this.RaisePropertyChanged(nameof(FishEntries));
- this.RaisePropertyChanged(nameof(FishSpecialEntries));
- }
-
- private void ResetContainerEntries() {
- _containerGrassEntries.Clear();
- _containerGrassDoubleEntries.Clear();
- _containerGrassSpecialEntries.Clear();
- _containerFishEntries.Clear();
- _containerFishSpecialEntries.Clear();
- _containerSurfEntries.Clear();
- _containerSurfSpecialEntries.Clear();
- }
-
- private void ChangeWildContainer(int Index) {
- ResetContainerEntries();
- try {
- byte[] buffer = UI.Patcher.fetchFileFromNarc(UI.GameInfo.wildEncounters, Index);
- if (buffer.Length > 0 && buffer.Length % 0xE8 == 0) {
- _numberOfEntries = buffer.Length / 0xE8;
- for (int index = 0; index < _numberOfEntries; ++index) {
- WildEncounters e = new(buffer.Skip(0xE8 * index).Take(0xE8).ToArray());
- _containerGrassEntries.Add(new(e.grassEntries));
- _containerGrassDoubleEntries.Add(new(e.grassDoubleEntries));
- _containerGrassSpecialEntries.Add(new(e.grassSpecialEntries));
- _containerSurfEntries.Add(new(e.surfEntries));
- _containerSurfSpecialEntries.Add(new(e.surfSpecialEntries));
- _containerFishEntries.Add(new(e.fishEntries));
- _containerFishSpecialEntries.Add(new(e.fishSpecialEntries));
- }
- SelectedSubentryIndex = 0;
- }
- }
- catch (Exception ex) {
- MessageHandler.ErrorMessage("Invalid wild encounter container", "This file is invalid.");
- }
- }
-
- public override void OnAddNew() {
-
- }
-
- public override void OnRemoveSelected(int index) {
-
- }
-
- public override void OnSaveChanges() {
- MemoryStream ms = new MemoryStream();
- for (int i = 0; i < _numberOfEntries; ++i) {
- ms.Write(new WildEncounters {
- grassEntries = new List(_containerGrassEntries[i]),
- grassDoubleEntries = new List(_containerGrassDoubleEntries[i]),
- grassSpecialEntries = new List(_containerGrassSpecialEntries[i]),
- surfEntries = new List(_containerSurfEntries[i]),
- surfSpecialEntries = new List(_containerSurfSpecialEntries[i]),
- fishEntries = new List(_containerFishEntries[i]),
- fishSpecialEntries = new List(_containerFishSpecialEntries[i]),
- }.serialize());
- }
- UI.Patcher.saveToNarcFolder(UI.GameInfo.wildEncounters, SelectedIndex, x => File.WriteAllBytes(x, ms.ToArray()));
- }
- }
-}
\ No newline at end of file
diff --git a/ViewModels/Editors/ZoneEditorViewModel.cs b/ViewModels/Editors/ZoneEditorViewModel.cs
new file mode 100644
index 0000000..9eb303f
--- /dev/null
+++ b/ViewModels/Editors/ZoneEditorViewModel.cs
@@ -0,0 +1,21 @@
+using SwissArmyKnife.ViewModels.Base;
+
+namespace SwissArmyKnife.ViewModels.Editors;
+
+public class ZoneEditorViewModel : EditorViewModelBase {
+ public override void OnAddNew() {
+ throw new System.NotImplementedException();
+ }
+ public override void OnRemoveSelected() {
+ throw new System.NotImplementedException();
+ }
+ public override void OnLoadFile() {
+ throw new System.NotImplementedException();
+ }
+ public override void OnSaveChanges() {
+ throw new System.NotImplementedException();
+ }
+ protected override void TryShowTabControl() {
+ throw new System.NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/Editors/ZoneEntitiesEditorViewModel.cs b/ViewModels/Editors/ZoneEntitiesEditorViewModel.cs
new file mode 100644
index 0000000..1aaa9e9
--- /dev/null
+++ b/ViewModels/Editors/ZoneEntitiesEditorViewModel.cs
@@ -0,0 +1,25 @@
+using SwissArmyKnife.ViewModels.Base;
+
+namespace SwissArmyKnife.ViewModels.Editors;
+
+public class ZoneEntitiesEditorViewModel : EditorViewModelBase {
+ public override void OnAddNew() {
+ throw new System.NotImplementedException();
+ }
+
+ public override void OnRemoveSelected() {
+ throw new System.NotImplementedException();
+ }
+
+ public override void OnLoadFile() {
+ throw new System.NotImplementedException();
+ }
+
+ public override void OnSaveChanges() {
+ throw new System.NotImplementedException();
+ }
+
+ protected override void TryShowTabControl() {
+ throw new System.NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/Editors/ZoneEntitiesViewModel.cs b/ViewModels/Editors/ZoneEntitiesViewModel.cs
deleted file mode 100644
index 2466f37..0000000
--- a/ViewModels/Editors/ZoneEntitiesViewModel.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Reactive;
-using System.Threading.Tasks;
-using BeaterLibrary.Formats.Overworld;
-using BeaterLibrary.Formats.Scripts;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Utils;
-
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public class ZoneEntitiesViewModel : ViewModelTemplate {
- private const int INTERACTABLES = 0,
- NPC = 1,
- WARPS = 2,
- TRIGGERS = 3,
- STATIC_INIT_SCRIPTS = 4,
- DYNAMIC_INIT_SCRIPTS = 5;
-
- private int _selectedIndex;
- private ZoneEntities _currentZoneEntities;
- private int[] _selectedSubIndices;
- public ObservableCollection Interactables { get; set; }
- public ObservableCollection NPCs { get; set; }
- public ObservableCollection Warps { get; set; }
- public ObservableCollection Triggers { get; set; }
- public ObservableCollection InitScripts { get; set; }
- public ObservableCollection TriggerRelated { get; set; }
-
- public ReactiveCommand OnAddNewListEntry { get; }
- public ReactiveCommand OnRemoveSelectedListEntry { get; }
-
- public ZoneEntities CurrentZoneEntities {
- get => _currentZoneEntities;
- set {
- this.RaiseAndSetIfChanged(ref _currentZoneEntities, value);
- this.RaisePropertyChanged();
- }
- }
- public int SelectedTab { get; set; }
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
-
- public int[] SelectedSubIndices {
- get => _selectedSubIndices;
- set {
- this.RaiseAndSetIfChanged(ref _selectedSubIndices, value);
- this.RaisePropertyChanged();
- }
- }
-
- public ZoneEntitiesViewModel() {
- OnAddNewListEntry = ReactiveCommand.Create(OnAddNewEntry);
- OnRemoveSelectedListEntry = ReactiveCommand.Create(OnRemoveSelectedEntry);
- SelectedSubIndices = new int[6];
- SelectedTab = 0;
- SelectedIndex = 0;
- }
-
- public override void OnAddNew() {
-
- }
-
- public override void OnRemoveSelected(int index) {
-
- }
-
- public void OnAddNewEntry() {
- switch (SelectedTab) {
- case INTERACTABLES:
- Interactables.Add(new Interactable());
- this.RaisePropertyChanged(nameof(Interactables));
- break;
- case NPC:
- NPCs.Add(new NPC());
- this.RaisePropertyChanged(nameof(NPCs));
- break;
- case WARPS:
- Warps.Add(new Warp());
- this.RaisePropertyChanged(nameof(Warps));
- break;
- case TRIGGERS:
- Triggers.Add(new Trigger());
- this.RaisePropertyChanged(nameof(Triggers));
- break;
- case STATIC_INIT_SCRIPTS:
- InitScripts.Add(new InitializationScript());
- this.RaisePropertyChanged(nameof(InitScripts));
- break;
- case DYNAMIC_INIT_SCRIPTS:
- TriggerRelated.Add(new TriggerRelated());
- this.RaisePropertyChanged(nameof(TriggerRelated));
- break;
- }
- }
-
- public override void OnIndexChange(int newValue) {
- if (newValue >= 0 && newValue < UI.Patcher.getNarcEntryCount(UI.GameInfo.zoneEntities)) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
- this.RaisePropertyChanged(nameof(SelectedIndex));
-
- CurrentZoneEntities = new ZoneEntities(UI.Patcher.fetchFileFromNarc(UI.GameInfo.zoneEntities, newValue));
- Interactables = new ObservableCollection(CurrentZoneEntities.interactables);
- NPCs = new ObservableCollection(CurrentZoneEntities.npcs);
- Warps = new ObservableCollection(CurrentZoneEntities.warps);
- Triggers = new ObservableCollection(CurrentZoneEntities.triggers);
- InitScripts = new ObservableCollection(CurrentZoneEntities.initializationScripts);
- TriggerRelated = new ObservableCollection(CurrentZoneEntities.triggerRelatedEntries);
-
- this.RaisePropertyChanged(nameof(Interactables));
- this.RaisePropertyChanged(nameof(NPCs));
- this.RaisePropertyChanged(nameof(Warps));
- this.RaisePropertyChanged(nameof(Triggers));
- this.RaisePropertyChanged(nameof(InitScripts));
- this.RaisePropertyChanged(nameof(TriggerRelated));
- }
- }
-
- public void OnRemoveSelectedEntry() {
- if (SelectedSubIndices[SelectedTab] > -1) {
- switch (SelectedTab) {
- case INTERACTABLES:
- Interactables.RemoveAt(SelectedSubIndices[SelectedTab]);
- this.RaisePropertyChanged(nameof(Interactables));
- break;
- case NPC:
- NPCs.RemoveAt(SelectedSubIndices[SelectedTab]);
- this.RaisePropertyChanged(nameof(NPCs));
- break;
- case WARPS:
- Warps.RemoveAt(SelectedSubIndices[SelectedTab]);
- this.RaisePropertyChanged(nameof(Warps));
- break;
- case TRIGGERS:
- Triggers.RemoveAt(SelectedSubIndices[SelectedTab]);
- this.RaisePropertyChanged(nameof(Triggers));
- break;
- case STATIC_INIT_SCRIPTS:
- InitScripts.RemoveAt(SelectedSubIndices[SelectedTab]);
- this.RaisePropertyChanged(nameof(InitScripts));
- break;
- case DYNAMIC_INIT_SCRIPTS:
- TriggerRelated.RemoveAt(SelectedSubIndices[SelectedTab]);
- this.RaisePropertyChanged(nameof(TriggerRelated));
- break;
- }
- }
- }
-
- public override void OnSaveChanges() {
- CurrentZoneEntities.interactables = new List(Interactables);
- CurrentZoneEntities.npcs = new List(NPCs);
- CurrentZoneEntities.warps = new List(Warps);
- CurrentZoneEntities.triggers = new List(Triggers);
- CurrentZoneEntities.initializationScripts = new List(InitScripts);
- CurrentZoneEntities.triggerRelatedEntries = new List(TriggerRelated);
- }
- }
-}
\ No newline at end of file
diff --git a/ViewModels/Editors/ZoneHeaderViewModel.cs b/ViewModels/Editors/ZoneHeaderViewModel.cs
deleted file mode 100644
index 5d38a81..0000000
--- a/ViewModels/Editors/ZoneHeaderViewModel.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Reactive;
-using BeaterLibrary.Formats.Maps;
-using BeaterLibrary.Formats.Text;
-using BeaterLibrary.GameInfo;
-using DynamicData.Kernel;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Utils;
-
-namespace SwissArmyKnife.Avalonia.ViewModels.Editors {
- public class ZoneHeaderViewModel : ViewModelTemplate {
- private int _selectedIndex, _selectedNameIndex;
- private List MapHeaders { get; set; }
- public ObservableCollection MapHeaderNames { get; }
- public ObservableCollection MapNames { get; }
- private MapHeader CurrentHeader => MapHeaders[SelectedIndex];
- public ReactiveCommand LoadZone { get; }
-
- public override int SelectedIndex {
- get => _selectedIndex;
- set => OnIndexChange(value);
- }
-
- public int SelectedNameIndex {
- get => CurrentHeader.nameIndex;
- set {
- CurrentHeader.nameIndex = (ushort) value;
- MapHeaderNames[SelectedIndex] = $"{SelectedIndex} - {MapNames[CurrentHeader.nameIndex]}";
- this.RaisePropertyChanged(nameof(MapHeaderNames));
- }
- }
-
- public ZoneHeaderViewModel() {
- LoadZone = ReactiveCommand.Create(() => {
- this.RaisePropertyChanged(nameof(CurrentHeader));
- this.RaisePropertyChanged(nameof(SelectedNameIndex));
- });
- var data = UI.Patcher.fetchFileFromNarc(UI.GameInfo.zoneHeaders, 0);
- MapHeaders = new MapHeaders(data).headers;
- MapNames = new ObservableCollection(
- new TextContainer(UI.Patcher.fetchFileFromNarc(UI.GameInfo.systemsText,
- UI.GameInfo.ImportantSystemText["MapNames"])).fetchTextAsStringArray());
- MapHeaderNames = new ObservableCollection();
- for (int i = 0; i < MapHeaders.Count; ++i) {
- MapHeaderNames.Add($"{i} - {MapNames[MapHeaders[i].nameIndex]}");
- }
- }
-
- public override void OnAddNew() {
- MapHeaders.Add(new MapHeader(MapHeaders.Count));
- }
-
- public override void OnRemoveSelected(int index) {
- if (index < MapHeaders.Count && index >= 0)
- MapHeaders.RemoveAt(index);
- }
-
- public override void OnIndexChange(int newValue) {
- if (newValue < MapHeaders.Count && newValue >= 0) {
- this.RaiseAndSetIfChanged(ref _selectedIndex, newValue);
- this.RaisePropertyChanged(nameof(SelectedIndex));
- }
- }
-
- public override void OnSaveChanges() {
- UI.Patcher.saveToNarcFolder(UI.GameInfo.zoneHeaders, 0, x => BeaterLibrary.Formats.Maps.MapHeaders.serialize(MapHeaders.AsList(), x));
- }
- }
-}
\ No newline at end of file
diff --git a/ViewModels/Main/FlowViewModel.cs b/ViewModels/Main/FlowViewModel.cs
new file mode 100644
index 0000000..8681ca6
--- /dev/null
+++ b/ViewModels/Main/FlowViewModel.cs
@@ -0,0 +1,17 @@
+using ReactiveUI;
+using SwissArmyKnife.ViewModels.Base;
+
+namespace SwissArmyKnife.ViewModels.Main;
+
+public class FlowViewModel : ViewModelBase {
+ private string _CurrentTabName, _WindowTitle;
+ public string CurrentTabName {
+ get => _CurrentTabName;
+ set => this.RaiseAndSetIfChanged(ref _CurrentTabName, value);
+ }
+
+ public string WindowTitle {
+ get => _WindowTitle;
+ set => this.RaiseAndSetIfChanged(ref _WindowTitle, value);
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/Main/StartupViewModel.cs b/ViewModels/Main/StartupViewModel.cs
new file mode 100644
index 0000000..465c2cb
--- /dev/null
+++ b/ViewModels/Main/StartupViewModel.cs
@@ -0,0 +1,121 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Reactive;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Hotswap.Configuration;
+using Hotswap.Project;
+using Material.Dialog;
+using ReactiveUI;
+using SwissArmyKnife.Handlers;
+using SwissArmyKnife.Models;
+using SwissArmyKnife.ViewModels.Base;
+using SwissArmyKnife.Views;
+
+namespace SwissArmyKnife.ViewModels.Main {
+ public class StartupViewModel : ViewModelBase {
+ public NewProjectModel ProjectModel { get; private set; }
+ public ReactiveCommand MakeProject { get; }
+ public ReactiveCommand OpenProject { get; }
+ public ReactiveCommand SelectPath { get; }
+ public GameEntry SelectedGameEntry { get; set; }
+ public List Games => GameWork.Patcher.BaseROMs.Games;
+ public int SelectedTab { get; set; }
+
+ public bool CanCreate => ProjectModel.Path.Length > 0 &&
+ ProjectModel.ProjectName.Length > 0 &&
+ ProjectModel.ProjectROMCode.Length > 0 &&
+ SelectedGameEntry != null;
+
+ public StartupViewModel() {
+ GameWork.Init(Handlers.Preferences.Prefs.BaseROMConfigurationPath);
+ ProjectModel = new NewProjectModel();
+ SelectPath = ReactiveCommand.Create(OnPathSelect);
+ MakeProject = ReactiveCommand.Create(OnCreateNewProject);
+ OpenProject = ReactiveCommand.Create(OnOpenProject);
+ SelectedTab = 1;
+ }
+
+ private async void OnPathSelect() {
+ if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string Res = await IO.OpenFolder(Desktop.MainWindow);
+ if (Res != null) {
+ ProjectModel.Path = Res;
+ }
+ }
+ }
+
+ private async void OnCreateNewProject() {
+ if (CanCreate) {
+ string? ProjectRoot = Path.Combine(ProjectModel.Path, ProjectModel.ProjectName);
+ HotswapProject HS = new HotswapProject() {
+ Base = SelectedGameEntry.Path,
+ Path = ProjectRoot,
+ Name = ProjectModel.ProjectName,
+ ROMCode = ProjectModel.ProjectROMCode,
+ VFS = "VFS",
+ User = "User",
+ };
+ HS.Generate(ProjectRoot);
+ if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ DialogResult Result = await Messages.YesNo(Desktop, "Project Creation Successful",
+ $"Your project \"{ProjectModel.ProjectName}\" has been created and stored at \"{ProjectRoot}\"." + "\n"
+ + "Would you like to open it now?");
+ if (Result.GetResult.Equals("Confirm")) {
+ LoadProject(Desktop, HS);
+ }
+ }
+ }
+ }
+
+ private async void OnOpenProject() {
+ List Filters = new List {
+ new() {
+ Name = "Project Configuration",
+ Extensions = new List {
+ "yml",
+ }
+ }
+ };
+ if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime Desktop) {
+ string? ProjectPath = await IO.OpenFile(Desktop.MainWindow, Filters);
+ if (ProjectPath != null) {
+ IProject Proj;
+ switch (Path.GetExtension(ProjectPath)) {
+ case ".yml":
+ Proj = new HotswapProject(ProjectPath);
+ break;
+ case ".cmproj":
+ Proj = new CTRMapProject(ProjectPath);
+ break;
+ default:
+ return;
+ }
+ LoadProject(Desktop, Proj);
+ }
+ }
+ }
+
+ private async void LoadProject(IClassicDesktopStyleApplicationLifetime Desktop, IProject Proj) {
+ if (GameWork.HandleProject(Proj) && GameWork.Patcher != null) {
+ DialogResult ScriptCommandDownloadPrompt = await Messages.YesNo(Desktop, "Update Script Commands", "Would you like to fetch the latest script commands? (Make sure you have internet before doing this).");
+ if (ScriptCommandDownloadPrompt.GetResult.Equals("Confirm")) {
+ if (!await Commands.Fetch()) {
+ Messages.Error(Desktop, "Fetching Error", "An error occurred when trying to fetch the latest script commands from the repository.\nThe previous version will be used.");
+ }
+ }
+ Window? StartupWindow = Desktop.MainWindow;
+ Desktop.MainWindow = new Flow {
+ DataContext = new FlowViewModel() {
+ WindowTitle = $"{GameWork.Project.Name} - SwissArmyKnife"
+ }
+ };
+ Desktop.MainWindow.Show();
+ StartupWindow.Close();
+ } else {
+ Messages.Error(Desktop, "Project Failed to Load", "An error occurred when loading your project. Make sure it is valid, then try again.");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs
deleted file mode 100644
index 01f917e..0000000
--- a/ViewModels/MainWindowViewModel.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reactive;
-using System.Threading.Tasks;
-using Avalonia.Controls;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.Utils;
-
-namespace SwissArmyKnife.Avalonia.ViewModels {
- public class MainWindowViewModel : ReactiveObject {
- private static Window _instance;
- public MainWindowViewModel(Window instance) {
- OpenProject = ReactiveCommand.Create(async () => {
- try {
- var result = await UI.OpenFile(instance, new List {
- new() {
- Name = "Project Configuration",
- Extensions = new List {
- "yml"
- }
- }
- });
- UI.InitializePatcher(PreferencesHandler.Prefs.BaseRomConfiguration, result);
- }
- catch (OperationCanceledException ex) {
- }
- });
- ExportRom = ReactiveCommand.Create(async () => {
- try {
- var result = await UI.SaveFile(instance, new List {
- new() {
- Name = "Nintendo DS ROM",
- Extensions = new List {
- "nds"
- }
- }
- });
- UI.Patcher.patchAndSerialize(result);
- }
- catch (OperationCanceledException ex) {
- }
- });
- }
-
- public ReactiveCommand OpenProject { get; }
- public ReactiveCommand SaveProject { get; }
- public ReactiveCommand ExportRom { get; }
- }
-}
\ No newline at end of file
diff --git a/ViewModels/NewProjectViewModel.cs b/ViewModels/NewProjectViewModel.cs
deleted file mode 100644
index a08114f..0000000
--- a/ViewModels/NewProjectViewModel.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
-using System.Reactive;
-using System.Threading.Tasks;
-using Avalonia.Controls;
-using Hotswap.Configuration;
-using MessageBox.Avalonia.Enums;
-using ReactiveUI;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.Utils;
-using SwissArmyKnife.Avalonia.Views;
-
-namespace SwissArmyKnife.Avalonia.ViewModels {
- public class NewProjectViewModel : ReactiveObject {
- private readonly baseROMConfiguration _baseRomConfig;
- private string _projectName;
- private string _projectPath;
- private int _selectedGame;
-
- public NewProjectViewModel(baseROMConfiguration baseRoMs, Window instance) {
- ProjectName = "";
- ProjectPath = "";
- _baseRomConfig = baseRoMs;
- this.BaseRoMs = new ObservableCollection(_baseRomConfig.games);
- SetDirectory = ReactiveCommand.Create(async () => {
- try {
- ProjectPath = await UI.OpenFolder(instance);
- }
- catch (OperationCanceledException ex) {
- }
- });
- CreateProject = ReactiveCommand.Create(async () => {
- var numErrors = 0;
- var errors = new List();
- if (ProjectName.Equals(string.Empty)) {
- errors.Add("Invalid project name!");
- numErrors++;
- }
-
- if (ProjectPath.Equals(string.Empty) || !Directory.Exists(ProjectPath)) {
- errors.Add("Invalid project path!");
- numErrors++;
- }
-
- if (SelectedGame is -1) {
- errors.Add("Game must be selected!");
- numErrors++;
- }
-
- if (numErrors > 0) {
- MessageHandler.ErrorMessage("Project Creation", string.Join('\n', errors));
- return;
- }
-
- if (CreateProjectStructure()) {
- instance.Close();
- if (await PromptLoadAfterCreation()) {
- try {
- UI.InitializePatcher(PreferencesHandler.Prefs.BaseRomConfiguration,
- Path.Combine(ProjectPath, ProjectName, $"{ProjectName}.yml"));
- UI.Patcher.handleROM(true);
- new MainWindow().Show();
- UI.Patcher.handleROM(false);
- }
- catch (Exception ex) {
- MessageHandler.ErrorMessage("Initialization Error", ex.Message);
- }
- }
- }
- });
- }
-
- public NewProjectViewModel() {
-
- }
-
- public ReactiveCommand SetDirectory { get; set; }
- public ReactiveCommand CreateProject { get; set; }
- public ObservableCollection BaseRoMs { get; }
-
- public int SelectedGame {
- get => _selectedGame;
- set {
- this.RaiseAndSetIfChanged(ref _selectedGame, value);
- this.RaisePropertyChanged("enableCreateButton");
- }
- }
-
- public bool EnableCreateButton => ProjectName.Length > 0 && ProjectPath.Length > 0 && SelectedGame != -1;
-
- public string ProjectName {
- get => _projectName;
- set {
- this.RaiseAndSetIfChanged(ref _projectName, value);
- this.RaisePropertyChanged("enableCreateButton");
- }
- }
-
- public string ProjectPath {
- get => _projectPath;
- set {
- this.RaiseAndSetIfChanged(ref _projectPath, value);
- this.RaisePropertyChanged("enableCreateButton");
- }
- }
-
- private bool CreateProjectStructure() {
- try {
- new Generator(ProjectName, ProjectPath, _baseRomConfig.getROMCode(BaseRoMs[SelectedGame]));
- return true;
- }
- catch (Exception e) {
- MessageHandler.ErrorMessage("Project Creation", $"Failed to create project. \"{e.Message}\"");
- return false;
- }
- }
-
- private async Task PromptLoadAfterCreation() {
- return await MessageHandler.YesNoMessage(
- "Project creation successful!",
- $"Your project \"{ProjectName}\" was successfully created at \"{Path.Combine(ProjectPath, ProjectName)}\".\nWould you like to load this project now?"
- ) == ButtonResult.Yes;
- }
- }
-}
\ No newline at end of file
diff --git a/Views/Flow.axaml b/Views/Flow.axaml
new file mode 100644
index 0000000..5942779
--- /dev/null
+++ b/Views/Flow.axaml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Views/Flow.axaml.cs b/Views/Flow.axaml.cs
new file mode 100644
index 0000000..6ba6295
--- /dev/null
+++ b/Views/Flow.axaml.cs
@@ -0,0 +1,21 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace SwissArmyKnife.Views;
+
+
+public partial class Flow : Window {
+ public Flow() {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+
+ private void InitializeComponent() {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/Views/MainWindow.axaml b/Views/MainWindow.axaml
deleted file mode 100644
index a1f9244..0000000
--- a/Views/MainWindow.axaml
+++ /dev/null
@@ -1,110 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Views/MainWindow.axaml.cs b/Views/MainWindow.axaml.cs
deleted file mode 100644
index 256f57b..0000000
--- a/Views/MainWindow.axaml.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.IO;
-using System.Xml;
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Interactivity;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using AvaloniaEdit.Highlighting;
-using AvaloniaEdit.Highlighting.Xshd;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.Pages;
-using SwissArmyKnife.Avalonia.Utils;
-using SwissArmyKnife.Avalonia.ViewModels;
-
-namespace SwissArmyKnife.Avalonia.Views {
- public class MainWindow : ReactiveWindow {
- private readonly ScriptEditor _scriptEditor;
- private readonly TextEditor _textEditor;
-
- public MainWindow() {
- InitializeComponent();
- DataContext = new MainWindowViewModel(this);
-#if DEBUG
- this.AttachDevTools();
-#endif
- _scriptEditor = this.FindControl("ScriptEditor");
- if (File.Exists("BeaterSyntax.xshd"))
- _scriptEditor.FindControl("ScriptEditorTextbox").SyntaxHighlighting =
- HighlightingLoader.Load(new XmlTextReader(File.Open("BeaterSyntax.xshd", FileMode.Open)),
- HighlightingManager.Instance);
- _textEditor = this.FindControl("TextEditorTextbox");
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
- }
-}
\ No newline at end of file
diff --git a/Views/NewProjectWindow.axaml b/Views/NewProjectWindow.axaml
deleted file mode 100644
index 0b611ef..0000000
--- a/Views/NewProjectWindow.axaml
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Views/NewProjectWindow.axaml.cs b/Views/NewProjectWindow.axaml.cs
deleted file mode 100644
index 311ee0a..0000000
--- a/Views/NewProjectWindow.axaml.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-using Hotswap.Configuration;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.ViewModels;
-
-namespace SwissArmyKnife.Avalonia.Views {
- public class NewProjectWindow : ReactiveWindow {
- public NewProjectWindow() {
- InitializeComponent();
- if (!Design.IsDesignMode)
- if (InitializePatcher())
- Show();
- }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-
- private bool InitializePatcher() {
- try {
- baseROMConfiguration configuration = new();
- configuration.initializePatcher(PreferencesHandler.Prefs
- .BaseRomConfiguration); // This call throws an exception if "BaseROM.yml" is not found.
- DataContext = new NewProjectViewModel(configuration, this);
- return true;
- }
- catch (Exception e) {
- MessageHandler.ErrorMessage("Initialization", e.Message);
- return false;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Views/ProjectManagementWindow.axaml b/Views/ProjectManagementWindow.axaml
deleted file mode 100644
index 6d513cb..0000000
--- a/Views/ProjectManagementWindow.axaml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Views/ProjectManagementWindow.axaml.cs b/Views/ProjectManagementWindow.axaml.cs
deleted file mode 100644
index 50a2d7e..0000000
--- a/Views/ProjectManagementWindow.axaml.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Interactivity;
-using Avalonia.Markup.Xaml;
-using SwissArmyKnife.Avalonia.Handlers;
-using SwissArmyKnife.Avalonia.Utils;
-
-namespace SwissArmyKnife.Avalonia.Views {
- public class ProjectManagementWindow : Window {
- public ProjectManagementWindow() {
- Instance = this;
- InitializeComponent();
-#if DEBUG
- this.AttachDevTools();
-#endif
- }
-
- public static Window? Instance { get; private set; }
-
- private void InitializeComponent() {
- AvaloniaXamlLoader.Load(this);
- }
-
- private async void OpenProjectButton(object? sender, RoutedEventArgs e) {
- try {
- var result = await UI.OpenFile(this, new List {
- new() {
- Name = "Project Configuration",
- Extensions = new List {
- "yml"
- }
- }
- });
- // Initialize the patcher object
- try {
- UI.InitializePatcher(PreferencesHandler.Prefs.BaseRomConfiguration, result);
- Hotswap.Patcher.isPreloading = true;
- UI.Patcher.handleROM(true);
- new MainWindow().Show();
- Hotswap.Patcher.isPreloading = false;
- UI.Patcher.handleROM(false);
- Close();
- }
- catch (Exception ex) {
- MessageHandler.ErrorMessage("Initialization Error", ex.Message);
- }
- }
- catch (OperationCanceledException ex) {
- }
- }
-
- private void NewProjectButton(object? sender, RoutedEventArgs e) {
- new NewProjectWindow();
- }
- }
-}
\ No newline at end of file
diff --git a/Views/Startup.axaml b/Views/Startup.axaml
new file mode 100644
index 0000000..76d64bf
--- /dev/null
+++ b/Views/Startup.axaml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Views/Startup.axaml.cs b/Views/Startup.axaml.cs
new file mode 100644
index 0000000..e6554a1
--- /dev/null
+++ b/Views/Startup.axaml.cs
@@ -0,0 +1,9 @@
+using Avalonia.Controls;
+
+namespace SwissArmyKnife.Views;
+
+public partial class StartupWindow : Window {
+ public StartupWindow() {
+ InitializeComponent();
+ }
+}
\ No newline at end of file