move menu work, start on preliminary save system
This commit is contained in:
Generated
+106
@@ -184,6 +184,18 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "app_dirs2"
|
||||||
|
version = "2.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7e7b35733e3a8c1ccb90385088dd5b6eaa61325cb4d1ad56e683b5224ff352e"
|
||||||
|
dependencies = [
|
||||||
|
"jni 0.21.1",
|
||||||
|
"ndk-context",
|
||||||
|
"winapi",
|
||||||
|
"xdg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "approx"
|
name = "approx"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -2269,6 +2281,37 @@ version = "2.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06"
|
checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"defmt-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt-macros"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8"
|
||||||
|
dependencies = [
|
||||||
|
"defmt-parser",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt-parser"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@@ -3141,6 +3184,59 @@ version = "1.0.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff"
|
||||||
|
version = "0.2.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc"
|
||||||
|
dependencies = [
|
||||||
|
"defmt",
|
||||||
|
"jiff-core",
|
||||||
|
"jiff-static",
|
||||||
|
"jiff-tzdb-platform",
|
||||||
|
"log",
|
||||||
|
"portable-atomic",
|
||||||
|
"portable-atomic-util",
|
||||||
|
"serde_core",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09"
|
||||||
|
dependencies = [
|
||||||
|
"defmt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff-static"
|
||||||
|
version = "0.2.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204"
|
||||||
|
dependencies = [
|
||||||
|
"jiff-core",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff-tzdb"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff-tzdb-platform"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
|
||||||
|
dependencies = [
|
||||||
|
"jiff-tzdb",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.21.1"
|
version = "0.21.1"
|
||||||
@@ -5090,8 +5186,12 @@ dependencies = [
|
|||||||
name = "tt_net_test_vibeless"
|
name = "tt_net_test_vibeless"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"app_dirs2",
|
||||||
"bevy",
|
"bevy",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"jiff",
|
||||||
|
"ron",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6078,6 +6178,12 @@ version = "0.3.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23"
|
checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xdg"
|
||||||
|
version = "2.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xkbcommon-dl"
|
name = "xkbcommon-dl"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|||||||
+5
-1
@@ -4,8 +4,12 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.19"
|
app_dirs2 = "2.5.5"
|
||||||
|
bevy = { version = "0.19", features = ["system_clipboard"] }
|
||||||
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
||||||
|
jiff = { version = "0.2.35", features = ["serde"] }
|
||||||
|
ron = "0.12.2"
|
||||||
|
serde = { version = "1.0.229", features = ["derive"] }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|||||||
+4
-1
@@ -2,8 +2,11 @@ use bevy::{camera::ScalingMode, color::palettes::css::GREEN, prelude::*};
|
|||||||
use main_menu::MainMenuPlugin;
|
use main_menu::MainMenuPlugin;
|
||||||
use networking::NetworkingPlugin;
|
use networking::NetworkingPlugin;
|
||||||
|
|
||||||
|
use crate::save::SavePlugin;
|
||||||
|
|
||||||
mod main_menu;
|
mod main_menu;
|
||||||
mod networking;
|
mod networking;
|
||||||
|
mod save;
|
||||||
|
|
||||||
/// We target this 16:9 resolution to make things easier.
|
/// We target this 16:9 resolution to make things easier.
|
||||||
pub const WINDOW_TARGET_WIDTH_U32: u32 = 3840;
|
pub const WINDOW_TARGET_WIDTH_U32: u32 = 3840;
|
||||||
@@ -22,7 +25,7 @@ pub enum AppState {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins((DefaultPlugins, MainMenuPlugin, NetworkingPlugin))
|
.add_plugins((DefaultPlugins, MainMenuPlugin, NetworkingPlugin, SavePlugin))
|
||||||
.add_systems(Startup, setup)
|
.add_systems(Startup, setup)
|
||||||
.add_systems(Update, debug_border)
|
.add_systems(Update, debug_border)
|
||||||
.insert_resource(ClearColor(Color::srgb(0.07, 0.33, 0.45)))
|
.insert_resource(ClearColor(Color::srgb(0.07, 0.33, 0.45)))
|
||||||
|
|||||||
+110
-19
@@ -1,4 +1,8 @@
|
|||||||
|
use crate::save::get_saves;
|
||||||
use crate::{AppState, WINDOW_TARGET_HEIGHT, WINDOW_TARGET_WIDTH};
|
use crate::{AppState, WINDOW_TARGET_HEIGHT, WINDOW_TARGET_WIDTH};
|
||||||
|
use bevy::color::palettes::tailwind::SLATE_900;
|
||||||
|
use bevy::input_focus::tab_navigation::TabIndex;
|
||||||
|
use bevy::text::{EditableText, TextCursorStyle};
|
||||||
use bevy::ui_widgets::Button;
|
use bevy::ui_widgets::Button;
|
||||||
use bevy::{prelude::*, ui_widgets::Activate};
|
use bevy::{prelude::*, ui_widgets::Activate};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
@@ -9,6 +13,7 @@ impl Plugin for MainMenuPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(OnEnter(AppState::Menu), setup_menu)
|
app.add_systems(OnEnter(AppState::Menu), setup_menu)
|
||||||
.add_systems(OnExit(AppState::Menu), cleanup_menu)
|
.add_systems(OnExit(AppState::Menu), cleanup_menu)
|
||||||
|
// .add_systems(Startup, enable_ui_debug)
|
||||||
.add_systems(Update, (menu_redraw).run_if(in_state(AppState::Menu)))
|
.add_systems(Update, (menu_redraw).run_if(in_state(AppState::Menu)))
|
||||||
.add_observer(button_activate_observer)
|
.add_observer(button_activate_observer)
|
||||||
.add_systems(Update, (scale_ui, style_ui_elements));
|
.add_systems(Update, (scale_ui, style_ui_elements));
|
||||||
@@ -78,6 +83,7 @@ pub enum MenuLayer {
|
|||||||
Root,
|
Root,
|
||||||
Play,
|
Play,
|
||||||
LoadSave,
|
LoadSave,
|
||||||
|
NewGame,
|
||||||
Browse,
|
Browse,
|
||||||
DirectConnect,
|
DirectConnect,
|
||||||
Settings,
|
Settings,
|
||||||
@@ -110,16 +116,31 @@ impl MenuLayer {
|
|||||||
menu_button("Direct Connect", Some(MenuLayer::DirectConnect)),
|
menu_button("Direct Connect", Some(MenuLayer::DirectConnect)),
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
MenuLayer::LoadSave => Box::new(bsn! {
|
MenuLayer::LoadSave => {
|
||||||
menu_layer(layer)
|
// TODO: this needs to be on an IO thread
|
||||||
|
let saves = get_saves().unwrap_or_default();
|
||||||
|
let entries: Vec<_> = saves
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| menu_button(m.save_name, None))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Box::new(bsn! {
|
||||||
|
menu_layer(layer)
|
||||||
|
ChildOf(menu_root)
|
||||||
|
Children [
|
||||||
|
{entries}
|
||||||
|
(
|
||||||
|
menu_button("New Game", Some(MenuLayer::NewGame))
|
||||||
|
InteractionColors::GOOD
|
||||||
|
),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
MenuLayer::NewGame => Box::new(bsn! {
|
||||||
|
full_menu_layer(layer)
|
||||||
ChildOf(menu_root)
|
ChildOf(menu_root)
|
||||||
Children [
|
Children [
|
||||||
menu_button("Save 1", None),
|
{new_game_menu()}
|
||||||
menu_button("Save 2", None),
|
|
||||||
(
|
|
||||||
menu_button("New Game", None)
|
|
||||||
InteractionColors::GOOD
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
MenuLayer::Browse => Box::new(bsn! {
|
MenuLayer::Browse => Box::new(bsn! {
|
||||||
@@ -170,6 +191,13 @@ struct LastMenu(Vec<MenuLayer>);
|
|||||||
#[derive(Resource, Debug, Clone, PartialEq, Eq, Hash, Deref, DerefMut)]
|
#[derive(Resource, Debug, Clone, PartialEq, Eq, Hash, Deref, DerefMut)]
|
||||||
struct CurrentMenu(Vec<MenuLayer>);
|
struct CurrentMenu(Vec<MenuLayer>);
|
||||||
|
|
||||||
|
// fn enable_ui_debug(mut debug_options: ResMut<GlobalUiDebugOptions>) {
|
||||||
|
// debug_options.enabled = true;
|
||||||
|
// debug_options.outline_border_box = true;
|
||||||
|
// debug_options.outline_padding_box = true;
|
||||||
|
// debug_options.outline_content_box = true;
|
||||||
|
// }
|
||||||
|
|
||||||
fn setup_menu(mut commands: Commands) {
|
fn setup_menu(mut commands: Commands) {
|
||||||
commands.insert_resource(CurrentMenu(vec![MenuLayer::Root]));
|
commands.insert_resource(CurrentMenu(vec![MenuLayer::Root]));
|
||||||
commands.insert_resource(LastMenu(vec![]));
|
commands.insert_resource(LastMenu(vec![]));
|
||||||
@@ -233,6 +261,70 @@ fn menu_redraw(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_game_menu() -> impl SceneList {
|
||||||
|
bsn_list![
|
||||||
|
(
|
||||||
|
Text("New Game")
|
||||||
|
Node {
|
||||||
|
align_self: AlignSelf::Center,
|
||||||
|
}
|
||||||
|
TextFont {
|
||||||
|
// font: FontSourceTemplate::Handle("fonts/FiraSans-Bold.ttf"),
|
||||||
|
font_size: px(100.0),
|
||||||
|
}
|
||||||
|
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||||
|
TextShadow
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Text("Save Name")
|
||||||
|
Node {
|
||||||
|
margin: UiRect::axes(px(12), px(0)),
|
||||||
|
}
|
||||||
|
TextFont {
|
||||||
|
// font: FontSourceTemplate::Handle("fonts/FiraSans-Bold.ttf"),
|
||||||
|
font_size: px(66.0),
|
||||||
|
}
|
||||||
|
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||||
|
TextShadow
|
||||||
|
),
|
||||||
|
(
|
||||||
|
#NewGameTextField
|
||||||
|
Node {
|
||||||
|
border: Val::all(px(6)),
|
||||||
|
padding: Val::all(px(12)),
|
||||||
|
border_radius: BorderRadius::all(px(12)),
|
||||||
|
}
|
||||||
|
// BorderColor::from(SLATE_800)
|
||||||
|
BorderColor::from(SLATE_900)
|
||||||
|
EditableText {
|
||||||
|
cursor_width: 0.05,
|
||||||
|
}
|
||||||
|
TextLayout::no_wrap()
|
||||||
|
TextFont {
|
||||||
|
font_size: FontSize::Px(66.),
|
||||||
|
}
|
||||||
|
TextCursorStyle {
|
||||||
|
color: Color::BLACK
|
||||||
|
}
|
||||||
|
TabIndex(0)
|
||||||
|
BackgroundColor(Color::srgb(0.48, 0.84, 0.87))
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Node {
|
||||||
|
margin: UiRect::top(px(48)),
|
||||||
|
}
|
||||||
|
Children [
|
||||||
|
menu_button("Create", None)
|
||||||
|
Node {
|
||||||
|
margin: UiRect::left(Val::Auto),
|
||||||
|
}
|
||||||
|
InteractionColors::GOOD
|
||||||
|
on(|event: On<Activate>, q_text:| { info!("create!") })
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_layer(layer: usize) -> impl Scene {
|
fn menu_layer(layer: usize) -> impl Scene {
|
||||||
let name = format!("MenuLayer{}", layer);
|
let name = format!("MenuLayer{}", layer);
|
||||||
bsn! {
|
bsn! {
|
||||||
@@ -242,8 +334,6 @@ fn menu_layer(layer: usize) -> impl Scene {
|
|||||||
width: percent(100.0 / N_LAYERS as f32),
|
width: percent(100.0 / N_LAYERS as f32),
|
||||||
height: percent(100),
|
height: percent(100),
|
||||||
flex_direction: FlexDirection::Column,
|
flex_direction: FlexDirection::Column,
|
||||||
// align_items: AlignItems::Start,
|
|
||||||
align_items: AlignItems::Baseline,
|
|
||||||
justify_content: JustifyContent::FlexEnd,
|
justify_content: JustifyContent::FlexEnd,
|
||||||
row_gap: px(100),
|
row_gap: px(100),
|
||||||
}
|
}
|
||||||
@@ -251,21 +341,22 @@ fn menu_layer(layer: usize) -> impl Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn full_menu_layer(layer: usize) -> impl Scene {
|
fn full_menu_layer(layer: usize) -> impl Scene {
|
||||||
|
let name = format!("FullMenuLayer{}", layer);
|
||||||
bsn! {
|
bsn! {
|
||||||
menu_layer(layer)
|
Name(name)
|
||||||
|
Layer(layer)
|
||||||
Node {
|
Node {
|
||||||
width: Val::Auto,
|
flex_direction: FlexDirection::Column,
|
||||||
|
align_self: AlignSelf::FlexEnd,
|
||||||
flex_grow: 1.,
|
flex_grow: 1.,
|
||||||
|
border_radius: BorderRadius::all(px(24)),
|
||||||
|
padding: Val::all(px(24)),
|
||||||
}
|
}
|
||||||
BackgroundColor(Color::srgba(0.8, 0.1, 0.1, 0.7))
|
BackgroundColor(Color::srgb(0.4, 0.4, 0.4))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn menu_button(label: &str, next_layer: Option<MenuLayer>) -> impl Scene {
|
fn menu_button(label: impl Into<String>, next_layer: Option<MenuLayer>) -> impl Scene {
|
||||||
let next_layer_component = next_layer
|
|
||||||
.map(|n| Box::new(bsn! { NextLayer(n) }) as Box<dyn Scene>)
|
|
||||||
.unwrap_or(Box::new(bsn! {}));
|
|
||||||
|
|
||||||
bsn! {
|
bsn! {
|
||||||
Button
|
Button
|
||||||
Node {
|
Node {
|
||||||
@@ -277,7 +368,7 @@ fn menu_button(label: &str, next_layer: Option<MenuLayer>) -> impl Scene {
|
|||||||
align_items: AlignItems::Center,
|
align_items: AlignItems::Center,
|
||||||
margin: UiRect::all(px(4)),
|
margin: UiRect::all(px(4)),
|
||||||
}
|
}
|
||||||
next_layer_component
|
{next_layer.map(|l| template_value(NextLayer(l)))}
|
||||||
BorderColor::from(Color::BLACK)
|
BorderColor::from(Color::BLACK)
|
||||||
InteractionColors::DEFAULT
|
InteractionColors::DEFAULT
|
||||||
Interaction
|
Interaction
|
||||||
|
|||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
use app_dirs2::{AppInfo, app_dir};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use jiff::Zoned;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub const APP_INFO: AppInfo = AppInfo {
|
||||||
|
name: "OfficeWarper",
|
||||||
|
author: "MarinoDev",
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ActiveGameSave {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SaveMessage;
|
||||||
|
|
||||||
|
pub struct SavePlugin;
|
||||||
|
|
||||||
|
/// The metadata stored with each game save
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct GameSaveMetadata {
|
||||||
|
pub save_name: String,
|
||||||
|
pub version: String,
|
||||||
|
pub timestamp: Zoned,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for SavePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_message::<SaveMessage>()
|
||||||
|
.add_systems(PostUpdate, handle_saves);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_saves(
|
||||||
|
mut save_messages: MessageReader<SaveMessage>,
|
||||||
|
active_game_save: Option<Res<ActiveGameSave>>,
|
||||||
|
) {
|
||||||
|
for _save in save_messages.read() {
|
||||||
|
let Some(ref active_game_save) = active_game_save else {
|
||||||
|
warn!("Save requested, but no active game save exists!");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Saving!");
|
||||||
|
let save_subpath = format!("saves/{}", active_game_save.name);
|
||||||
|
let save_path = match app_dir(app_dirs2::AppDataType::UserData, &APP_INFO, &*save_subpath) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Failed to get the save path for \"{}\": {e}",
|
||||||
|
active_game_save.name
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = std::fs::write(save_path.join("version.txt"), "v0.0.1") {
|
||||||
|
error!("Error when writing the game version: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Game saved!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_saves() -> Result<Vec<GameSaveMetadata>, std::io::Error> {
|
||||||
|
let saves_path = match app_dir(app_dirs2::AppDataType::UserData, &APP_INFO, "saves") {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(app_dirs2::AppDirsError::Io(e)) => {
|
||||||
|
error!("Failed to get path to the saves: {e}",);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
Err(app_dirs2::AppDirsError::NotSupported) => {
|
||||||
|
error!("The app data directory is not known on this platform!");
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Unsupported,
|
||||||
|
"the app data directory is not known on this platform",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(app_dirs2::AppDirsError::InvalidAppInfo) => {
|
||||||
|
// :/
|
||||||
|
panic!("APP_INFO invalid!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let dir = match std::fs::read_dir(saves_path) {
|
||||||
|
Ok(dir) => dir,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to read the saves path: {e}");
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// TODO: do a meta.ron file instead of name.txt
|
||||||
|
let save_folders = dir
|
||||||
|
.filter_map(|entry| {
|
||||||
|
entry
|
||||||
|
.ok()
|
||||||
|
.filter(|e| e.file_type().is_ok_and(|t| t.is_dir()))
|
||||||
|
})
|
||||||
|
.map(|dir| dir.path());
|
||||||
|
|
||||||
|
let mut saves = vec![];
|
||||||
|
for save_folder in save_folders {
|
||||||
|
let meta_raw = match std::fs::read_to_string(save_folder.join("meta.ron")) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to read meta for save \"{save_folder:?}\"");
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let meta: GameSaveMetadata = match ron::from_str(&meta_raw) {
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error when deserializing metadata for save \"{save_folder:?}\": {e}");
|
||||||
|
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e));
|
||||||
|
}
|
||||||
|
Ok(m) => m,
|
||||||
|
};
|
||||||
|
saves.push(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(saves)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user