Implement StartSingleplayerState

Former-commit-id: 982246096fe20c33631c1df3ce172c60b4f49bfe
This commit is contained in:
timokoesters 2019-04-27 22:55:30 +02:00
parent b72c6b7185
commit a4d7d0d488
6 changed files with 95 additions and 22 deletions

View File

@ -25,7 +25,6 @@ use crate::{
menu::main::MainMenuState,
window::Window,
settings::Settings,
singleplayer::Singleplayer,
};
/// The URL of the default public server that Voxygen will connect to
@ -35,7 +34,6 @@ const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
pub struct GlobalState {
settings: Settings,
window: Window,
singleplayer: Option<Singleplayer>,
}
impl GlobalState {
@ -47,6 +45,11 @@ impl GlobalState {
}
}
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 {
@ -65,7 +68,7 @@ pub enum PlayStateResult {
pub trait PlayState {
/// Play the state until some change of state is required (i.e: a menu is opened or the game
/// is closed).
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult;
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult;
/// Get a descriptive name for this state type
fn name(&self) -> &'static str;
@ -123,7 +126,6 @@ The information below is intended for developers and testers.
let mut global_state = GlobalState {
settings,
window,
singleplayer: None,
};
// Set up the initial play state
@ -141,10 +143,12 @@ The information below is intended for developers and testers.
// 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.
while let Some(state_result) = states.last_mut().map(|last| last.play(&mut global_state)){
let mut direction = Direction::Forwards;
while let Some(state_result) = states.last_mut().map(|last| last.play(direction, &mut global_state)){
// Implement state transfer logic
match state_result {
PlayStateResult::Shutdown => {
direction = Direction::Backwards;
log::info!("Shutting down all states...");
while states.last().is_some() {
states.pop().map(|old_state| {
@ -154,17 +158,20 @@ The information below is intended for developers and testers.
}
},
PlayStateResult::Pop => {
direction = Direction::Backwards;
states.pop().map(|old_state| {
log::info!("Popped state '{}'", old_state.name());
global_state.on_play_state_changed();
});
},
PlayStateResult::Push(new_state) => {
direction = Direction::Forwards;
log::info!("Pushed state '{}'", new_state.name());
states.push(new_state);
global_state.on_play_state_changed();
},
PlayStateResult::Switch(mut new_state) => {
direction = Direction::Forwards;
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);

View File

@ -3,7 +3,7 @@ mod ui;
use crate::{
window::{Event, Window},
session::SessionState,
GlobalState, PlayState, PlayStateResult,
Direction, GlobalState, PlayState, PlayStateResult,
};
use client::{self, Client};
use common::{
@ -40,7 +40,7 @@ const BG_COLOR: Rgba<f32> = Rgba {
};
impl PlayState for CharSelectionState {
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
// Set up an fps clock
let mut clock = Clock::new();
@ -49,7 +49,6 @@ impl PlayState for CharSelectionState {
for event in global_state.window.fetch_events() {
match event {
Event::Close => {
global_state.singleplayer = None;
return PlayStateResult::Shutdown;
},
// Pass events to ui
@ -67,7 +66,6 @@ impl PlayState for CharSelectionState {
for event in self.char_selection_ui.maintain(global_state.window.renderer_mut()) {
match event {
ui::Event::Logout => {
global_state.singleplayer = None;
return PlayStateResult::Pop;
},
ui::Event::Play => {

View File

@ -1,11 +1,12 @@
mod client_init;
mod start_singleplayer;
mod ui;
use start_singleplayer::StartSingleplayerState;
use super::char_selection::CharSelectionState;
use crate::{
window::{Event, Window},
GlobalState, PlayState, PlayStateResult,
singleplayer::Singleplayer,
Direction, GlobalState, PlayState, PlayStateResult,
};
use client_init::{ClientInit, Error as InitError};
use common::{clock::Clock, comp};
@ -28,6 +29,8 @@ impl MainMenuState {
}
}
const DEFAULT_PORT: u16 = 59003;
// Background colour
const BG_COLOR: Rgba<f32> = Rgba {
r: 0.0,
@ -37,7 +40,7 @@ const BG_COLOR: Rgba<f32> = Rgba {
};
impl PlayState for MainMenuState {
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
// Set up an fps clock
let mut clock = Clock::new();
@ -98,7 +101,6 @@ impl PlayState for MainMenuState {
net_settings.servers.push(server_address.clone());
}
global_state.settings.save_to_file();
const DEFAULT_PORT: u16 = 59003;
// Don't try to connect if there is already a connection in progress
client_init = client_init.or(Some(ClientInit::new(
(server_address, DEFAULT_PORT, false),
@ -109,7 +111,7 @@ impl PlayState for MainMenuState {
)));
},
MainMenuEvent::StartSingleplayer => {
global_state.singleplayer = Some(Singleplayer::new());
return PlayStateResult::Push(Box::new(StartSingleplayerState::new()));
},
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
}

View File

@ -0,0 +1,66 @@
use common::comp;
use super::{DEFAULT_PORT, client_init::ClientInit};
use crate::{
menu::char_selection::CharSelectionState,
singleplayer::Singleplayer,
Direction, GlobalState, PlayState, PlayStateResult,
};
pub struct StartSingleplayerState {
singleplayer: Singleplayer,
}
impl StartSingleplayerState {
/// Create a new `MainMenuState`
pub fn new() -> Self {
Self {
singleplayer: Singleplayer::new(),
}
}
}
impl PlayState for StartSingleplayerState {
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult {
match direction {
Direction::Forwards => {
let username = "singleplayer".to_owned();
let server_address = "localhost".to_owned();
let client_init = ClientInit::new(
(server_address.clone(), DEFAULT_PORT, false),
(
comp::Player::new(username.clone()),
300,
),
);
// Client creation
let client = loop {
match client_init.poll() {
Some(Ok(client)) => break client,
// Should always work
Some(Err(err)) => unreachable!(),
_ => {},
}
};
let mut net_settings = &mut global_state.settings.networking;
net_settings.username = username.clone();
if !net_settings.servers.contains(&server_address) {
net_settings.servers.push(server_address.clone());
}
global_state.settings.save_to_file();
PlayStateResult::Push(Box::new(CharSelectionState::new(
&mut global_state.window,
std::rc::Rc::new(std::cell::RefCell::new(client)),
)))
},
Direction::Backwards => PlayStateResult::Pop,
}
}
fn name(&self) -> &'static str {
"Starting Singleplayer"
}
}

View File

@ -176,10 +176,11 @@ impl MainMenuUi {
.top_left_with_margins(30.0, 30.0)
.set(self.ids.v_logo, ui_widgets);
Text::new(version)
.top_left_with_margins_on(ui_widgets.window, 5.0, 5.0)
.font_size(14)
.color(TEXT_COLOR)
.set(self.ids.version, ui_widgets);
.top_left_with_margins_on(ui_widgets.window, 5.0, 5.0)
.font_size(14)
.color(TEXT_COLOR)
.set(self.ids.version, ui_widgets);
// Input fields
// Used when the login button is pressed, or enter is pressed within input field
macro_rules! login {
@ -390,7 +391,7 @@ impl MainMenuUi {
};
// Singleplayer button
if Button::image(self.imgs.button)
if Button::image(self.imgs.button)
.hover_image(self.imgs.button_hover)
.press_image(self.imgs.button_press)
.w_h(258.0, 68.0)

View File

@ -6,6 +6,7 @@ use client::{
Client,
};
use crate::{
Direction,
Error,
PlayState,
PlayStateResult,
@ -100,7 +101,7 @@ impl SessionState {
}
impl PlayState for SessionState {
fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
// Trap the cursor
global_state.window.grab_cursor(true);
@ -129,7 +130,6 @@ impl PlayState for SessionState {
}
let _handled = match event {
Event::Close => {
global_state.singleplayer = None;
return PlayStateResult::Shutdown;
},
// Toggle cursor grabbing
@ -171,7 +171,6 @@ impl PlayState for SessionState {
},
HudEvent::Logout => return PlayStateResult::Pop,
HudEvent::Quit => {
global_state.singleplayer = None;
return PlayStateResult::Shutdown;
},
}