2019-01-23 20:01:58 +00:00
|
|
|
#![feature(drain_filter)]
|
2019-03-15 04:55:52 +00:00
|
|
|
#![recursion_limit="2048"]
|
2019-01-23 20:01:58 +00:00
|
|
|
|
2019-01-13 20:53:55 +00:00
|
|
|
pub mod anim;
|
2019-01-11 23:18:34 +00:00
|
|
|
pub mod error;
|
2019-03-15 04:55:52 +00:00
|
|
|
pub mod hud;
|
2019-03-02 03:48:30 +00:00
|
|
|
pub mod key_state;
|
2019-01-11 23:18:34 +00:00
|
|
|
pub mod menu;
|
2019-01-13 20:53:55 +00:00
|
|
|
pub mod mesh;
|
2019-01-11 23:18:34 +00:00
|
|
|
pub mod render;
|
|
|
|
pub mod scene;
|
|
|
|
pub mod session;
|
2019-01-30 12:11:34 +00:00
|
|
|
pub mod ui;
|
2019-01-11 23:18:34 +00:00
|
|
|
pub mod window;
|
2019-04-15 17:51:26 +00:00
|
|
|
pub mod settings;
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
// Reexports
|
|
|
|
pub use crate::error::Error;
|
2019-01-02 21:25:01 +00:00
|
|
|
|
|
|
|
// Standard
|
2019-01-11 23:18:34 +00:00
|
|
|
use std::mem;
|
2019-01-02 21:25:01 +00:00
|
|
|
|
2019-01-07 21:10:31 +00:00
|
|
|
// Library
|
2019-01-11 23:18:34 +00:00
|
|
|
use log;
|
|
|
|
use pretty_env_logger;
|
2019-01-07 21:10:31 +00:00
|
|
|
|
2019-01-02 21:25:01 +00:00
|
|
|
// Crate
|
|
|
|
use crate::{
|
2019-03-29 07:34:33 +00:00
|
|
|
menu::main::MainMenuState,
|
2019-01-02 21:25:01 +00:00
|
|
|
window::Window,
|
2019-04-16 08:56:47 +00:00
|
|
|
settings::Settings
|
2019-01-02 21:25:01 +00:00
|
|
|
};
|
|
|
|
|
2019-01-12 13:56:34 +00:00
|
|
|
/// A type used to store state that is shared between all play states
|
2019-01-02 21:25:01 +00:00
|
|
|
pub struct GlobalState {
|
2019-04-15 17:51:26 +00:00
|
|
|
settings: Settings,
|
2019-01-02 21:25:01 +00:00
|
|
|
window: Window,
|
|
|
|
}
|
|
|
|
|
2019-01-12 01:14:58 +00:00
|
|
|
impl GlobalState {
|
2019-01-12 13:56:34 +00:00
|
|
|
/// Called after a change in play state has occured (usually used to reverse any temporary
|
|
|
|
/// effects a state may have made).
|
2019-01-12 01:14:58 +00:00
|
|
|
pub fn on_play_state_changed(&mut self) {
|
2019-01-23 22:21:47 +00:00
|
|
|
self.window.grab_cursor(false);
|
2019-03-28 04:42:04 +00:00
|
|
|
self.window.needs_refresh_resize();
|
2019-01-12 01:14:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-02 21:25:01 +00:00
|
|
|
// 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
|
2019-01-07 21:10:31 +00:00
|
|
|
pub enum PlayStateResult {
|
|
|
|
/// Pop all play states in reverse order and shut down the program
|
|
|
|
Shutdown,
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Close the current play state and pop it from the play state stack
|
|
|
|
Pop,
|
2019-01-07 21:10:31 +00:00
|
|
|
/// Push a new play state onto the play state stack
|
2019-01-02 21:25:01 +00:00
|
|
|
Push(Box<dyn PlayState>),
|
2019-01-07 21:10:31 +00:00
|
|
|
/// Switch the current play state with a new play state
|
2019-01-02 21:25:01 +00:00
|
|
|
Switch(Box<dyn PlayState>),
|
|
|
|
}
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
/// A trait representing a playable game state. This may be a menu, a game session, the title
|
|
|
|
/// screen, etc.
|
2019-01-02 21:25:01 +00:00
|
|
|
pub trait PlayState {
|
2019-01-11 23:18:34 +00:00
|
|
|
/// Play the state until some change of state is required (i.e: a menu is opened or the game
|
|
|
|
/// is closed).
|
2019-01-07 21:10:31 +00:00
|
|
|
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult;
|
2019-01-11 23:18:34 +00:00
|
|
|
|
|
|
|
/// Get a descriptive name for this state type
|
|
|
|
fn name(&self) -> &'static str;
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2019-01-11 23:18:34 +00:00
|
|
|
// Init logging
|
|
|
|
pretty_env_logger::init();
|
|
|
|
|
|
|
|
// Set up the global state
|
2019-04-16 08:56:47 +00:00
|
|
|
let settings = match Settings::load() {
|
|
|
|
Ok(settings) => settings,
|
2019-04-16 16:06:23 +00:00
|
|
|
Err(err) => {
|
|
|
|
let settings = Settings::default();
|
|
|
|
settings.save_to_file();
|
|
|
|
settings
|
|
|
|
},
|
2019-04-16 08:56:47 +00:00
|
|
|
};
|
2019-04-15 17:51:26 +00:00
|
|
|
let window = Window::new(&settings).expect("Failed to create window");
|
|
|
|
|
2019-01-02 21:25:01 +00:00
|
|
|
let mut global_state = GlobalState {
|
2019-04-15 17:51:26 +00:00
|
|
|
settings,
|
|
|
|
window,
|
2019-01-02 21:25:01 +00:00
|
|
|
};
|
|
|
|
|
2019-01-30 12:11:34 +00:00
|
|
|
// Set up the initial play state
|
2019-03-29 07:34:33 +00:00
|
|
|
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(
|
2019-02-16 03:01:42 +00:00
|
|
|
&mut global_state.window,
|
2019-01-30 12:11:34 +00:00
|
|
|
))];
|
|
|
|
states.last().map(|current_state| {
|
|
|
|
log::info!("Started game with state '{}'", current_state.name())
|
|
|
|
});
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
// What's going on here?
|
|
|
|
// ---------------------
|
|
|
|
// The state system used by Voxygen allows for the easy development of stack-based menus.
|
|
|
|
// For example, you may want a "title" state that can push a "main menu" state on top of it,
|
|
|
|
// which can in turn push a "settings" state or a "game session" state on top of it.
|
|
|
|
// The code below manages the state transfer logic automatically so that we don't have to
|
|
|
|
// re-engineer it for each menu we decide to add to the game.
|
2019-01-02 22:08:13 +00:00
|
|
|
while let Some(state_result) = states.last_mut().map(|last| last.play(&mut global_state)){
|
2019-01-02 21:25:01 +00:00
|
|
|
// Implement state transfer logic
|
2019-01-02 22:08:13 +00:00
|
|
|
match state_result {
|
2019-01-11 23:18:34 +00:00
|
|
|
PlayStateResult::Shutdown => {
|
|
|
|
log::info!("Shutting down all states...");
|
|
|
|
while states.last().is_some() {
|
|
|
|
states.pop().map(|old_state| {
|
2019-01-12 01:14:58 +00:00
|
|
|
log::info!("Popped state '{}'", old_state.name());
|
|
|
|
global_state.on_play_state_changed();
|
2019-01-11 23:18:34 +00:00
|
|
|
});
|
|
|
|
}
|
2019-01-07 21:10:31 +00:00
|
|
|
},
|
2019-01-11 23:18:34 +00:00
|
|
|
PlayStateResult::Pop => {
|
|
|
|
states.pop().map(|old_state| {
|
2019-01-12 01:14:58 +00:00
|
|
|
log::info!("Popped state '{}'", old_state.name());
|
|
|
|
global_state.on_play_state_changed();
|
2019-01-11 23:18:34 +00:00
|
|
|
});
|
2019-01-02 22:08:13 +00:00
|
|
|
},
|
2019-01-07 21:10:31 +00:00
|
|
|
PlayStateResult::Push(new_state) => {
|
2019-01-11 23:18:34 +00:00
|
|
|
log::info!("Pushed state '{}'", new_state.name());
|
2019-01-02 22:08:13 +00:00
|
|
|
states.push(new_state);
|
2019-01-12 01:14:58 +00:00
|
|
|
global_state.on_play_state_changed();
|
2019-01-02 22:08:13 +00:00
|
|
|
},
|
2019-01-07 21:10:31 +00:00
|
|
|
PlayStateResult::Switch(mut new_state) => {
|
2019-01-11 23:18:34 +00:00
|
|
|
states.last_mut().map(|old_state| {
|
|
|
|
log::info!("Switching to state '{}' from state '{}'", new_state.name(), old_state.name());
|
|
|
|
mem::swap(old_state, &mut new_state);
|
2019-01-12 01:14:58 +00:00
|
|
|
global_state.on_play_state_changed();
|
2019-01-11 23:18:34 +00:00
|
|
|
});
|
2019-01-02 21:25:01 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|