mirror of
https://github.com/Stone-Red-Code/StoneRed.LogicSimulator.git
synced 2026-09-04 09:06:29 +02:00
Implement load and save UI
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<Project StylesheetPath="C:\Users\David\My Drive\Programming\StoneRed.LogicSimulator\StoneRed.LogicSimulator\Content\stylesheet\default_ui_skin.xmms">
|
||||
<Project.ExportOptions />
|
||||
<Window Title="Load world" Left="266" Top="198" MinWidth="400">
|
||||
<VerticalStackPanel>
|
||||
<ListBox HorizontalAlignment="Stretch" Id="saves" />
|
||||
<TextButton Text="Load" Enabled="False" Margin="0, 10, 0, 0" Padding="5, 5, 8, 5" Id="load" />
|
||||
</VerticalStackPanel>
|
||||
</Window>
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project StylesheetPath="C:\Users\David\My Drive\Programming\StoneRed.LogicSimulator\StoneRed.LogicSimulator\Content\stylesheet\default_ui_skin.xmms">
|
||||
<Project.ExportOptions />
|
||||
<Window Title="Load world" Left="266" Top="201" MinWidth="400">
|
||||
<VerticalStackPanel>
|
||||
<ListBox HorizontalAlignment="Stretch" Id="saves" />
|
||||
<HorizontalStackPanel Spacing="10">
|
||||
<TextButton Text="Save" Enabled="False" Margin="0, 10, 0, 0" Padding="5, 5, 8, 5" Id="save" />
|
||||
<TextButton Text="New Save" Margin="0, 10, 0, 0" Padding="5, 5, 8, 5" Id="newSave" />
|
||||
</HorizontalStackPanel>
|
||||
</VerticalStackPanel>
|
||||
</Window>
|
||||
</Project>
|
||||
@@ -0,0 +1,81 @@
|
||||
using Myra.Utility;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace StoneRed.LogicSimulator.Misc;
|
||||
|
||||
internal static class Paths
|
||||
{
|
||||
public static string GetAppDataPath()
|
||||
{
|
||||
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
string srlsAppDataPath = Path.Combine(appDataPath, "StoneRed", "LogicSimulator");
|
||||
|
||||
if (!Directory.Exists(srlsAppDataPath))
|
||||
{
|
||||
_ = Directory.CreateDirectory(srlsAppDataPath);
|
||||
}
|
||||
|
||||
return srlsAppDataPath;
|
||||
}
|
||||
|
||||
public static string GetAppDataPath(string fileName)
|
||||
{
|
||||
return Path.Combine(GetAppDataPath(), fileName);
|
||||
}
|
||||
|
||||
public static string GetAppDataPath(params string[] paths)
|
||||
{
|
||||
return Path.Combine(GetAppDataPath(), Path.Combine(paths));
|
||||
}
|
||||
|
||||
public static string GetContentPath()
|
||||
{
|
||||
return Path.Combine(PathUtils.ExecutingAssemblyDirectory, "Content");
|
||||
}
|
||||
|
||||
public static string GetContentPath(string fileName)
|
||||
{
|
||||
return Path.Combine(GetContentPath(), fileName);
|
||||
}
|
||||
|
||||
public static string GetContentPath(params string[] paths)
|
||||
{
|
||||
return Path.Combine(GetContentPath(), Path.Combine(paths));
|
||||
}
|
||||
|
||||
public static string GetSettingsPath()
|
||||
{
|
||||
return Path.Combine(GetAppDataPath(), "settings.json");
|
||||
}
|
||||
|
||||
public static string GetWorldSavesPath()
|
||||
{
|
||||
string savesPath = Path.Combine(GetAppDataPath(), "Saves");
|
||||
|
||||
if (!Directory.Exists(savesPath))
|
||||
{
|
||||
_ = Directory.CreateDirectory(savesPath);
|
||||
}
|
||||
|
||||
return savesPath;
|
||||
}
|
||||
|
||||
public static string GetWorldSaveDirectoryPath(string saveName)
|
||||
{
|
||||
string savePath = Path.Combine(GetWorldSavesPath(), saveName);
|
||||
|
||||
if (!Directory.Exists(savePath))
|
||||
{
|
||||
_ = Directory.CreateDirectory(savePath);
|
||||
}
|
||||
|
||||
return savePath;
|
||||
}
|
||||
|
||||
public static string GetWorldSaveFilePath(string saveName)
|
||||
{
|
||||
return Path.Combine(GetWorldSaveDirectoryPath(saveName), saveName + ".srls");
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using StoneRed.LogicSimulator.Utilities;
|
||||
|
||||
namespace StoneRed.LogicSimulator.Utilities;
|
||||
namespace StoneRed.LogicSimulator.Misc;
|
||||
|
||||
internal class Settings
|
||||
{
|
||||
@@ -8,8 +8,8 @@ using MonoGame.Extended.Screens;
|
||||
using Myra;
|
||||
using Myra.Assets;
|
||||
using Myra.Graphics2D.UI;
|
||||
using Myra.Utility;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.UserInterface.Screens;
|
||||
using StoneRed.LogicSimulator.UserInterface.Windows;
|
||||
using StoneRed.LogicSimulator.Utilities;
|
||||
@@ -36,18 +36,11 @@ internal class Srls : Game
|
||||
|
||||
public Settings Settings { get; set; }
|
||||
|
||||
public string ContentPath { get; }
|
||||
|
||||
public string SettingsPath { get; }
|
||||
|
||||
public Srls()
|
||||
{
|
||||
Content.RootDirectory = "Content";
|
||||
|
||||
ContentPath = Path.Combine(PathUtils.ExecutingAssemblyDirectory, "Content");
|
||||
SettingsPath = Path.Combine(PathUtils.ExecutingAssemblyDirectory, "settings.json");
|
||||
|
||||
Settings = Settings.Load(SettingsPath) ?? new Settings()
|
||||
Settings = Settings.Load(Paths.GetSettingsPath()) ?? new Settings()
|
||||
{
|
||||
Resolution = new Resolution(GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height),
|
||||
Scale = 1
|
||||
@@ -101,7 +94,7 @@ internal class Srls : Game
|
||||
|
||||
public TextButton ShowContextMenu(string title, Point position, MenuItem[] menuItems, bool showButton = false)
|
||||
{
|
||||
string data = File.ReadAllText(Path.Combine(ContentPath, "ContextMenu.xmmp"));
|
||||
string data = File.ReadAllText(Paths.GetContentPath("ContextMenu.xmmp"));
|
||||
VerticalStackPanel contextMenu = (VerticalStackPanel)Project.LoadFromXml(data, AssetManager).Root;
|
||||
|
||||
contextMenu.FindChildById<Label>("title").Text = title;
|
||||
@@ -164,9 +157,9 @@ internal class Srls : Game
|
||||
Desktop = new Desktop();
|
||||
|
||||
FontSystem = new FontSystem();
|
||||
FontSystem.AddFont(File.ReadAllBytes(Path.Combine(ContentPath, "ManoloMono.ttf")));
|
||||
FontSystem.AddFont(File.ReadAllBytes(Paths.GetContentPath("ManoloMono.ttf")));
|
||||
|
||||
FileAssetResolver assetResolver = new FileAssetResolver(ContentPath);
|
||||
FileAssetResolver assetResolver = new FileAssetResolver(Paths.GetContentPath());
|
||||
AssetManager = new AssetManager(assetResolver);
|
||||
|
||||
LogicGatesManager = new LogicGatesManager();
|
||||
|
||||
@@ -41,6 +41,12 @@
|
||||
<None Update="Content\LoadingScreen.xmmp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Content\SaveWorldWindow.xmmp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Content\LoadWorldWindow.xmmp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Content\ManoloMono.ttf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -4,12 +4,9 @@ using Microsoft.Xna.Framework;
|
||||
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates;
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
using StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -17,14 +14,14 @@ namespace StoneRed.LogicSimulator.UserInterface.Screens;
|
||||
|
||||
internal class LoadingScreen : SrlsScreen<VerticalStackPanel>
|
||||
{
|
||||
private readonly string filePath;
|
||||
private readonly string saveName;
|
||||
private Label label = null!;
|
||||
private HorizontalProgressBar horizontalProgressBar = null!;
|
||||
protected override string XmmpPath => "LoadingScreen.xmmp";
|
||||
|
||||
public LoadingScreen(string filePath)
|
||||
public LoadingScreen(string saveName)
|
||||
{
|
||||
this.filePath = filePath;
|
||||
this.saveName = saveName;
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
@@ -43,8 +40,13 @@ internal class LoadingScreen : SrlsScreen<VerticalStackPanel>
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
Result<IEnumerable<LogicGate>> result = await worldLoader.LoadWorld(filePath, progress);
|
||||
if (result.IsFailed)
|
||||
Result<WorldData> result = await worldLoader.LoadWorld(saveName, progress);
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
srls.LoadScreen(new WorldScreen(result.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
Dialog.CreateMessageBox("Error", string.Join(',', result.Errors.Select(e => e.Message))).Show(srls.Desktop);
|
||||
}
|
||||
@@ -53,89 +55,6 @@ internal class LoadingScreen : SrlsScreen<VerticalStackPanel>
|
||||
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
return;
|
||||
|
||||
label.Text = $"Loading... {Math.Round(100 / horizontalProgressBar.Maximum * horizontalProgressBar.Value, 0)}%";
|
||||
if (horizontalProgressBar.Value >= horizontalProgressBar.Maximum)
|
||||
{
|
||||
Clock button = new Clock()
|
||||
{
|
||||
Id = 0,
|
||||
WorldData = new LogicGateWorldData()
|
||||
{
|
||||
Name = "Clock",
|
||||
Position = new Vector2(0, 0)
|
||||
}
|
||||
};
|
||||
|
||||
Switch @switch = new Switch()
|
||||
{
|
||||
Id = 1,
|
||||
WorldData = new LogicGateWorldData()
|
||||
{
|
||||
Name = "Switch",
|
||||
Position = new Vector2(0, 200)
|
||||
}
|
||||
};
|
||||
|
||||
NotGate testLogicGate1 = new NotGate()
|
||||
{
|
||||
Id = 2,
|
||||
WorldData = new LogicGateWorldData()
|
||||
{
|
||||
Name = "Not Gate",
|
||||
Position = new Vector2(200, 200)
|
||||
}
|
||||
};
|
||||
|
||||
Pin testLogicGate2 = new Pin()
|
||||
{
|
||||
Id = 3,
|
||||
WorldData = new LogicGateWorldData()
|
||||
{
|
||||
Name = "Pin",
|
||||
Position = new Vector2(400, 400)
|
||||
}
|
||||
};
|
||||
|
||||
Pin testLogicGate3 = new Pin()
|
||||
{
|
||||
Id = 4,
|
||||
WorldData = new LogicGateWorldData()
|
||||
{
|
||||
Name = "Pin",
|
||||
Position = new Vector2(500, 500)
|
||||
}
|
||||
};
|
||||
|
||||
Lamp lamp = new Lamp()
|
||||
{
|
||||
Id = 5,
|
||||
WorldData = new LogicGateWorldData()
|
||||
{
|
||||
Name = "Lamp",
|
||||
Position = new Vector2(600, 600)
|
||||
}
|
||||
};
|
||||
|
||||
button.Connect(testLogicGate1, 0, 0);
|
||||
@switch.Connect(testLogicGate1, 0, 0);
|
||||
testLogicGate1.Connect(testLogicGate2, 0, 0);
|
||||
testLogicGate2.Connect(testLogicGate3, 0, 0);
|
||||
testLogicGate3.Connect(lamp, 0, 0);
|
||||
|
||||
List<LogicGate> logicGates = new List<LogicGate>
|
||||
{
|
||||
testLogicGate3,
|
||||
button,
|
||||
testLogicGate1,
|
||||
testLogicGate2,
|
||||
lamp,
|
||||
@switch
|
||||
};
|
||||
|
||||
srls.LoadScreen(new WorldScreen(logicGates));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime)
|
||||
|
||||
@@ -4,6 +4,8 @@ using MonoGame.Extended.Screens;
|
||||
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
@@ -20,7 +22,7 @@ internal abstract class SrlsScreen
|
||||
{
|
||||
this.srls = srls;
|
||||
|
||||
string data = File.ReadAllText(Path.Combine(srls.ContentPath, XmmpPath));
|
||||
string data = File.ReadAllText(Paths.GetContentPath(XmmpPath));
|
||||
srls.Desktop.Root = Project.LoadFromXml(data, srls.AssetManager).Root;
|
||||
|
||||
GameScreenWrapper gameScreenWrapper = new GameScreenWrapper(srls);
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
using Myra.Graphics2D.UI;
|
||||
using Myra.Graphics2D.UI.File;
|
||||
|
||||
using StoneRed.LogicSimulator.UserInterface.Windows;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StoneRed.LogicSimulator.UserInterface.Screens;
|
||||
|
||||
internal class StartScreen : SrlsScreen<VerticalStackPanel>
|
||||
@@ -32,21 +29,6 @@ internal class StartScreen : SrlsScreen<VerticalStackPanel>
|
||||
|
||||
private void MenuLoad_Selected(object? sender, System.EventArgs e)
|
||||
{
|
||||
FileDialog fileDialog = new FileDialog(FileDialogMode.OpenFile);
|
||||
|
||||
fileDialog.Show(srls.Desktop);
|
||||
fileDialog.Scale = new Vector2(srls.Scale / 3);
|
||||
fileDialog.Closed += async (s, a) =>
|
||||
{
|
||||
if (!fileDialog.Result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Very cheap workaround to make sure the file dialog is closed before loading the screen
|
||||
await Task.Delay(100);
|
||||
|
||||
srls.LoadScreen(new LoadingScreen(fileDialog.FilePath));
|
||||
};
|
||||
srls.ShowWindow<LoadWorldWindow>();
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,9 @@ using StoneRed.LogicSimulator.Simulation;
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
using StoneRed.LogicSimulator.UserInterface.Windows;
|
||||
using StoneRed.LogicSimulator.Utilities;
|
||||
using StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using IColorable = StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces.IColorable;
|
||||
@@ -26,6 +26,7 @@ internal class WorldScreen : SrlsScreen<Grid>
|
||||
{
|
||||
private readonly LogicGateSimulator simulator;
|
||||
private readonly Vector2 logicGateSize = new Vector2(100, 100);
|
||||
private readonly WorldData worldData;
|
||||
private OrthographicCamera camera = null!;
|
||||
private RichTextLayout richTextLayout = null!;
|
||||
|
||||
@@ -45,14 +46,16 @@ internal class WorldScreen : SrlsScreen<Grid>
|
||||
public override bool ScalingEnabled => false;
|
||||
protected override string XmmpPath => "WorldScreen.xmmp";
|
||||
|
||||
public WorldScreen(IEnumerable<LogicGate> logicGates)
|
||||
public WorldScreen(WorldData worldData)
|
||||
{
|
||||
simulator = new LogicGateSimulator(logicGates);
|
||||
simulator = new LogicGateSimulator(worldData.LogicGates);
|
||||
this.worldData = worldData;
|
||||
}
|
||||
|
||||
public WorldScreen()
|
||||
{
|
||||
simulator = new LogicGateSimulator(Enumerable.Empty<LogicGate>());
|
||||
worldData = new WorldData(Enumerable.Empty<LogicGate>(), 1, string.Empty);
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
@@ -230,7 +233,8 @@ internal class WorldScreen : SrlsScreen<Grid>
|
||||
|
||||
if (keyboardState.IsKeyDown(Keys.Q))
|
||||
{
|
||||
srls.ShowWindow<QuickMenu>();
|
||||
worldData.LogicGates = simulator.GetLogicGates();
|
||||
srls.ShowWindow(new QuickMenu(worldData));
|
||||
}
|
||||
|
||||
previousMouseState = mouseState;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.UserInterface.Screens;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace StoneRed.LogicSimulator.UserInterface.Windows;
|
||||
|
||||
internal class LoadWorldWindow : SrlsWindow
|
||||
{
|
||||
private ListBox savesListBox = null!;
|
||||
private TextButton loadButton = null!;
|
||||
|
||||
protected override string XmmpPath => "LoadWorldWindow.xmmp";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
savesListBox = window.FindChildById<ListBox>("saves");
|
||||
loadButton = window.FindChildById<TextButton>("load");
|
||||
|
||||
loadButton.Click += LoadButton_Clicked;
|
||||
|
||||
foreach (string directories in Directory.GetDirectories(Paths.GetWorldSavesPath()))
|
||||
{
|
||||
string saveName = Path.GetFileName(directories) ?? string.Empty;
|
||||
savesListBox.Items.Add(new(saveName));
|
||||
}
|
||||
|
||||
savesListBox.SelectedIndexChanged += SavesListBox_SelectedIndexChanged;
|
||||
}
|
||||
|
||||
private void SavesListBox_SelectedIndexChanged(object? sender, EventArgs e)
|
||||
{
|
||||
loadButton.Enabled = savesListBox.SelectedItem is not null;
|
||||
}
|
||||
|
||||
private void LoadButton_Clicked(object? sender, EventArgs e)
|
||||
{
|
||||
srls.LoadScreen(new LoadingScreen(savesListBox.SelectedItem.Text));
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,29 @@
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.UserInterface.Screens;
|
||||
using StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
|
||||
namespace StoneRed.LogicSimulator.UserInterface.Windows;
|
||||
|
||||
internal class QuickMenu : SrlsWindow
|
||||
{
|
||||
private readonly WorldData worldData;
|
||||
|
||||
protected override string XmmpPath => "QuickMenu.xmmp";
|
||||
|
||||
public QuickMenu(WorldData worldData)
|
||||
{
|
||||
this.worldData = worldData;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
VerticalMenu menu = window.FindChildById<VerticalMenu>("menu");
|
||||
|
||||
menu.FindMenuItemById("menuMainMenu").Selected += (s, a) => srls.LoadScreen<StartScreen>();
|
||||
menu.FindMenuItemById("menuSettings").Selected += (s, a) => srls.ShowWindow<SettingsWindow>();
|
||||
menu.FindMenuItemById("menuSave").Selected += (s, a) => srls.ShowWindow<SettingsWindow>();
|
||||
menu.FindMenuItemById("menuLoad").Selected += (s, a) => srls.ShowWindow<SettingsWindow>();
|
||||
menu.FindMenuItemById("menuSave").Selected += (s, a) => srls.ShowWindow(new SaveWorldWindow(worldData));
|
||||
menu.FindMenuItemById("menuLoad").Selected += (s, a) => srls.ShowWindow<LoadWorldWindow>();
|
||||
menu.FindMenuItemById("menuQuit").Selected += QuickMenu_Selected;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using FluentResults;
|
||||
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StoneRed.LogicSimulator.UserInterface.Windows;
|
||||
|
||||
internal class SaveWorldWindow : SrlsWindow
|
||||
{
|
||||
private readonly WorldData worldData;
|
||||
private ListBox savesListBox = null!;
|
||||
private TextButton saveButton = null!;
|
||||
|
||||
protected override string XmmpPath => "SaveWorldWindow.xmmp";
|
||||
|
||||
public SaveWorldWindow(WorldData worldData)
|
||||
{
|
||||
this.worldData = worldData;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
savesListBox = window.FindChildById<ListBox>("saves");
|
||||
saveButton = window.FindChildById<TextButton>("save");
|
||||
TextButton newSaveButton = window.FindChildById<TextButton>("newSave");
|
||||
|
||||
saveButton.Click += SaveButton_Clicked;
|
||||
newSaveButton.Click += NewSaveButton_Click;
|
||||
|
||||
foreach (string directories in Directory.GetDirectories(Paths.GetWorldSavesPath()))
|
||||
{
|
||||
string saveName = Path.GetFileName(directories) ?? string.Empty;
|
||||
savesListBox.Items.Add(new(saveName));
|
||||
}
|
||||
|
||||
savesListBox.SelectedIndexChanged += SavesListBox_SelectedIndexChanged;
|
||||
}
|
||||
|
||||
private void SavesListBox_SelectedIndexChanged(object? sender, EventArgs e)
|
||||
{
|
||||
saveButton.Enabled = savesListBox.SelectedItem is not null;
|
||||
}
|
||||
|
||||
private async void NewSaveButton_Click(object? sender, EventArgs e)
|
||||
{
|
||||
worldData.SaveName = "New Save";
|
||||
await Save();
|
||||
}
|
||||
|
||||
private async void SaveButton_Clicked(object? sender, EventArgs e)
|
||||
{
|
||||
await Save();
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
WorldSaver worldSaver = new WorldSaver(srls);
|
||||
Result result = await worldSaver.SaveWorld(worldData, new Progress<WorldSaveLoadProgress>());
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
_ = Dialog.CreateMessageBox("Success", "Saved world!");
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Dialog.CreateMessageBox("Error", string.Join(',', result.Errors.Select(e => e.Message)));
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.Utilities;
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -53,7 +54,7 @@ internal class SettingsWindow : SrlsWindow
|
||||
|
||||
srls.Settings.Resolution = newResolution;
|
||||
srls.Settings.Scale = scaleSpinButton.Value.GetValueOrDefault(1);
|
||||
srls.Settings.Save(srls.SettingsPath);
|
||||
srls.Settings.Save(Paths.GetSettingsPath());
|
||||
|
||||
window.Close();
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
@@ -23,7 +25,7 @@ internal abstract class SrlsWindow
|
||||
{
|
||||
this.srls = srls;
|
||||
|
||||
string data = File.ReadAllText(Path.Combine(srls.ContentPath, XmmpPath));
|
||||
string data = File.ReadAllText(Paths.GetContentPath(XmmpPath));
|
||||
window = (Window)Project.LoadFromXml(data, srls.AssetManager).Root;
|
||||
window.Closed += (_, _) => Closed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
|
||||
internal class WorldData
|
||||
{
|
||||
public IEnumerable<LogicGate> LogicGates { get; set; }
|
||||
|
||||
public int SaveVersion { get; set; }
|
||||
|
||||
public string SaveName { get; set; }
|
||||
|
||||
public WorldData(IEnumerable<LogicGate> logicGates, int saveVersion, string saveName)
|
||||
{
|
||||
LogicGates = logicGates;
|
||||
SaveVersion = saveVersion;
|
||||
SaveName = saveName;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using FluentResults;
|
||||
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.WorldSaveSystem.WorldReaders;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -19,9 +18,9 @@ internal class WorldLoader
|
||||
this.srls = srls;
|
||||
}
|
||||
|
||||
public Task<Result<IEnumerable<LogicGate>>> LoadWorld(string filePath, IProgress<WorldSaveLoadProgress> progress)
|
||||
public Task<Result<WorldData>> LoadWorld(string saveName, IProgress<WorldSaveLoadProgress> progress)
|
||||
{
|
||||
BinaryReader binaryReader = new BinaryReader(File.OpenRead(filePath));
|
||||
BinaryReader binaryReader = new BinaryReader(File.OpenRead(Paths.GetWorldSaveFilePath(saveName)));
|
||||
ushort fileVersion = binaryReader.ReadUInt16();
|
||||
binaryReader.Close();
|
||||
|
||||
@@ -33,9 +32,9 @@ internal class WorldLoader
|
||||
|
||||
if (worldReader is null)
|
||||
{
|
||||
return Task.FromResult(Result.Fail<IEnumerable<LogicGate>>("Invalid file version!"));
|
||||
return Task.FromResult(Result.Fail<WorldData>("Invalid file version!"));
|
||||
}
|
||||
|
||||
return worldReader.ReadWorld(filePath, progress);
|
||||
return worldReader.ReadWorld(saveName, progress);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
using FluentResults;
|
||||
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StoneRed.LogicSimulator.WorldSaveSystem.WorldReaders;
|
||||
|
||||
internal interface IWorldReader
|
||||
{
|
||||
Task<Result<IEnumerable<LogicGate>>> ReadWorld(string filePath, IProgress<WorldSaveLoadProgress> progress);
|
||||
Task<Result<WorldData>> ReadWorld(string saveName, IProgress<WorldSaveLoadProgress> progress);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using FluentResults;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
|
||||
using System;
|
||||
@@ -19,17 +20,17 @@ internal class WorldReaderV1 : IWorldReader
|
||||
this.srls = srls;
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<LogicGate>>> ReadWorld(string filePath, IProgress<WorldSaveLoadProgress> progress)
|
||||
public async Task<Result<WorldData>> ReadWorld(string saveName, IProgress<WorldSaveLoadProgress> progress)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
if (!File.Exists(Paths.GetWorldSaveFilePath(saveName)))
|
||||
{
|
||||
return Result.Fail($"File \"{filePath}\" does not exist");
|
||||
return Result.Fail($"Save \"{saveName}\" does not exist");
|
||||
}
|
||||
|
||||
return await Task.Run(() => InternalReadWorld(filePath, progress));
|
||||
return await Task.Run(() => InternalReadWorld(saveName, progress));
|
||||
}
|
||||
|
||||
public Result<IEnumerable<LogicGate>> InternalReadWorld(string filePath, IProgress<WorldSaveLoadProgress> progress)
|
||||
public Result<WorldData> InternalReadWorld(string saveName, IProgress<WorldSaveLoadProgress> progress)
|
||||
{
|
||||
BinaryReader? reader = null;
|
||||
Dictionary<LogicGate, List<(ulong GateRefId, int inputIndex, int outputIndex)>> connections = new();
|
||||
@@ -38,19 +39,23 @@ internal class WorldReaderV1 : IWorldReader
|
||||
{
|
||||
progress.Report(new(0, "Opening file"));
|
||||
|
||||
reader = new BinaryReader(File.OpenRead(filePath));
|
||||
_ = reader.ReadUInt16(); // File version
|
||||
reader = new BinaryReader(File.OpenRead(Paths.GetWorldSaveFilePath(saveName)));
|
||||
int saveVersion = reader.ReadUInt16();
|
||||
|
||||
int numberOfLogicGates = reader.ReadInt32();
|
||||
|
||||
for (int gateNumber = 0; gateNumber < numberOfLogicGates; gateNumber++)
|
||||
{
|
||||
progress.Report(new((int)((double)gateNumber / numberOfLogicGates * 50d), $"Loading logic gates ({gateNumber / numberOfLogicGates})"));
|
||||
progress.Report(new((int)((double)gateNumber / numberOfLogicGates * 50d), $"Loading logic gates ({gateNumber}/{numberOfLogicGates})"));
|
||||
|
||||
ulong id = reader.ReadUInt64();
|
||||
string typeName = reader.ReadString();
|
||||
int inputCount = reader.ReadInt32();
|
||||
int outputCount = reader.ReadInt32();
|
||||
string name = reader.ReadString();
|
||||
string description = reader.ReadString();
|
||||
float positionX = reader.ReadSingle();
|
||||
float positionY = reader.ReadSingle();
|
||||
int numberOfConnections = reader.ReadInt32();
|
||||
|
||||
if (srls.LogicGatesManager.TryCreateLogicGate(typeName, out LogicGate? logicGate))
|
||||
@@ -58,6 +63,9 @@ internal class WorldReaderV1 : IWorldReader
|
||||
logicGate.Id = id;
|
||||
logicGate.InputCount = inputCount;
|
||||
logicGate.OutputCount = outputCount;
|
||||
logicGate.WorldData.Name = name;
|
||||
logicGate.WorldData.Description = description;
|
||||
logicGate.WorldData.Position = new(positionX, positionY);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -80,7 +88,7 @@ internal class WorldReaderV1 : IWorldReader
|
||||
|
||||
foreach (KeyValuePair<LogicGate, List<(ulong gateRefId, int inputIndex, int outputIndex)>> connectionPair in connections)
|
||||
{
|
||||
progress.Report(new((int)((double)connections.Count / connectionCount * 50d), $"Connecting logic gates ({connections.Count / connectionCount})"));
|
||||
progress.Report(new((int)((double)connectionCount / connections.Count * 50d), $"Connecting logic gates ({connectionCount}/{connections.Count})"));
|
||||
|
||||
LogicGate logicGate = connectionPair.Key;
|
||||
|
||||
@@ -98,6 +106,8 @@ internal class WorldReaderV1 : IWorldReader
|
||||
|
||||
connectionCount++;
|
||||
}
|
||||
|
||||
return new WorldData(connections.Keys, saveVersion, saveName);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
@@ -107,7 +117,5 @@ internal class WorldReaderV1 : IWorldReader
|
||||
{
|
||||
reader?.Dispose();
|
||||
}
|
||||
|
||||
return connections.Keys;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,34 @@
|
||||
namespace StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
using FluentResults;
|
||||
|
||||
using StoneRed.LogicSimulator.WorldSaveSystem.WorldWriters;
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StoneRed.LogicSimulator.WorldSaveSystem;
|
||||
|
||||
internal class WorldSaver
|
||||
{
|
||||
private readonly Srls srls;
|
||||
|
||||
public WorldSaver(Srls srls)
|
||||
{
|
||||
this.srls = srls;
|
||||
}
|
||||
|
||||
public Task<Result> SaveWorld(WorldData worldData, IProgress<WorldSaveLoadProgress> progress)
|
||||
{
|
||||
IWorldWriter? worldWriter = worldData.SaveVersion switch
|
||||
{
|
||||
1 => new WorldWriterV1(srls),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (worldWriter is null)
|
||||
{
|
||||
return Task.FromResult(Result.Fail("Invalid file version!"));
|
||||
}
|
||||
|
||||
return worldWriter.WriteWorld(worldData, progress);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
using FluentResults;
|
||||
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StoneRed.LogicSimulator.WorldSaveSystem.WorldWriters;
|
||||
|
||||
internal interface IWorldWriter
|
||||
{
|
||||
Task<Result> WriteWorld(string filePath, IEnumerable<LogicGate> logicGates, IProgress<WorldSaveLoadProgress> progress);
|
||||
Task<Result> WriteWorld(WorldData worldData, IProgress<WorldSaveLoadProgress> progress);
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using FluentResults;
|
||||
|
||||
using StoneRed.LogicSimulator.Misc;
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Attributes;
|
||||
using StoneRed.LogicSimulator.Simulation.LogicGates.Interfaces;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -20,27 +20,29 @@ internal class WorldWriterV1 : IWorldWriter
|
||||
this.srls = srls;
|
||||
}
|
||||
|
||||
public Task<Result> WriteWorld(string filePath, IEnumerable<LogicGate> logicGates, IProgress<WorldSaveLoadProgress> progress)
|
||||
public Task<Result> WriteWorld(WorldData worldData, IProgress<WorldSaveLoadProgress> progress)
|
||||
{
|
||||
return Task.Run(() => InternalWriteWorld(filePath, logicGates, progress));
|
||||
return Task.Run(() => InternalWriteWorld(worldData, progress));
|
||||
}
|
||||
|
||||
private Result InternalWriteWorld(string filePath, IEnumerable<LogicGate> logicGates, IProgress<WorldSaveLoadProgress> progress)
|
||||
private Result InternalWriteWorld(WorldData worldData, IProgress<WorldSaveLoadProgress> progress)
|
||||
{
|
||||
BinaryWriter? writer = null;
|
||||
|
||||
try
|
||||
{
|
||||
writer = new BinaryWriter(File.OpenWrite(filePath));
|
||||
string filePath = Paths.GetWorldSaveFilePath(worldData.SaveName);
|
||||
|
||||
writer = new BinaryWriter(File.Open(filePath, FileMode.Create));
|
||||
|
||||
progress.Report(new(0, "Counting logic gates"));
|
||||
|
||||
int numberOfLogicGates = logicGates.Count();
|
||||
int numberOfLogicGates = worldData.LogicGates.Count();
|
||||
|
||||
writer.Write(1); // Write file version
|
||||
writer.Write((short)1); // Write file version
|
||||
writer.Write(numberOfLogicGates);
|
||||
|
||||
foreach (LogicGate logicGate in logicGates)
|
||||
foreach (LogicGate logicGate in worldData.LogicGates)
|
||||
{
|
||||
writer.Write(logicGate.Id);
|
||||
|
||||
@@ -52,6 +54,10 @@ internal class WorldWriterV1 : IWorldWriter
|
||||
writer.Write(typeName);
|
||||
writer.Write(logicGate.InputCount);
|
||||
writer.Write(logicGate.OutputCount);
|
||||
writer.Write(logicGate.WorldData.Name);
|
||||
writer.Write(logicGate.WorldData.Description);
|
||||
writer.Write(logicGate.WorldData.Position.X);
|
||||
writer.Write(logicGate.WorldData.Position.Y);
|
||||
writer.Write(logicGate.LogicGateConnections.Count);
|
||||
|
||||
foreach (LogicGateConnection connection in logicGate.LogicGateConnections)
|
||||
|
||||
Reference in New Issue
Block a user