#![deny(unsafe_code)]
#![allow(incomplete_features)]
#![allow(
clippy::identity_op,
clippy::option_map_unit_fn,
clippy::needless_pass_by_ref_mut )]
#![deny(clippy::clone_on_ref_ptr)]
#![feature(
extract_if,
trait_alias,
option_get_or_insert_default,
map_try_insert,
slice_as_chunks,
let_chains,
generic_const_exprs,
maybe_uninit_uninit_array,
maybe_uninit_array_assume_init,
closure_lifetime_binder
)]
#![recursion_limit = "2048"]
#[macro_use]
pub mod ui;
pub mod audio;
pub mod cli;
pub mod cmd;
pub mod controller;
mod credits;
#[cfg(feature = "discord")] pub mod discord;
mod ecs;
pub mod error;
pub mod game_input;
pub mod hud;
pub mod key_state;
pub mod menu;
pub mod mesh;
pub mod panic_handler;
pub mod profile;
pub mod render;
pub mod run;
pub mod scene;
pub mod session;
pub mod settings;
#[cfg(feature = "singleplayer")]
pub mod singleplayer;
pub mod window;
#[cfg(feature = "singleplayer")]
use crate::singleplayer::Singleplayer;
#[cfg(feature = "singleplayer")]
use crate::singleplayer::SingleplayerState;
#[cfg(feature = "egui-ui")]
use crate::ui::egui::EguiState;
use crate::{
audio::AudioFrontend,
profile::Profile,
render::{Drawer, GlobalsBindGroup},
settings::Settings,
window::{Event, Window},
};
use common::clock::Clock;
use common_base::span;
use i18n::LocalizationHandle;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::runtime::Runtime;
pub struct GlobalState {
pub userdata_dir: PathBuf,
pub config_dir: PathBuf,
pub settings: Settings,
pub profile: Profile,
pub window: Window,
pub tokio_runtime: Arc<Runtime>,
#[cfg(feature = "egui-ui")]
pub egui_state: EguiState,
pub lazy_init: scene::terrain::SpriteRenderContextLazy,
pub audio: AudioFrontend,
pub info_message: Option<String>,
pub clock: Clock,
#[cfg(feature = "singleplayer")]
pub singleplayer: SingleplayerState,
pub i18n: LocalizationHandle,
pub clipboard: iced_winit::Clipboard,
pub clear_shadows_next_frame: bool,
pub args: crate::cli::Args,
#[cfg(feature = "discord")]
pub discord: crate::discord::Discord,
}
impl GlobalState {
pub fn on_play_state_changed(&mut self) {
self.window.grab_cursor(false);
self.window.needs_refresh_resize();
}
pub fn maintain(&mut self) {
span!(_guard, "maintain", "GlobalState::maintain");
self.audio.maintain();
self.window.renderer().maintain()
}
#[cfg(feature = "singleplayer")]
pub fn paused(&self) -> bool {
self.singleplayer
.as_running()
.map_or(false, Singleplayer::is_paused)
}
#[cfg(not(feature = "singleplayer"))]
pub fn paused(&self) -> bool { false }
#[cfg(feature = "singleplayer")]
pub fn unpause(&self) { self.singleplayer.as_running().map(|s| s.pause(false)); }
#[cfg(feature = "singleplayer")]
pub fn pause(&self) { self.singleplayer.as_running().map(|s| s.pause(true)); }
}
pub enum Direction {
Forwards,
Backwards,
}
pub enum PlayStateResult {
Continue,
Shutdown,
Pop,
Push(Box<dyn PlayState>),
Switch(Box<dyn PlayState>),
}
pub trait PlayState {
fn enter(&mut self, global_state: &mut GlobalState, direction: Direction);
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult;
fn name(&self) -> &'static str;
fn capped_fps(&self) -> bool;
fn globals_bind_group(&self) -> &GlobalsBindGroup;
fn render(&self, drawer: &mut Drawer<'_>, settings: &Settings);
fn egui_enabled(&self) -> bool;
}