2019-04-14 23:28:29 +00:00
mod client_init ;
2020-02-01 20:39:39 +00:00
#[ cfg(feature = " singleplayer " ) ] mod ui ;
2019-01-02 22:08:13 +00:00
2019-03-17 17:52:54 +00:00
use super ::char_selection ::CharSelectionState ;
2019-10-18 20:05:37 +00:00
use crate ::{
2020-01-17 23:43:18 +00:00
i18n ::{ i18n_asset_key , VoxygenLocalization } ,
singleplayer ::Singleplayer ,
window ::Event ,
Direction , GlobalState , PlayState , PlayStateResult ,
2019-10-18 20:05:37 +00:00
} ;
2020-01-02 08:43:45 +00:00
use client_init ::{ ClientInit , Error as InitError , Msg as InitMsg } ;
2020-01-17 23:43:18 +00:00
use common ::{ assets ::load_expect , clock ::Clock , comp } ;
2020-01-02 08:43:45 +00:00
use log ::{ error , warn } ;
2019-09-15 20:41:47 +00:00
#[ cfg(feature = " singleplayer " ) ]
2019-03-15 04:55:52 +00:00
use std ::time ::Duration ;
2019-03-17 17:52:54 +00:00
use ui ::{ Event as MainMenuEvent , MainMenuUi } ;
2019-01-02 21:25:01 +00:00
2019-03-04 07:28:16 +00:00
pub struct MainMenuState {
main_menu_ui : MainMenuUi ,
2019-01-30 12:11:34 +00:00
}
2019-01-02 21:25:01 +00:00
2019-03-04 07:28:16 +00:00
impl MainMenuState {
2019-05-17 09:22:32 +00:00
/// Create a new `MainMenuState`.
2019-04-18 17:40:29 +00:00
pub fn new ( global_state : & mut GlobalState ) -> Self {
2019-01-30 12:11:34 +00:00
Self {
2019-04-18 17:40:29 +00:00
main_menu_ui : MainMenuUi ::new ( global_state ) ,
2019-01-30 12:11:34 +00:00
}
2019-01-02 21:25:01 +00:00
}
}
2019-07-20 11:59:35 +00:00
const DEFAULT_PORT : u16 = 14004 ;
2019-04-27 20:55:30 +00:00
2020-01-08 22:45:10 +00:00
static LOGIN_FAILED_MSG : & str = " If you are having issues signing in. Please note that you now need an account to play on auth-enabled servers. \n You can create an account over at https://account.veloren.net. " ;
2019-03-04 07:28:16 +00:00
impl PlayState for MainMenuState {
2019-04-27 20:55:30 +00:00
fn play ( & mut self , _ : Direction , global_state : & mut GlobalState ) -> PlayStateResult {
2019-05-17 09:22:32 +00:00
// Set up an fps clock.
2019-07-01 20:42:43 +00:00
let mut clock = Clock ::start ( ) ;
2019-03-04 07:28:16 +00:00
2019-05-17 09:22:32 +00:00
// Used for client creation.
2019-04-14 23:28:29 +00:00
let mut client_init : Option < ClientInit > = None ;
2019-10-04 17:31:24 +00:00
// Kick off title music
2020-02-15 21:30:44 +00:00
if global_state . settings . audio . audio_on & & global_state . audio . music_enabled ( ) {
global_state . audio . play_title_music ( ) ;
2019-10-17 07:10:24 +00:00
}
2019-10-04 17:31:24 +00:00
2019-10-18 20:05:37 +00:00
// Reset singleplayer server if it was running already
2020-03-01 22:18:22 +00:00
global_state . singleplayer = None ;
2019-10-18 20:05:37 +00:00
2019-01-11 23:18:34 +00:00
loop {
2019-05-17 09:22:32 +00:00
// Handle window events.
2020-01-02 03:48:11 +00:00
for event in global_state . window . fetch_events ( & mut global_state . settings ) {
2019-01-07 21:10:31 +00:00
match event {
2019-01-11 23:18:34 +00:00
Event ::Close = > return PlayStateResult ::Shutdown ,
2019-05-17 09:22:32 +00:00
// Pass events to ui.
2019-03-22 03:55:42 +00:00
Event ::Ui ( event ) = > {
self . main_menu_ui . handle_event ( event ) ;
2020-02-01 20:39:39 +00:00
} ,
2019-05-17 09:22:32 +00:00
// Ignore all other events.
2020-02-01 20:39:39 +00:00
_ = > { } ,
2019-01-07 21:10:31 +00:00
}
}
2019-01-02 21:25:01 +00:00
2019-07-04 12:02:26 +00:00
global_state . window . renderer_mut ( ) . clear ( ) ;
2019-02-12 04:14:55 +00:00
2019-05-17 09:22:32 +00:00
// Poll client creation.
2019-04-15 20:51:32 +00:00
match client_init . as_ref ( ) . and_then ( | init | init . poll ( ) ) {
2020-01-10 00:33:38 +00:00
Some ( Ok ( mut client ) ) = > {
2019-04-14 23:28:29 +00:00
self . main_menu_ui . connected ( ) ;
2020-01-10 00:33:38 +00:00
// Register voxygen components / resources
crate ::ecs ::init ( client . state_mut ( ) . ecs_mut ( ) ) ;
2019-04-14 23:28:29 +00:00
return PlayStateResult ::Push ( Box ::new ( CharSelectionState ::new (
2019-07-26 02:28:53 +00:00
global_state ,
2019-04-14 23:28:29 +00:00
std ::rc ::Rc ::new ( std ::cell ::RefCell ::new ( client ) ) ,
) ) ) ;
2020-02-01 20:39:39 +00:00
} ,
2020-01-02 08:43:45 +00:00
Some ( InitMsg ::Done ( Err ( err ) ) ) = > {
2019-04-14 23:28:29 +00:00
client_init = None ;
2020-01-04 10:21:59 +00:00
global_state . info_message = Some ( {
let err = match err {
InitError ::BadAddress ( _ ) | InitError ::NoAddress = > {
" Server not found " . into ( )
} ,
2020-01-02 08:43:45 +00:00
InitError ::ClientError ( err ) = > match err {
2020-01-07 06:27:18 +00:00
client ::Error ::AuthErr ( e ) = > format! ( " Auth error on server: {} " , e ) ,
2020-01-04 10:21:59 +00:00
client ::Error ::TooManyPlayers = > " Server is full " . into ( ) ,
client ::Error ::AuthServerNotTrusted = > {
" Auth server not trusted " . into ( )
} ,
client ::Error ::ServerWentMad = > " ServerWentMad: Probably versions \
are incompatible , check for \
updates . "
. into ( ) ,
client ::Error ::ServerTimeout = > " Timeout: Server did not respond \
in time . ( Overloaded or network \
issues ) . "
. into ( ) ,
client ::Error ::ServerShutdown = > " Server shut down " . into ( ) ,
client ::Error ::AlreadyLoggedIn = > {
" You are already logged into the server. " . into ( )
} ,
client ::Error ::Network ( e ) = > format! ( " Network error: {:?} " , e ) ,
client ::Error ::Other ( e ) = > format! ( " Error: {} " , e ) ,
client ::Error ::AuthClientError ( e ) = > match e {
client ::AuthClientError ::JsonError ( e ) = > {
format! ( " Fatal error: {} " , e )
} ,
2020-01-08 22:45:10 +00:00
client ::AuthClientError ::RequestError ( _ ) = > {
LOGIN_FAILED_MSG . into ( )
2020-01-04 10:21:59 +00:00
} ,
client ::AuthClientError ::ServerError ( _ , e ) = > format! ( " {} " , e ) ,
2020-01-02 08:43:45 +00:00
} ,
} ,
2020-01-04 10:21:59 +00:00
InitError ::ClientCrashed = > " Client crashed " . into ( ) ,
} ;
// Log error for possible additional use later or incase that the error
// displayed is cut of.
error! ( " {} " , err ) ;
err
} ) ;
2020-02-01 20:39:39 +00:00
} ,
2020-01-02 08:43:45 +00:00
Some ( InitMsg ::IsAuthTrusted ( auth_server ) ) = > {
if global_state
. settings
. networking
. trusted_auth_servers
. contains ( & auth_server )
{
// Can't fail since we just polled it, it must be Some
client_init . as_ref ( ) . unwrap ( ) . auth_trust ( auth_server , true ) ;
} else {
// Show warning that auth server is not trusted and prompt for approval
self . main_menu_ui . auth_trust_prompt ( auth_server ) ;
}
} ,
2020-02-01 20:39:39 +00:00
None = > { } ,
2019-04-14 23:28:29 +00:00
}
2019-05-18 20:10:02 +00:00
// Maintain global_state
2019-08-31 08:30:23 +00:00
global_state . maintain ( clock . get_last_delta ( ) . as_secs_f32 ( ) ) ;
2019-05-18 20:10:02 +00:00
2019-05-17 09:22:32 +00:00
// Maintain the UI.
2019-11-23 00:51:18 +00:00
for event in self
. main_menu_ui
. maintain ( global_state , clock . get_last_delta ( ) )
{
2019-04-04 14:45:57 +00:00
match event {
2019-04-14 23:28:29 +00:00
MainMenuEvent ::LoginAttempt {
username ,
2019-08-07 19:42:44 +00:00
password ,
2019-04-14 23:28:29 +00:00
server_address ,
} = > {
2019-10-18 20:05:37 +00:00
attempt_login (
global_state ,
username ,
password ,
server_address ,
DEFAULT_PORT ,
& mut client_init ,
2019-06-29 15:04:06 +00:00
) ;
2020-02-01 20:39:39 +00:00
} ,
2019-09-29 19:12:26 +00:00
MainMenuEvent ::CancelLoginAttempt = > {
2020-02-01 20:39:39 +00:00
// client_init contains Some(ClientInit), which spawns a thread which
// contains a TcpStream::connect() call This call is
// blocking TODO fix when the network rework happens
2020-03-01 22:18:22 +00:00
global_state . singleplayer = None ;
2019-09-29 19:12:26 +00:00
client_init = None ;
self . main_menu_ui . cancel_connection ( ) ;
2020-02-01 20:39:39 +00:00
} ,
2019-09-15 20:41:47 +00:00
#[ cfg(feature = " singleplayer " ) ]
2019-04-18 13:53:03 +00:00
MainMenuEvent ::StartSingleplayer = > {
2019-10-18 20:05:37 +00:00
let ( singleplayer , server_settings ) = Singleplayer ::new ( None ) ; // TODO: Make client and server use the same thread pool
2020-03-01 22:18:22 +00:00
global_state . singleplayer = Some ( singleplayer ) ;
2019-10-18 20:05:37 +00:00
attempt_login (
global_state ,
" singleplayer " . to_owned ( ) ,
" " . to_owned ( ) ,
server_settings . gameserver_address . ip ( ) . to_string ( ) ,
server_settings . gameserver_address . port ( ) ,
& mut client_init ,
) ;
2020-02-01 20:39:39 +00:00
} ,
MainMenuEvent ::Settings = > { } , // TODO
2019-04-04 14:45:57 +00:00
MainMenuEvent ::Quit = > return PlayStateResult ::Shutdown ,
2019-05-26 20:42:45 +00:00
MainMenuEvent ::DisclaimerClosed = > {
global_state . settings . show_disclaimer = false
2020-02-01 20:39:39 +00:00
} ,
2020-01-02 08:43:45 +00:00
MainMenuEvent ::AuthServerTrust ( auth_server , trust ) = > {
if trust {
global_state
. settings
. networking
. trusted_auth_servers
. insert ( auth_server . clone ( ) ) ;
global_state . settings . save_to_file_warn ( ) ;
}
client_init
. as_ref ( )
. map ( | init | init . auth_trust ( auth_server , trust ) ) ;
} ,
2019-04-04 14:45:57 +00:00
}
2019-03-04 07:28:16 +00:00
}
2020-01-17 23:43:18 +00:00
let localized_strings = load_expect ::< VoxygenLocalization > ( & i18n_asset_key (
& global_state . settings . language . selected_language ,
) ) ;
2019-01-30 12:11:34 +00:00
2019-10-18 20:05:37 +00:00
if let Some ( info ) = global_state . info_message . take ( ) {
2020-01-02 09:49:48 +00:00
self . main_menu_ui . show_info ( info ) ;
2019-10-18 11:24:18 +00:00
}
2019-05-17 09:22:32 +00:00
// Draw the UI to the screen.
2019-03-04 07:28:16 +00:00
self . main_menu_ui . render ( global_state . window . renderer_mut ( ) ) ;
2019-02-11 06:12:46 +00:00
2019-05-17 09:22:32 +00:00
// Finish the frame.
2019-02-12 04:14:55 +00:00
global_state . window . renderer_mut ( ) . flush ( ) ;
2019-03-15 04:55:52 +00:00
global_state
. window
2019-03-04 07:28:16 +00:00
. swap_buffers ( )
2019-05-17 09:22:32 +00:00
. expect ( " Failed to swap window buffers! " ) ;
2019-03-04 07:28:16 +00:00
2019-05-18 19:28:12 +00:00
// Wait for the next tick
2019-06-06 19:11:39 +00:00
clock . tick ( Duration ::from_millis (
1000 / ( global_state . settings . graphics . max_fps as u64 ) ,
) ) ;
2019-01-02 21:25:01 +00:00
}
}
2019-01-11 23:18:34 +00:00
2020-02-01 20:39:39 +00:00
fn name ( & self ) -> & 'static str { " Title " }
2019-01-02 21:25:01 +00:00
}
2019-10-18 20:05:37 +00:00
fn attempt_login (
global_state : & mut GlobalState ,
username : String ,
password : String ,
server_address : String ,
server_port : u16 ,
client_init : & mut Option < ClientInit > ,
) {
let mut net_settings = & mut global_state . settings . networking ;
net_settings . username = username . clone ( ) ;
net_settings . password = password . clone ( ) ;
if ! net_settings . servers . contains ( & server_address ) {
net_settings . servers . push ( server_address . clone ( ) ) ;
}
if let Err ( err ) = global_state . settings . save_to_file ( ) {
warn! ( " Failed to save settings: {:?} " , err ) ;
}
let player = comp ::Player ::new (
username . clone ( ) ,
Some ( global_state . settings . graphics . view_distance ) ,
) ;
if player . is_valid ( ) {
// Don't try to connect if there is already a connection in progress.
if client_init . is_none ( ) {
* client_init = Some ( ClientInit ::new (
( server_address , server_port , false ) ,
player ,
2020-01-02 08:43:45 +00:00
{ password } ,
2019-10-18 20:05:37 +00:00
) ) ;
}
} else {
global_state . info_message = Some ( " Invalid username or password " . to_string ( ) ) ;
}
}