mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'singleplayer' into 'master'
Start Singleplayer server when singleplayer is selected See merge request veloren/veloren!39 Former-commit-id: ac8c9f3f52871d89847fdecc74ac58bb593e762b
This commit is contained in:
commit
1e4d02a5d8
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1960,6 +1960,7 @@ dependencies = [
|
|||||||
"vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"veloren-client 0.2.0",
|
"veloren-client 0.2.0",
|
||||||
"veloren-common 0.2.0",
|
"veloren-common 0.2.0",
|
||||||
|
"veloren-server 0.2.0",
|
||||||
"winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
1
voxygen/.gitignore
vendored
1
voxygen/.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
settings.toml
|
||||||
|
@ -12,6 +12,7 @@ default = ["gl"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
common = { package = "veloren-common", path = "../common" }
|
common = { package = "veloren-common", path = "../common" }
|
||||||
client = { package = "veloren-client", path = "../client" }
|
client = { package = "veloren-client", path = "../client" }
|
||||||
|
server = { package = "veloren-server", path = "../server" }
|
||||||
|
|
||||||
# Graphics
|
# Graphics
|
||||||
gfx = "0.17"
|
gfx = "0.17"
|
||||||
|
@ -13,12 +13,14 @@ pub mod session;
|
|||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
pub mod singleplayer;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use crate::error::Error;
|
pub use crate::error::Error;
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
use log;
|
use log;
|
||||||
@ -28,7 +30,8 @@ use pretty_env_logger;
|
|||||||
use crate::{
|
use crate::{
|
||||||
menu::main::MainMenuState,
|
menu::main::MainMenuState,
|
||||||
window::Window,
|
window::Window,
|
||||||
settings::Settings
|
settings::Settings,
|
||||||
|
singleplayer::Singleplayer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The URL of the default public server that Voxygen will connect to
|
/// The URL of the default public server that Voxygen will connect to
|
||||||
@ -38,6 +41,7 @@ const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
|
|||||||
pub struct GlobalState {
|
pub struct GlobalState {
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
window: Window,
|
window: Window,
|
||||||
|
singleplayer: Option<Singleplayer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalState {
|
impl GlobalState {
|
||||||
@ -91,6 +95,7 @@ fn main() {
|
|||||||
let mut global_state = GlobalState {
|
let mut global_state = GlobalState {
|
||||||
settings,
|
settings,
|
||||||
window,
|
window,
|
||||||
|
singleplayer: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set up the initial play state
|
// Set up the initial play state
|
||||||
|
@ -45,7 +45,10 @@ impl PlayState for CharSelectionState {
|
|||||||
// Handle window events
|
// Handle window events
|
||||||
for event in global_state.window.fetch_events() {
|
for event in global_state.window.fetch_events() {
|
||||||
match event {
|
match event {
|
||||||
Event::Close => return PlayStateResult::Shutdown,
|
Event::Close => {
|
||||||
|
global_state.singleplayer = None;
|
||||||
|
return PlayStateResult::Shutdown;
|
||||||
|
},
|
||||||
// Pass events to ui
|
// Pass events to ui
|
||||||
Event::Ui(event) => {
|
Event::Ui(event) => {
|
||||||
self.char_selection_ui.handle_event(event);
|
self.char_selection_ui.handle_event(event);
|
||||||
@ -60,7 +63,10 @@ impl PlayState for CharSelectionState {
|
|||||||
// Maintain the UI
|
// Maintain the UI
|
||||||
for event in self.char_selection_ui.maintain(global_state.window.renderer_mut()) {
|
for event in self.char_selection_ui.maintain(global_state.window.renderer_mut()) {
|
||||||
match event {
|
match event {
|
||||||
ui::Event::Logout => return PlayStateResult::Pop,
|
ui::Event::Logout => {
|
||||||
|
global_state.singleplayer = None;
|
||||||
|
return PlayStateResult::Pop;
|
||||||
|
},
|
||||||
ui::Event::Play => return PlayStateResult::Push(
|
ui::Event::Play => return PlayStateResult::Push(
|
||||||
Box::new(SessionState::new(&mut global_state.window, self.client.clone()))
|
Box::new(SessionState::new(&mut global_state.window, self.client.clone()))
|
||||||
),
|
),
|
||||||
|
@ -5,10 +5,12 @@ use super::char_selection::CharSelectionState;
|
|||||||
use crate::{
|
use crate::{
|
||||||
window::{Event, Window},
|
window::{Event, Window},
|
||||||
GlobalState, PlayState, PlayStateResult,
|
GlobalState, PlayState, PlayStateResult,
|
||||||
|
singleplayer::Singleplayer,
|
||||||
};
|
};
|
||||||
use client_init::{ClientInit, Error as InitError};
|
use client_init::{ClientInit, Error as InitError};
|
||||||
use common::{clock::Clock, comp};
|
use common::{clock::Clock, comp};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::thread;
|
||||||
use ui::{Event as MainMenuEvent, MainMenuUi};
|
use ui::{Event as MainMenuEvent, MainMenuUi};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -100,6 +102,9 @@ impl PlayState for MainMenuState {
|
|||||||
),
|
),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
MainMenuEvent::StartSingleplayer => {
|
||||||
|
global_state.singleplayer = Some(Singleplayer::new());
|
||||||
|
}
|
||||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ pub enum Event {
|
|||||||
username: String,
|
username: String,
|
||||||
server_address: String,
|
server_address: String,
|
||||||
},
|
},
|
||||||
|
StartSingleplayer,
|
||||||
Quit,
|
Quit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,6 +174,18 @@ impl MainMenuUi {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! singleplayer {
|
||||||
|
() => {
|
||||||
|
self.login_error = None;
|
||||||
|
events.push(Event::StartSingleplayer);
|
||||||
|
events.push(Event::LoginAttempt {
|
||||||
|
username: "singleplayer".to_string(),
|
||||||
|
server_address: "localhost".to_string(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
||||||
// Username
|
// Username
|
||||||
// TODO: get a lower resolution and cleaner input_bg.png
|
// TODO: get a lower resolution and cleaner input_bg.png
|
||||||
@ -297,7 +310,7 @@ impl MainMenuUi {
|
|||||||
.set(self.ids.singleplayer_button, ui_widgets)
|
.set(self.ids.singleplayer_button, ui_widgets)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
login!();
|
singleplayer!();
|
||||||
}
|
}
|
||||||
// Quit
|
// Quit
|
||||||
if Button::image(self.imgs.button)
|
if Button::image(self.imgs.button)
|
||||||
|
@ -125,7 +125,10 @@ impl PlayState for SessionState {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let _handled = match event {
|
let _handled = match event {
|
||||||
Event::Close => return PlayStateResult::Shutdown,
|
Event::Close => {
|
||||||
|
global_state.singleplayer = None;
|
||||||
|
return PlayStateResult::Shutdown;
|
||||||
|
},
|
||||||
// Toggle cursor grabbing
|
// Toggle cursor grabbing
|
||||||
Event::KeyDown(Key::ToggleCursor) => {
|
Event::KeyDown(Key::ToggleCursor) => {
|
||||||
global_state
|
global_state
|
||||||
@ -166,7 +169,10 @@ impl PlayState for SessionState {
|
|||||||
self.client.borrow_mut().send_chat(msg);
|
self.client.borrow_mut().send_chat(msg);
|
||||||
},
|
},
|
||||||
HudEvent::Logout => return PlayStateResult::Pop,
|
HudEvent::Logout => return PlayStateResult::Pop,
|
||||||
HudEvent::Quit => return PlayStateResult::Shutdown,
|
HudEvent::Quit => {
|
||||||
|
global_state.singleplayer = None;
|
||||||
|
return PlayStateResult::Shutdown;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
voxygen/src/singleplayer.rs
Normal file
81
voxygen/src/singleplayer.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
use log::info;
|
||||||
|
use server::{Input, Event, Server};
|
||||||
|
use common::clock::Clock;
|
||||||
|
use std::{
|
||||||
|
thread,
|
||||||
|
thread::JoinHandle
|
||||||
|
};
|
||||||
|
use std::sync::mpsc::{
|
||||||
|
channel, Receiver, Sender, TryRecvError,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TPS: u64 = 30;
|
||||||
|
|
||||||
|
enum Msg {
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to start and stop the background thread running the server
|
||||||
|
/// when in singleplayer mode.
|
||||||
|
pub struct Singleplayer {
|
||||||
|
server_thread: JoinHandle<()>,
|
||||||
|
sender: Sender<Msg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Singleplayer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let (sender, reciever) = channel();
|
||||||
|
let thread = thread::spawn(move || {
|
||||||
|
run_server(reciever);
|
||||||
|
});
|
||||||
|
Singleplayer {
|
||||||
|
server_thread: thread,
|
||||||
|
sender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Singleplayer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.sender.send(Msg::Stop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_server(rec: Receiver<Msg>) {
|
||||||
|
info!("Starting server-cli...");
|
||||||
|
|
||||||
|
// Set up an fps clock
|
||||||
|
let mut clock = Clock::new();
|
||||||
|
|
||||||
|
// Create server
|
||||||
|
let mut server = Server::new()
|
||||||
|
.expect("Failed to create server instance");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let events = server.tick(Input::default(), clock.get_last_delta())
|
||||||
|
.expect("Failed to tick server");
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
match event {
|
||||||
|
Event::ClientConnected { entity } => info!("Client connected!"),
|
||||||
|
Event::ClientDisconnected { entity } => info!("Client disconnected!"),
|
||||||
|
Event::Chat { entity, msg } => info!("[Client] {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the server after a tick
|
||||||
|
server.cleanup();
|
||||||
|
|
||||||
|
match rec.try_recv() {
|
||||||
|
Ok(msg) => break,
|
||||||
|
Err(err) => match err {
|
||||||
|
TryRecvError::Empty => (),
|
||||||
|
TryRecvError::Disconnected => break,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the next tick
|
||||||
|
clock.tick(Duration::from_millis(1000 / TPS));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user