From 466f4db89541edaf3e82a22146ba9062a8110def Mon Sep 17 00:00:00 2001 From: Louis Capitanchik <contact@louiscap.co> Date: Tue, 6 Dec 2022 20:33:47 +0000 Subject: [PATCH] Support clean up when exiting game, add debug snapshot options --- Cargo.lock | 75 +++++++++++ game_core/Cargo.toml | 1 + game_core/src/graphics/mod.rs | 34 ----- game_core/src/lib.rs | 1 - game_core/src/main.rs | 14 +-- game_core/src/persistance/save_file.rs | 1 - game_core/src/states/debug_state.rs | 132 ++++++++++++++++++++ game_core/src/states/game_state.rs | 15 ++- game_core/src/states/mod.rs | 20 +++ game_core/src/system/utilities.rs | 4 + game_core/src/ui/screens/in_game.rs | 17 ++- game_core/src/ui/widgets/encounter_panel.rs | 2 +- game_core/src/ui/widgets/shop_panel.rs | 3 +- game_core/src/ui/widgets/transit_panel.rs | 3 +- game_core/src/world/mod.rs | 6 +- game_core/src/world/spawning.rs | 56 ++++++--- 16 files changed, 312 insertions(+), 72 deletions(-) delete mode 100644 game_core/src/graphics/mod.rs create mode 100644 game_core/src/states/debug_state.rs diff --git a/Cargo.lock b/Cargo.lock index b44149f..69f109e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -578,6 +578,17 @@ dependencies = [ "radsort", ] +[[package]] +name = "bevy_prototype_lyon" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c063aff10ca720d5cadf9cf669800eff2166f6f28cf7f20648ece1c3bdb2442" +dependencies = [ + "bevy", + "lyon_tessellation", + "svgtypes", +] + [[package]] name = "bevy_ptr" version = "0.9.1" @@ -1528,6 +1539,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float_next_after" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632" +dependencies = [ + "num-traits", +] + [[package]] name = "flume" version = "0.10.14" @@ -1620,6 +1640,7 @@ dependencies = [ "anyhow", "bevy", "bevy_ecs_tilemap", + "bevy_prototype_lyon", "bevy_tweening", "directories", "fake", @@ -2202,6 +2223,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + [[package]] name = "libudev-sys" version = "0.1.4" @@ -2231,6 +2258,38 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lyon_geom" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5237e77afe5a112d5ce8060e3473e78b09b5f8cea722a251dcafa1254711f440" +dependencies = [ + "arrayvec", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2a6c0d4a27bb3fe8b747184caf79a57b8bd2caeee49c0f9e59d068d30f7a0d" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "lyon_tessellation" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583cfbb96beba3d5843b92a3a4db89c6dc6ba731ae80e28c80bb587636ca28d9" +dependencies = [ + "float_next_after", + "lyon_path", + "thiserror", +] + [[package]] name = "lzma-sys" version = "0.1.20" @@ -2692,6 +2751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3353,6 +3413,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.7" @@ -3485,6 +3551,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" +[[package]] +name = "svgtypes" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564" +dependencies = [ + "siphasher", +] + [[package]] name = "symphonia" version = "0.5.1" diff --git a/game_core/Cargo.toml b/game_core/Cargo.toml index 0ce21e8..e114881 100644 --- a/game_core/Cargo.toml +++ b/game_core/Cargo.toml @@ -33,6 +33,7 @@ kayak_ui.workspace = true kayak_font.workspace = true fake = "2.5.0" directories = "4.0.1" +bevy_prototype_lyon = "0.7.2" #remote_events = { git = "https://lab.lcr.gr/microhacks/micro-bevy-remote-events.git", rev = "be0c6b43a73e4c5e7ece20797e3d6f59340147b4"} diff --git a/game_core/src/graphics/mod.rs b/game_core/src/graphics/mod.rs deleted file mode 100644 index 02567b1..0000000 --- a/game_core/src/graphics/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -use bevy::prelude::*; - -#[derive(Component, Copy, Clone)] -pub struct AlignedBackground; - -pub fn adjust_aligned_backgrounds( - mut query: Query<(&mut Transform, &Handle<Image>), With<AlignedBackground>>, - windows: Res<Windows>, - images: Res<Assets<Image>>, -) { - if let Some(window) = windows.get_primary() { - let width = window.width(); - let height = window.height(); - - for (mut transform, handle) in &mut query { - if let Some(image) = images.get(handle) { - if width > height { - let scale = image.texture_descriptor.size.width as f32 / width; - transform.scale = Vec3::splat(scale); - } else { - let scale = image.texture_descriptor.size.height as f32 / height; - transform.scale = Vec3::splat(scale); - } - } - } - } -} - -pub struct GraphicsPlugin; -impl Plugin for GraphicsPlugin { - fn build(&self, app: &mut App) { - app.add_system(adjust_aligned_backgrounds); - } -} diff --git a/game_core/src/lib.rs b/game_core/src/lib.rs index 93c9644..1d04c08 100644 --- a/game_core/src/lib.rs +++ b/game_core/src/lib.rs @@ -1,7 +1,6 @@ #![feature(result_option_inspect)] pub mod assets; -pub mod graphics; pub mod multiplayer; pub mod persistance; pub mod splash_screen; diff --git a/game_core/src/main.rs b/game_core/src/main.rs index 3202daa..989e47b 100644 --- a/game_core/src/main.rs +++ b/game_core/src/main.rs @@ -1,28 +1,24 @@ use bevy::prelude::*; -use bevy_ecs_tilemap::TilemapPlugin; use game_core::assets::AssetHandles; use game_core::system::flow::AppState; -use game_core::system::resources::InitAppPlugins; -use game_core::ui::AdventUIPlugins; use iyes_loopless::prelude::AppLooplessStateExt; -use micro_musicbox::CombinedAudioPlugins; fn main() { App::new() .add_loopless_state(AppState::Preload) - .add_plugins(InitAppPlugins) + .add_plugins(game_core::system::resources::InitAppPlugins) .add_plugin(game_core::assets::AssetsPlugin) - .add_plugins(CombinedAudioPlugins::<AssetHandles>::new()) + .add_plugins(micro_musicbox::CombinedAudioPlugins::<AssetHandles>::new()) .add_plugin(game_core::splash_screen::SplashScreenPlugin) .add_plugin(game_core::system::camera::CameraManagementPlugin) .add_plugin(game_core::states::StatesPlugin) .add_plugin(micro_asset_io::MicroAssetIOPlugin) .add_plugin(bevy_tweening::TweeningPlugin) .add_plugin(game_core::world::WorldPlugin) - .add_plugin(TilemapPlugin) - .add_plugin(game_core::graphics::GraphicsPlugin) + .add_plugin(bevy_ecs_tilemap::TilemapPlugin) .add_plugins(micro_banimate::BanimatePluginGroup) - .add_plugins(AdventUIPlugins) + .add_plugins(game_core::ui::AdventUIPlugins) .add_plugin(game_core::persistance::PersistencePlugin) + .add_plugin(bevy_prototype_lyon::plugin::ShapePlugin) .run(); } diff --git a/game_core/src/persistance/save_file.rs b/game_core/src/persistance/save_file.rs index 36ce085..c0d7466 100644 --- a/game_core/src/persistance/save_file.rs +++ b/game_core/src/persistance/save_file.rs @@ -142,7 +142,6 @@ pub fn handle_load_event(mut commands: Commands, mut events: ResMut<Events<LoadF match std::fs::File::open(path) { Ok(file) => match serde_json::from_reader::<File, PersistenceState>(file) { Ok(value) => { - log::info!("GET PER: {:?}", &value); commands.insert_resource(PendingLoadState(value)); commands.insert_resource(NextState(AppState::InGame)); } diff --git a/game_core/src/states/debug_state.rs b/game_core/src/states/debug_state.rs new file mode 100644 index 0000000..4c71995 --- /dev/null +++ b/game_core/src/states/debug_state.rs @@ -0,0 +1,132 @@ +use std::collections::HashSet; +use std::hash::{Hash, Hasher}; +use std::ops::Not; +use std::os::linux::raw::stat; + +use bevy::input::Input; +use bevy::prelude::{ + Color, Commands, Component, Entity, EventWriter, KeyCode, Query, Rect, Res, ResMut, Resource, + Transform, With, +}; +use bevy_prototype_lyon::draw::DrawMode; +use bevy_prototype_lyon::prelude::{FillMode, GeometryBuilder, RectangleOrigin, StrokeMode}; +use bevy_prototype_lyon::shapes; +use iyes_loopless::state::NextState; + +use crate::persistance::{LoadFileEvent, SaveFileEvent}; +use crate::system::flow::AppState; +use crate::world::WorldZones; + +#[derive(Debug, Copy, Clone, Resource, Ord, PartialOrd, Eq, PartialEq)] +pub enum DebugStatus { + On, + Off, +} + +impl DebugStatus { + pub fn inverse(&self) -> Self { + match self { + Self::Off => Self::On, + Self::On => Self::Off, + } + } +} + +impl Not for DebugStatus { + type Output = DebugStatus; + + fn not(self) -> Self::Output { + self.inverse() + } +} + +pub fn toggle_debug_mode(input: Res<Input<KeyCode>>, mut status: ResMut<DebugStatus>) { + if input.just_released(KeyCode::F5) { + *status = !*status; + } +} + +const DEBUG_SNAPSHOT: &str = "debug_snapshot.json"; + +pub fn handle_debug_snapshots( + mut commands: Commands, + input: Res<Input<KeyCode>>, + mut save_events: EventWriter<SaveFileEvent>, + mut load_events: EventWriter<LoadFileEvent>, +) { + if input.just_released(KeyCode::F6) { + save_events.send(SaveFileEvent { + filename: Some(DEBUG_SNAPSHOT.to_string()), + }); + } else if input.just_released(KeyCode::F7) { + commands.insert_resource(NextState(AppState::Menu)); + load_events.send(LoadFileEvent { + filename: Some(DEBUG_SNAPSHOT.to_string()), + }); + } +} + +#[derive(Component)] +pub struct ZoneShape; + +#[derive(Component, Copy, Clone)] +pub struct ZoneData(Rect); +impl Eq for ZoneData {} +impl PartialEq for ZoneData { + fn eq(&self, other: &Self) -> bool { + other.0 == self.0 + } +} +impl Hash for ZoneData { + fn hash<H: Hasher>(&self, state: &mut H) { + state.write_i128((self.0.min.x * 1000.0) as i128); + state.write_i128((self.0.min.y * 1000.0) as i128); + state.write_i128((self.0.max.x * 1000.0) as i128); + state.write_i128((self.0.max.y * 1000.0) as i128); + } +} + +pub fn show_zone_shapes( + mut commands: Commands, + query: Query<(Entity, &ZoneData), With<ZoneShape>>, + debug: Res<DebugStatus>, + zones: Res<WorldZones>, +) { + if *debug == DebugStatus::Off { + for (entity, _) in &query { + commands.entity(entity).despawn(); + } + } else { + let mut handled = HashSet::with_capacity(zones.0.len()); + let map_zones = zones + .0 + .iter() + .map(|zone| ZoneData(zone.area)) + .collect::<HashSet<ZoneData>>(); + + for (entity, zone) in &query { + if map_zones.contains(zone) { + handled.insert(*zone); + } else { + commands.entity(entity).despawn(); + } + } + + for encounter in zones.0.iter() { + let data = ZoneData(encounter.area); + if !handled.contains(&data) { + commands.spawn(GeometryBuilder::build_as( + &shapes::Rectangle { + origin: RectangleOrigin::Center, + extents: data.0.half_size(), + }, + DrawMode::Outlined { + fill_mode: FillMode::color(Color::rgba(0.54, 0.23, 0.74, 0.25)), + outline_mode: StrokeMode::color(Color::rgb(0.54, 0.23, 0.74)), + }, + Transform::from_translation(data.0.center().extend(900.0)), + )); + } + } + } +} diff --git a/game_core/src/states/game_state.rs b/game_core/src/states/game_state.rs index 25fc138..d56d576 100644 --- a/game_core/src/states/game_state.rs +++ b/game_core/src/states/game_state.rs @@ -1,9 +1,12 @@ use std::time::Duration; -use bevy::prelude::Component; +use bevy::input::Input; +use bevy::prelude::{Commands, Component, KeyCode, Res}; +use iyes_loopless::state::NextState; use micro_musicbox::prelude::{AudioEasing, AudioTween, MusicBox}; use crate::assets::AssetHandles; +use crate::system::flow::AppState; #[derive(Component, Debug, Default, Copy, Clone)] pub struct Player; @@ -14,3 +17,13 @@ pub fn on_enter_game(mut musicbox: MusicBox<AssetHandles>) { AudioTween::new(Duration::from_secs(2), AudioEasing::Linear), ); } + +pub fn on_leave_game(mut musicbox: MusicBox<AssetHandles>) { + musicbox.fade_out_music(AudioTween::new(Duration::from_secs(2), AudioEasing::Linear)); +} + +pub fn quit_game(mut commands: Commands, input: Res<Input<KeyCode>>) { + if input.just_released(KeyCode::Escape) { + commands.insert_resource(NextState(AppState::Menu)); + } +} diff --git a/game_core/src/states/mod.rs b/game_core/src/states/mod.rs index 5a5214c..8d9e697 100644 --- a/game_core/src/states/mod.rs +++ b/game_core/src/states/mod.rs @@ -4,6 +4,7 @@ use iyes_loopless::prelude::{AppLooplessStateExt, ConditionSet}; use crate::states::menu_state::go_to_game; use crate::system::flow::AppState; +mod debug_state; mod game_state; mod menu_state; @@ -13,13 +14,32 @@ impl Plugin for StatesPlugin { app.add_enter_system(AppState::Menu, menu_state::spawn_menu_entities) .add_exit_system(AppState::Menu, menu_state::despawn_menu_entities) .add_enter_system(AppState::InGame, game_state::on_enter_game) + .add_exit_system(AppState::InGame, game_state::on_leave_game) .add_system_set( ConditionSet::new() .run_in_state(AppState::Menu) .with_system(go_to_game) .into(), + ) + .add_system_set( + ConditionSet::new() + .run_in_state(AppState::InGame) + .with_system(quit_game) + .into(), + ) + .insert_resource(debug_state::DebugStatus::Off) + .add_system(debug_state::toggle_debug_mode) + .add_system_set( + ConditionSet::new() + .run_in_state(AppState::InGame) + .run_if_resource_equals(debug_state::DebugStatus::On) + .with_system(debug_state::handle_debug_snapshots) + .with_system(debug_state::show_zone_shapes) + .into(), ); } } pub use game_state::Player; + +use crate::states::game_state::quit_game; diff --git a/game_core/src/system/utilities.rs b/game_core/src/system/utilities.rs index c26cbbf..1c5028c 100644 --- a/game_core/src/system/utilities.rs +++ b/game_core/src/system/utilities.rs @@ -143,3 +143,7 @@ where serde_json::from_value(serde_json::to_value(&self).unwrap()).unwrap() } } + +pub fn format_ui_distance(distance: f32) -> String { + format!("{:.0} km", distance / 10.0) +} diff --git a/game_core/src/ui/screens/in_game.rs b/game_core/src/ui/screens/in_game.rs index 29258ac..1ee476d 100644 --- a/game_core/src/ui/screens/in_game.rs +++ b/game_core/src/ui/screens/in_game.rs @@ -2,6 +2,7 @@ use bevy::prelude::*; use kayak_ui::prelude::*; use kayak_ui::widgets::{ElementBundle, KayakAppBundle, TextProps, TextWidgetBundle}; +use crate::system::utilities::format_ui_distance; use crate::ui::components::*; use crate::ui::prelude::{px, stretch, value}; use crate::ui::sync::UITravelInfo; @@ -30,25 +31,31 @@ pub fn render_game_panels( left: stretch(1.0), right: stretch(1.0), bottom: px(50.0), - height: px(60.0), + height: px(50.0), width: stretch(0.6), + max_width: px(200.0), padding: value(Edge::all(Units::Stretch(1.0))), ..Default::default() }; + let show_distance_panel = !encounter_state.is_in_encounter() + && !ui_data.is_in_town + && ui_data.distance_remaining > 0.1; + rsx! { <ElementBundle> - { if !encounter_state.is_in_encounter() && ui_data.distance_remaining > 0.1 { + { if show_distance_panel { constructor! { <PanelWidget styles={distance_style}> <TextWidgetBundle text={TextProps { - content: format!("{:.2}KM", ui_data.distance_remaining), - size: 48.0, + content: format_ui_distance(ui_data.distance_remaining), + size: 40.0, ..Default::default() }} styles={KStyle { - bottom: px(7.5), + color: value(Color::BLACK), + bottom: px(6.0), ..Default::default() }} /> diff --git a/game_core/src/ui/widgets/encounter_panel.rs b/game_core/src/ui/widgets/encounter_panel.rs index b1b5e1f..665ee3b 100644 --- a/game_core/src/ui/widgets/encounter_panel.rs +++ b/game_core/src/ui/widgets/encounter_panel.rs @@ -39,7 +39,7 @@ pub fn render_encounter_panel( height: pct(80.0), min_width: px(400.0), min_height: px(300.0), - max_width: px(850.0), + max_width: px(600.0), max_height: px(550.0), top: stretch(1.0), left: stretch(1.0), diff --git a/game_core/src/ui/widgets/shop_panel.rs b/game_core/src/ui/widgets/shop_panel.rs index ebb8575..00c8ed3 100644 --- a/game_core/src/ui/widgets/shop_panel.rs +++ b/game_core/src/ui/widgets/shop_panel.rs @@ -7,6 +7,7 @@ use kayak_ui::widgets::{ use crate::assets::AssetHandles; use crate::states::Player; +use crate::system::utilities::format_ui_distance; use crate::ui::components::*; use crate::ui::prelude::*; use crate::ui::sync::UITravelInfo; @@ -98,7 +99,7 @@ pub fn render_transit_panel( ..Default::default() } } - props={ButtonWidgetProps::text(format!("{}: {:.2}KM", &place, distance), 28.0)} + props={ButtonWidgetProps::text(format!("{}: {}", &place, format_ui_distance(*distance)), 28.0)} on_event={buysell_button_factory(place.clone())} /> } diff --git a/game_core/src/ui/widgets/transit_panel.rs b/game_core/src/ui/widgets/transit_panel.rs index 6e3571e..d610107 100644 --- a/game_core/src/ui/widgets/transit_panel.rs +++ b/game_core/src/ui/widgets/transit_panel.rs @@ -7,6 +7,7 @@ use kayak_ui::widgets::{ use crate::assets::AssetHandles; use crate::states::Player; +use crate::system::utilities::format_ui_distance; use crate::ui::components::*; use crate::ui::prelude::*; use crate::ui::sync::UITravelInfo; @@ -98,7 +99,7 @@ pub fn render_transit_panel( ..Default::default() } } - props={ButtonWidgetProps::text(format!("{}: {:.2}KM", &place, distance), 28.0)} + props={ButtonWidgetProps::text(format!("{}: {}", &place, format_ui_distance(*distance)), 28.0)} on_event={transit_button_factory(place.clone())} /> } diff --git a/game_core/src/world/mod.rs b/game_core/src/world/mod.rs index a0e75b1..0f03c26 100644 --- a/game_core/src/world/mod.rs +++ b/game_core/src/world/mod.rs @@ -23,8 +23,12 @@ impl Plugin for WorldPlugin { .init_resource::<EncounterState>() .add_event::<PopulateWorldEvent>() .add_enter_system(AppState::InGame, |mut commands: Commands| { - commands.insert_resource(ActiveLevel::new("Grantswaith")); + commands.insert_resource(ActiveLevel { + map: String::from("Grantswaith"), + dirty: true, + }); }) + .add_enter_system(AppState::Menu, spawning::clean_game_state) .add_system_set( ConditionSet::new() .run_in_state(AppState::InGame) diff --git a/game_core/src/world/spawning.rs b/game_core/src/world/spawning.rs index 4e59f6a..ac86485 100644 --- a/game_core/src/world/spawning.rs +++ b/game_core/src/world/spawning.rs @@ -12,7 +12,7 @@ use crate::world::encounters::WorldZones; use crate::world::towns::{CurrentResidence, TownPaths}; use crate::world::utils::{grid_to_px, px_to_grid, ActiveLevel, WorldLinked, TILE_SCALE_F32}; use crate::world::world_query::MapQuery; -use crate::world::{TravelPath, TravelTarget}; +use crate::world::{EncounterState, HungerState, TradingState, TravelPath, TravelTarget}; #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] pub struct PopulateWorldEvent; @@ -65,7 +65,7 @@ pub fn spawn_world_data( return; } - let map_entity = commands.spawn_empty().id(); + let map_entity = commands.spawn(WorldLinked).id(); let mut storage = TileStorage::empty(tilemap_size); layer.for_each_tile(|x, y, tile| { @@ -121,8 +121,6 @@ pub fn spawn_world_data( let grid_size = tilemap_tile_size.into(); let map_type = TilemapType::Square; - log::info!("Spawning tilemap"); - let bg = level .level_bg_color .clone() @@ -140,19 +138,16 @@ pub fn spawn_world_data( } } - commands.entity(map_entity).insert(( - TilemapBundle { - grid_size, - map_type, - size: tilemap_size, - storage, - texture: TilemapTexture::Single(assets.image("overworld")), - tile_size: tilemap_tile_size, - transform: Transform::from_xyz(0.0, 0.0, 5.0 + layer.get_z_delta()), // get_tilemap_center_transform(&tilemap_size, &grid_size, 5.0), - ..Default::default() - }, - WorldLinked, - )); + commands.entity(map_entity).insert((TilemapBundle { + grid_size, + map_type, + size: tilemap_size, + storage, + texture: TilemapTexture::Single(assets.image("overworld")), + tile_size: tilemap_tile_size, + transform: Transform::from_xyz(0.0, 0.0, 5.0 + layer.get_z_delta()), // get_tilemap_center_transform(&tilemap_size, &grid_size, 5.0), + ..Default::default() + },)); }); events.send(PopulateWorldEvent); @@ -218,6 +213,7 @@ pub fn populate_world( }, Player, ChaseCam, + WorldLinked, )); match &pending_load { @@ -278,3 +274,29 @@ pub fn populate_world( ); } } + +pub fn clean_game_state( + mut commands: Commands, + world_entities: Query<Entity, (Without<TileStorage>, With<WorldLinked>)>, + mut tile_storages: Query<Entity, Or<(With<TilemapId>, With<TileStorage>)>>, +) { + commands.remove_resource::<PendingLoadState>(); + commands.remove_resource::<PersistenceState>(); + commands.remove_resource::<TradingState>(); + commands.remove_resource::<HungerState>(); + + commands.insert_resource(TownPaths::default()); + commands.insert_resource(WorldZones::default()); + commands.insert_resource(EncounterState::default()); + + // + log::info!("Cleaning {} world objects", world_entities.iter().len()); + for entity in &world_entities { + commands.entity(entity).despawn_recursive(); + } + // + log::info!("Cleaning {} tile storages", tile_storages.iter().len()); + for entity in &mut tile_storages { + commands.entity(entity).despawn(); + } +} -- GitLab