added basic laod save functionality
This commit is contained in:
+1
-1
@@ -529,7 +529,7 @@ fn raster_target_size(settings: &UiSettings) -> (u32, u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build an SVG document for the current layout.
|
// Build an SVG document for the current layout.
|
||||||
fn build_svg(layout: &DungeonLayout, settings: &UiSettings) -> String {
|
pub fn build_svg(layout: &DungeonLayout, settings: &UiSettings) -> String {
|
||||||
let g = ExportGeometry::new(settings.cols, settings.rows);
|
let g = ExportGeometry::new(settings.cols, settings.rows);
|
||||||
let wall_w = (g.cell / 5.0).max(1.0);
|
let wall_w = (g.cell / 5.0).max(1.0);
|
||||||
let door_w = (g.cell / 10.0).max(1.0);
|
let door_w = (g.cell / 10.0).max(1.0);
|
||||||
|
|||||||
+11
-10
@@ -1,8 +1,9 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashSet, VecDeque};
|
use std::collections::{HashSet, VecDeque};
|
||||||
|
|
||||||
use crate::seed;
|
use crate::seed;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Room {
|
pub struct Room {
|
||||||
pub x: usize,
|
pub x: usize,
|
||||||
pub y: usize,
|
pub y: usize,
|
||||||
@@ -17,7 +18,7 @@ impl Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Corridor {
|
pub struct Corridor {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
@@ -27,7 +28,7 @@ pub struct Corridor {
|
|||||||
pub width: usize,
|
pub width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Door {
|
pub struct Door {
|
||||||
pub from: (usize, usize),
|
pub from: (usize, usize),
|
||||||
pub to: (usize, usize),
|
pub to: (usize, usize),
|
||||||
@@ -39,7 +40,7 @@ pub struct Door {
|
|||||||
pub manual: bool,
|
pub manual: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub cell: (usize, usize),
|
pub cell: (usize, usize),
|
||||||
pub side: WindowSide,
|
pub side: WindowSide,
|
||||||
@@ -47,20 +48,20 @@ pub struct Window {
|
|||||||
pub span_width: bool,
|
pub span_width: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct TextLabel {
|
pub struct TextLabel {
|
||||||
pub cell: (usize, usize),
|
pub cell: (usize, usize),
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub font_size: u16,
|
pub font_size: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct AreaMarker {
|
pub struct AreaMarker {
|
||||||
pub cell: (usize, usize),
|
pub cell: (usize, usize),
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum WindowSide {
|
pub enum WindowSide {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
@@ -68,7 +69,7 @@ pub enum WindowSide {
|
|||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct DoorSettings {
|
pub struct DoorSettings {
|
||||||
pub frequency_percent: usize,
|
pub frequency_percent: usize,
|
||||||
pub room_hallway_percent: usize,
|
pub room_hallway_percent: usize,
|
||||||
@@ -77,7 +78,7 @@ pub struct DoorSettings {
|
|||||||
pub allow_middle_corridor_doors: bool,
|
pub allow_middle_corridor_doors: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct WindowSettings {
|
pub struct WindowSettings {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub min_width: usize,
|
pub min_width: usize,
|
||||||
@@ -87,7 +88,7 @@ pub struct WindowSettings {
|
|||||||
pub allow_internal_windows: bool,
|
pub allow_internal_windows: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct DungeonLayout {
|
pub struct DungeonLayout {
|
||||||
pub rooms: Vec<Room>,
|
pub rooms: Vec<Room>,
|
||||||
pub corridors: Vec<Corridor>,
|
pub corridors: Vec<Corridor>,
|
||||||
|
|||||||
+18
@@ -1,5 +1,6 @@
|
|||||||
mod exporter;
|
mod exporter;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod saveandload;
|
||||||
mod seed;
|
mod seed;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod startend;
|
mod startend;
|
||||||
@@ -139,6 +140,23 @@ impl eframe::App for DungeonApp {
|
|||||||
} else if panel_result.reset_clicked || panel_result.settings_changed {
|
} else if panel_result.reset_clicked || panel_result.settings_changed {
|
||||||
self.push_undo_snapshot();
|
self.push_undo_snapshot();
|
||||||
self.regenerate_layout();
|
self.regenerate_layout();
|
||||||
|
} else if panel_result.save_clicked {
|
||||||
|
let svg = exporter::build_svg(&self.layout, &self.settings);
|
||||||
|
if let Err(err) = saveandload::save_dungeon(&self.settings, &self.layout, svg) {
|
||||||
|
eprintln!("{err}");
|
||||||
|
}
|
||||||
|
} else if panel_result.load_clicked {
|
||||||
|
match saveandload::load_dungeon() {
|
||||||
|
Ok(data) => {
|
||||||
|
self.push_undo_snapshot();
|
||||||
|
self.settings = data.settings;
|
||||||
|
self.layout = data.layout;
|
||||||
|
// Don't regenerate_layout() here to preserve the exact loaded state.
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("{err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ctx.input(|i| i.key_pressed(egui::Key::Delete) || i.key_pressed(egui::Key::Backspace)) {
|
if ctx.input(|i| i.key_pressed(egui::Key::Delete) || i.key_pressed(egui::Key::Backspace)) {
|
||||||
self.pending_delete = true;
|
self.pending_delete = true;
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
use rfd::FileDialog;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::layout::DungeonLayout;
|
||||||
|
use crate::ui::UiSettings;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct DungeonSave {
|
||||||
|
pub settings: UiSettings,
|
||||||
|
pub layout: DungeonLayout,
|
||||||
|
pub svg: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_dungeon(
|
||||||
|
settings: &UiSettings,
|
||||||
|
layout: &DungeonLayout,
|
||||||
|
svg: String,
|
||||||
|
) -> Result<PathBuf, String> {
|
||||||
|
let path = FileDialog::new()
|
||||||
|
.set_title("Save Dungeon State")
|
||||||
|
.add_filter("Dungeon File", &["dungeon"])
|
||||||
|
.set_file_name("my_dungeon.dungeon")
|
||||||
|
.save_file()
|
||||||
|
.ok_or_else(|| "Save canceled".to_string())?;
|
||||||
|
|
||||||
|
let save_data = DungeonSave {
|
||||||
|
settings: settings.clone(),
|
||||||
|
layout: layout.clone(),
|
||||||
|
svg,
|
||||||
|
};
|
||||||
|
|
||||||
|
let json = serde_json::to_string_pretty(&save_data)
|
||||||
|
.map_err(|e| format!("Failed to serialize dungeon: {e}"))?;
|
||||||
|
|
||||||
|
fs::write(&path, json).map_err(|e| format!("Failed to write file: {e}"))?;
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_dungeon() -> Result<DungeonSave, String> {
|
||||||
|
let path = FileDialog::new()
|
||||||
|
.set_title("Load Dungeon State")
|
||||||
|
.add_filter("Dungeon File", &["dungeon"])
|
||||||
|
.pick_file()
|
||||||
|
.ok_or_else(|| "Load canceled".to_string())?;
|
||||||
|
|
||||||
|
let content = fs::read_to_string(path).map_err(|e| format!("Failed to read file: {e}"))?;
|
||||||
|
|
||||||
|
let save_data: DungeonSave =
|
||||||
|
serde_json::from_str(&content).map_err(|e| format!("Failed to parse dungeon file: {e}"))?;
|
||||||
|
|
||||||
|
Ok(save_data)
|
||||||
|
}
|
||||||
@@ -226,6 +226,8 @@ pub struct SidePanelResult {
|
|||||||
pub reset_clicked: bool,
|
pub reset_clicked: bool,
|
||||||
pub clear_clicked: bool,
|
pub clear_clicked: bool,
|
||||||
pub export_clicked: bool,
|
pub export_clicked: bool,
|
||||||
|
pub save_clicked: bool,
|
||||||
|
pub load_clicked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_side_panel(
|
pub fn draw_side_panel(
|
||||||
@@ -354,6 +356,16 @@ fn draw_generate_tab(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui.add_space(8.0);
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if ui.button("Save State").clicked() {
|
||||||
|
result.save_clicked = true;
|
||||||
|
}
|
||||||
|
if ui.button("Load State").clicked() {
|
||||||
|
result.load_clicked = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
|||||||
Reference in New Issue
Block a user