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.
|
||||
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 wall_w = (g.cell / 5.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 crate::seed;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Room {
|
||||
pub x: 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 {
|
||||
#[allow(dead_code)]
|
||||
pub id: u64,
|
||||
@@ -27,7 +28,7 @@ pub struct Corridor {
|
||||
pub width: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Door {
|
||||
pub from: (usize, usize),
|
||||
pub to: (usize, usize),
|
||||
@@ -39,7 +40,7 @@ pub struct Door {
|
||||
pub manual: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Window {
|
||||
pub cell: (usize, usize),
|
||||
pub side: WindowSide,
|
||||
@@ -47,20 +48,20 @@ pub struct Window {
|
||||
pub span_width: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TextLabel {
|
||||
pub cell: (usize, usize),
|
||||
pub text: String,
|
||||
pub font_size: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AreaMarker {
|
||||
pub cell: (usize, usize),
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum WindowSide {
|
||||
Left,
|
||||
Right,
|
||||
@@ -68,7 +69,7 @@ pub enum WindowSide {
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct DoorSettings {
|
||||
pub frequency_percent: usize,
|
||||
pub room_hallway_percent: usize,
|
||||
@@ -77,7 +78,7 @@ pub struct DoorSettings {
|
||||
pub allow_middle_corridor_doors: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct WindowSettings {
|
||||
pub enabled: bool,
|
||||
pub min_width: usize,
|
||||
@@ -87,7 +88,7 @@ pub struct WindowSettings {
|
||||
pub allow_internal_windows: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct DungeonLayout {
|
||||
pub rooms: Vec<Room>,
|
||||
pub corridors: Vec<Corridor>,
|
||||
|
||||
+18
@@ -1,5 +1,6 @@
|
||||
mod exporter;
|
||||
mod layout;
|
||||
mod saveandload;
|
||||
mod seed;
|
||||
mod settings;
|
||||
mod startend;
|
||||
@@ -139,6 +140,23 @@ impl eframe::App for DungeonApp {
|
||||
} else if panel_result.reset_clicked || panel_result.settings_changed {
|
||||
self.push_undo_snapshot();
|
||||
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)) {
|
||||
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 clear_clicked: bool,
|
||||
pub export_clicked: bool,
|
||||
pub save_clicked: bool,
|
||||
pub load_clicked: bool,
|
||||
}
|
||||
|
||||
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.separator();
|
||||
ui.add_space(8.0);
|
||||
|
||||
Reference in New Issue
Block a user