2019-01-23 20:01:58 +00:00
|
|
|
#![feature(drain_filter)]
|
2019-04-29 20:37:19 +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-04-15 17:51:26 +00:00
|
|
|
pub mod settings;
|
2019-04-17 14:57:23 +00:00
|
|
|
pub mod singleplayer;
|
2019-04-29 20:37:19 +00:00
|
|
|
pub mod ui;
|
|
|
|
pub mod window;
|
2019-04-15 17:51:26 +00:00
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
// Reexports
|
|
|
|
pub use crate::error::Error;
|
2019-01-02 21:25:01 +00:00
|
|
|
|
2019-04-29 20:37:19 +00:00
|
|
|
use crate::{menu::main::MainMenuState, settings::Settings, window::Window};
|
2019-01-11 23:18:34 +00:00
|
|
|
use log;
|
2019-04-29 20:37:19 +00:00
|
|
|
use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
|
|
|
|
use std::{fs::File, mem, panic, str::FromStr, thread};
|
2019-01-02 21:25:01 +00:00
|
|
|
|
2019-04-17 13:23:34 +00:00
|
|
|
/// The URL of the default public server that Voxygen will connect to
|
|
|
|
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
|
|
|
|
|
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-04-27 20:55:30 +00:00
|
|
|
pub enum Direction {
|
|
|
|
Forwards,
|
|
|
|
Backwards,
|
|
|
|
}
|
|
|
|
|
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-04-27 20:55:30 +00:00
|
|
|
fn play(&mut self, direction: Direction, 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
|
|
|
// 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-29 20:37:19 +00:00
|
|
|
}
|
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-04-25 11:49:36 +00:00
|
|
|
// Init logging
|
2019-04-29 16:56:38 +00:00
|
|
|
let term_log_level = std::env::var_os("VOXYGEN_LOG")
|
|
|
|
.and_then(|env| env.to_str().map(|s| s.to_owned()))
|
|
|
|
.and_then(|s| log::LevelFilter::from_str(&s).ok())
|
|
|
|
.unwrap_or(log::LevelFilter::Warn);
|
2019-04-25 11:49:36 +00:00
|
|
|
CombinedLogger::init(vec![
|
2019-04-29 16:56:38 +00:00
|
|
|
TermLogger::new(term_log_level, Config::default()).unwrap(),
|
2019-04-29 20:37:19 +00:00
|
|
|
WriteLogger::new(
|
|
|
|
log::LevelFilter::Info,
|
|
|
|
Config::default(),
|
|
|
|
File::create(&settings.log.file).unwrap(),
|
|
|
|
),
|
|
|
|
])
|
|
|
|
.unwrap();
|
2019-04-25 11:49:36 +00:00
|
|
|
|
|
|
|
// Set up panic handler to relay swish panic messages to the user
|
|
|
|
let settings_clone = settings.clone();
|
|
|
|
panic::set_hook(Box::new(move |panic_info| {
|
|
|
|
let msg = format!(" \
|
|
|
|
A critical error has occured and Voxygen has been forced to terminate in an unusual manner. Details about the error can be found below.
|
|
|
|
|
|
|
|
> What should I do?
|
|
|
|
|
2019-04-25 11:55:45 +00:00
|
|
|
We need your help to fix this! You can help by contacting us and reporting this problem. To do this, open an issue on the Veloren issue tracker:
|
2019-04-25 11:49:36 +00:00
|
|
|
|
|
|
|
https://www.gitlab.com/veloren/veloren/issues/new
|
|
|
|
|
|
|
|
If you're on the Veloren community Discord server, we'd be grateful if you could also post a message in the #support channel.
|
|
|
|
|
|
|
|
> What should I include?
|
|
|
|
|
2019-04-25 11:55:45 +00:00
|
|
|
The error information below will be useful in finding and fixing the problem. Please include as much information about your setup and the events that led up to the panic as possible.
|
2019-04-25 11:49:36 +00:00
|
|
|
|
2019-04-25 11:55:45 +00:00
|
|
|
Voxygen has logged information about the problem (including this message) to the file {:#?}. Please include the contents of this file in your bug report.
|
2019-04-25 11:49:36 +00:00
|
|
|
|
|
|
|
> Error information
|
|
|
|
|
|
|
|
The information below is intended for developers and testers.
|
|
|
|
|
2019-04-25 11:55:45 +00:00
|
|
|
{:?}", settings_clone.log.file, panic_info);
|
2019-04-25 11:49:36 +00:00
|
|
|
|
|
|
|
log::error!("VOXYGEN HAS PANICKED\n\n{}", msg);
|
|
|
|
|
|
|
|
msgbox::create("Voxygen has panicked", &msg, msgbox::IconType::ERROR);
|
|
|
|
}));
|
|
|
|
|
2019-04-29 20:37:19 +00:00
|
|
|
let mut global_state = GlobalState { 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-04-29 20:37:19 +00:00
|
|
|
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
|
|
|
|
states
|
|
|
|
.last()
|
|
|
|
.map(|current_state| log::info!("Started game with state '{}'", current_state.name()));
|
2019-01-30 12:11:34 +00:00
|
|
|
|
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-04-27 20:55:30 +00:00
|
|
|
let mut direction = Direction::Forwards;
|
2019-04-29 20:37:19 +00:00
|
|
|
while let Some(state_result) = states
|
|
|
|
.last_mut()
|
|
|
|
.map(|last| last.play(direction, &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 => {
|
2019-04-27 20:55:30 +00:00
|
|
|
direction = Direction::Backwards;
|
2019-01-11 23:18:34 +00:00
|
|
|
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-04-29 20:37:19 +00:00
|
|
|
}
|
2019-01-11 23:18:34 +00:00
|
|
|
PlayStateResult::Pop => {
|
2019-04-27 20:55:30 +00:00
|
|
|
direction = Direction::Backwards;
|
2019-01-11 23:18:34 +00:00
|
|
|
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-04-29 20:37:19 +00:00
|
|
|
}
|
2019-01-07 21:10:31 +00:00
|
|
|
PlayStateResult::Push(new_state) => {
|
2019-04-27 20:55:30 +00:00
|
|
|
direction = Direction::Forwards;
|
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-04-29 20:37:19 +00:00
|
|
|
}
|
2019-01-07 21:10:31 +00:00
|
|
|
PlayStateResult::Switch(mut new_state) => {
|
2019-04-27 20:55:30 +00:00
|
|
|
direction = Direction::Forwards;
|
2019-01-11 23:18:34 +00:00
|
|
|
states.last_mut().map(|old_state| {
|
2019-04-29 20:37:19 +00:00
|
|
|
log::info!(
|
|
|
|
"Switching to state '{}' from state '{}'",
|
|
|
|
new_state.name(),
|
|
|
|
old_state.name()
|
|
|
|
);
|
2019-01-11 23:18:34 +00:00
|
|
|
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-04-29 20:37:19 +00:00
|
|
|
}
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|