2020-02-29 03:59:11 +00:00
|
|
|
#![deny(unsafe_code)]
|
2020-09-27 16:20:40 +00:00
|
|
|
#![allow(incomplete_features)]
|
|
|
|
#![allow(clippy::option_map_unit_fn)]
|
|
|
|
#![deny(clippy::clone_on_ref_ptr)]
|
2020-08-21 19:10:56 +00:00
|
|
|
#![feature(
|
2021-07-21 08:58:03 +00:00
|
|
|
array_methods,
|
|
|
|
array_zip,
|
2020-08-21 19:10:56 +00:00
|
|
|
bool_to_option,
|
|
|
|
drain_filter,
|
|
|
|
once_cell,
|
2021-06-02 04:31:23 +00:00
|
|
|
trait_alias
|
2020-08-21 19:10:56 +00:00
|
|
|
)]
|
2020-02-29 03:59:11 +00:00
|
|
|
#![recursion_limit = "2048"]
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
pub mod ui;
|
|
|
|
pub mod audio;
|
2020-03-10 21:00:13 +00:00
|
|
|
pub mod controller;
|
2021-09-24 05:48:29 +00:00
|
|
|
mod credits;
|
2020-02-29 03:59:11 +00:00
|
|
|
mod ecs;
|
|
|
|
pub mod error;
|
2021-07-21 11:23:45 +00:00
|
|
|
pub mod game_input;
|
2020-02-29 03:59:11 +00:00
|
|
|
pub mod hud;
|
|
|
|
pub mod key_state;
|
|
|
|
pub mod menu;
|
2020-01-09 06:05:20 +00:00
|
|
|
pub mod mesh;
|
2020-06-16 13:55:37 +00:00
|
|
|
pub mod profile;
|
2020-01-09 06:05:20 +00:00
|
|
|
pub mod render;
|
2019-10-27 07:11:18 +00:00
|
|
|
pub mod run;
|
2020-02-29 03:59:11 +00:00
|
|
|
pub mod scene;
|
|
|
|
pub mod session;
|
|
|
|
pub mod settings;
|
|
|
|
#[cfg(feature = "singleplayer")]
|
|
|
|
pub mod singleplayer;
|
|
|
|
pub mod window;
|
2020-01-26 19:29:46 +00:00
|
|
|
|
2020-03-07 22:16:00 +00:00
|
|
|
#[cfg(feature = "singleplayer")]
|
|
|
|
use crate::singleplayer::Singleplayer;
|
2021-07-04 09:47:18 +00:00
|
|
|
#[cfg(feature = "egui-ui")]
|
|
|
|
use crate::ui::egui::EguiState;
|
2020-06-16 13:55:37 +00:00
|
|
|
use crate::{
|
2019-10-27 07:11:18 +00:00
|
|
|
audio::AudioFrontend,
|
|
|
|
profile::Profile,
|
2021-07-04 09:47:18 +00:00
|
|
|
render::{Drawer, GlobalsBindGroup},
|
2019-10-27 07:11:18 +00:00
|
|
|
settings::Settings,
|
|
|
|
window::{Event, Window},
|
2020-06-16 13:55:37 +00:00
|
|
|
};
|
2021-04-24 14:39:35 +00:00
|
|
|
use common::clock::Clock;
|
2021-03-08 22:40:02 +00:00
|
|
|
use common_base::span;
|
2021-05-04 08:55:40 +00:00
|
|
|
use i18n::LocalizationHandle;
|
2021-07-19 02:57:14 +00:00
|
|
|
use std::path::PathBuf;
|
2020-02-29 03:59:11 +00:00
|
|
|
|
2021-08-10 13:55:58 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use tokio::runtime::Runtime;
|
|
|
|
|
2020-02-29 03:59:11 +00:00
|
|
|
/// A type used to store state that is shared between all play states.
|
|
|
|
pub struct GlobalState {
|
2021-07-19 02:57:14 +00:00
|
|
|
pub userdata_dir: PathBuf,
|
|
|
|
pub config_dir: PathBuf,
|
2020-02-29 03:59:11 +00:00
|
|
|
pub settings: Settings,
|
2020-06-16 13:55:37 +00:00
|
|
|
pub profile: Profile,
|
2020-02-29 03:59:11 +00:00
|
|
|
pub window: Window,
|
2021-08-10 13:55:58 +00:00
|
|
|
pub tokio_runtime: Arc<Runtime>,
|
2021-07-04 09:47:18 +00:00
|
|
|
#[cfg(feature = "egui-ui")]
|
|
|
|
pub egui_state: EguiState,
|
2021-04-10 14:53:34 +00:00
|
|
|
pub lazy_init: scene::terrain::SpriteRenderContextLazy,
|
2020-02-29 03:59:11 +00:00
|
|
|
pub audio: AudioFrontend,
|
|
|
|
pub info_message: Option<String>,
|
2019-10-27 07:11:18 +00:00
|
|
|
pub clock: Clock,
|
|
|
|
#[cfg(feature = "singleplayer")]
|
2020-02-29 03:59:11 +00:00
|
|
|
pub singleplayer: Option<Singleplayer>,
|
2019-10-27 07:11:18 +00:00
|
|
|
// TODO: redo this so that the watcher doesn't have to exist for reloading to occur
|
2021-04-24 14:39:35 +00:00
|
|
|
pub i18n: LocalizationHandle,
|
2021-06-15 08:01:57 +00:00
|
|
|
pub clipboard: iced_winit::Clipboard,
|
2020-12-30 14:50:17 +00:00
|
|
|
// NOTE: This can be removed from GlobalState if client state behavior is refactored to not
|
|
|
|
// enter the game before confirmation of successful character load
|
|
|
|
/// An error returned by Client that needs to be displayed by the UI
|
|
|
|
pub client_error: Option<String>,
|
2021-07-04 09:47:18 +00:00
|
|
|
// Used to clear the shadow textures when entering a PlayState that doesn't utilise shadows
|
|
|
|
pub clear_shadows_next_frame: bool,
|
2020-02-29 03:59:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GlobalState {
|
|
|
|
/// Called after a change in play state has occurred (usually used to
|
|
|
|
/// reverse any temporary effects a state may have made).
|
|
|
|
pub fn on_play_state_changed(&mut self) {
|
|
|
|
self.window.grab_cursor(false);
|
|
|
|
self.window.needs_refresh_resize();
|
|
|
|
}
|
|
|
|
|
2020-11-22 08:50:25 +00:00
|
|
|
pub fn maintain(&mut self, dt: std::time::Duration) {
|
|
|
|
span!(_guard, "maintain", "GlobalState::maintain");
|
|
|
|
self.audio.maintain(dt);
|
2021-06-16 13:07:23 +00:00
|
|
|
self.window.renderer().maintain()
|
2020-11-22 08:50:25 +00:00
|
|
|
}
|
2020-03-07 22:16:00 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "singleplayer")]
|
|
|
|
pub fn paused(&self) -> bool {
|
|
|
|
self.singleplayer
|
|
|
|
.as_ref()
|
|
|
|
.map_or(false, Singleplayer::is_paused)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "singleplayer"))]
|
|
|
|
pub fn paused(&self) -> bool { false }
|
|
|
|
|
2020-07-15 23:19:11 +00:00
|
|
|
#[cfg(feature = "singleplayer")]
|
|
|
|
pub fn unpause(&self) { self.singleplayer.as_ref().map(|s| s.pause(false)); }
|
|
|
|
|
|
|
|
#[cfg(feature = "singleplayer")]
|
|
|
|
pub fn pause(&self) { self.singleplayer.as_ref().map(|s| s.pause(true)); }
|
2020-02-29 03:59:11 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 06:06:37 +00:00
|
|
|
// TODO: appears to be currently unused by playstates
|
2020-02-29 03:59:11 +00:00
|
|
|
pub enum Direction {
|
|
|
|
Forwards,
|
|
|
|
Backwards,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// States can either close (and revert to a previous state), push a new state
|
|
|
|
/// on top of themselves, or switch to a totally different state.
|
|
|
|
pub enum PlayStateResult {
|
2019-10-27 07:11:18 +00:00
|
|
|
/// Keep running this play state.
|
|
|
|
Continue,
|
2020-02-29 03:59:11 +00:00
|
|
|
/// Pop all play states in reverse order and shut down the program.
|
|
|
|
Shutdown,
|
|
|
|
/// Close the current play state and pop it from the play state stack.
|
|
|
|
Pop,
|
|
|
|
/// Push a new play state onto the play state stack.
|
|
|
|
Push(Box<dyn PlayState>),
|
|
|
|
/// Switch the current play state with a new play state.
|
|
|
|
Switch(Box<dyn PlayState>),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A trait representing a playable game state. This may be a menu, a game
|
|
|
|
/// session, the title screen, etc.
|
|
|
|
pub trait PlayState {
|
2019-10-27 07:11:18 +00:00
|
|
|
/// Called when entering this play state from another
|
|
|
|
fn enter(&mut self, global_state: &mut GlobalState, direction: Direction);
|
|
|
|
|
|
|
|
/// Tick the play state
|
|
|
|
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult;
|
2020-02-29 03:59:11 +00:00
|
|
|
|
|
|
|
/// Get a descriptive name for this state type.
|
|
|
|
fn name(&self) -> &'static str;
|
2019-10-27 07:11:18 +00:00
|
|
|
|
2021-06-05 12:55:58 +00:00
|
|
|
/// Determines whether the play state should have an enforced FPS cap
|
|
|
|
fn capped_fps(&self) -> bool;
|
|
|
|
|
2021-07-04 09:47:18 +00:00
|
|
|
fn globals_bind_group(&self) -> &GlobalsBindGroup;
|
|
|
|
|
2019-10-27 07:11:18 +00:00
|
|
|
/// Draw the play state.
|
2021-07-04 09:47:18 +00:00
|
|
|
fn render<'a>(&'a self, drawer: &mut Drawer<'a>, settings: &Settings);
|
|
|
|
|
|
|
|
/// Determines whether egui will be rendered for this play state
|
|
|
|
fn egui_enabled(&self) -> bool;
|
2020-02-29 03:59:11 +00:00
|
|
|
}
|