mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added basic networked communications, chat communication
Former-commit-id: 06bafdf69486f4da5fbc416835e34c5bed8c2caa
This commit is contained in:
parent
187b7939d7
commit
dbbcc1e80e
@ -2,6 +2,7 @@
|
|||||||
members = [
|
members = [
|
||||||
"common",
|
"common",
|
||||||
"client",
|
"client",
|
||||||
|
"chat-cli",
|
||||||
"server",
|
"server",
|
||||||
"server-cli",
|
"server-cli",
|
||||||
"voxygen",
|
"voxygen",
|
||||||
|
3
chat-cli/.gitignore
vendored
Normal file
3
chat-cli/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
12
chat-cli/Cargo.toml
Normal file
12
chat-cli/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "veloren-chat-cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
client = { package = "veloren-client", path = "../client" }
|
||||||
|
common = { package = "veloren-common", path = "../common" }
|
||||||
|
|
||||||
|
log = "0.4"
|
||||||
|
pretty_env_logger = "0.3"
|
37
chat-cli/src/main.rs
Normal file
37
chat-cli/src/main.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
use log::info;
|
||||||
|
use client::{Input, Client, Event};
|
||||||
|
use common::clock::Clock;
|
||||||
|
|
||||||
|
const FPS: u64 = 60;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Init logging
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
info!("Starting chat-cli...");
|
||||||
|
|
||||||
|
// Set up an fps clock
|
||||||
|
let mut clock = Clock::new();
|
||||||
|
|
||||||
|
// Create client
|
||||||
|
let mut client = Client::new(([127, 0, 0, 1], 59003))
|
||||||
|
.expect("Failed to create client instance");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let events = client.tick(Input::default(), clock.get_last_delta())
|
||||||
|
.expect("Failed to tick client");
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
match event {
|
||||||
|
Event::Chat(msg) => println!("[chat] {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the server after a tick
|
||||||
|
client.cleanup();
|
||||||
|
|
||||||
|
// Wait for the next tick
|
||||||
|
clock.tick(Duration::from_millis(1000 / FPS));
|
||||||
|
}
|
||||||
|
}
|
17
client/src/error.rs
Normal file
17
client/src/error.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use common::net::PostError;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Network(PostError),
|
||||||
|
ServerShutdown,
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PostError> for Error {
|
||||||
|
fn from(err: PostError) -> Self {
|
||||||
|
match err {
|
||||||
|
PostError::Disconnected => Error::ServerShutdown,
|
||||||
|
err => Error::Network(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
client/src/input.rs
Normal file
14
client/src/input.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use vek::*;
|
||||||
|
|
||||||
|
pub struct Input {
|
||||||
|
// TODO: Use this type to manage client input
|
||||||
|
pub move_dir: Vec2<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Input {
|
||||||
|
fn default() -> Self {
|
||||||
|
Input {
|
||||||
|
move_dir: Vec2::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,38 @@
|
|||||||
// Standard
|
pub mod error;
|
||||||
use std::time::Duration;
|
pub mod input;
|
||||||
|
|
||||||
// Library
|
// Reexports
|
||||||
use specs::Entity as EcsEntity;
|
pub use specs::Entity as EcsEntity;
|
||||||
|
pub use crate::{
|
||||||
|
error::Error,
|
||||||
|
input::Input,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
time::Duration,
|
||||||
|
net::SocketAddr,
|
||||||
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use threadpool;
|
use threadpool;
|
||||||
|
use common::{
|
||||||
// Project
|
comp::phys::Vel,
|
||||||
use common::{comp::phys::Vel, state::State, terrain::TerrainChunk};
|
state::State,
|
||||||
|
terrain::TerrainChunk,
|
||||||
|
net::PostBox,
|
||||||
|
msg::{ClientMsg, ServerMsg},
|
||||||
|
};
|
||||||
use world::World;
|
use world::World;
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub enum Event {
|
||||||
pub enum Error {
|
Chat(String),
|
||||||
ServerShutdown,
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Input {
|
|
||||||
// TODO: Use this type to manage client input
|
|
||||||
pub move_dir: Vec2<f32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
thread_pool: threadpool::ThreadPool,
|
thread_pool: threadpool::ThreadPool,
|
||||||
|
|
||||||
|
last_ping: f64,
|
||||||
|
postbox: PostBox<ClientMsg, ServerMsg>,
|
||||||
|
|
||||||
tick: u64,
|
tick: u64,
|
||||||
state: State,
|
state: State,
|
||||||
player: Option<EcsEntity>,
|
player: Option<EcsEntity>,
|
||||||
@ -35,25 +44,35 @@ pub struct Client {
|
|||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Create a new `Client`.
|
/// Create a new `Client`.
|
||||||
pub fn new() -> Self {
|
#[allow(dead_code)]
|
||||||
Self {
|
pub fn new<A: Into<SocketAddr>>(addr: A) -> Result<Self, Error> {
|
||||||
|
let state = State::new();
|
||||||
|
|
||||||
|
let mut postbox = PostBox::to_server(addr)?;
|
||||||
|
postbox.send(ClientMsg::Chat(String::from("Hello, world!")));
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
thread_pool: threadpool::Builder::new()
|
thread_pool: threadpool::Builder::new()
|
||||||
.thread_name("veloren-worker".into())
|
.thread_name("veloren-worker".into())
|
||||||
.build(),
|
.build(),
|
||||||
|
|
||||||
|
last_ping: state.get_time(),
|
||||||
|
postbox,
|
||||||
|
|
||||||
tick: 0,
|
tick: 0,
|
||||||
state: State::new(),
|
state,
|
||||||
player: None,
|
player: None,
|
||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
world: World::new(),
|
world: World::new(),
|
||||||
chunk: None,
|
chunk: None,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the client's worker thread pool. This pool should be used for any
|
/// Get a reference to the client's worker thread pool. This pool should be used for any
|
||||||
/// computationally expensive operations that run outside of the main thread (i.e: threads that
|
/// computationally expensive operations that run outside of the main thread (i.e: threads that
|
||||||
/// block on I/O operations are exempt).
|
/// block on I/O operations are exempt).
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool }
|
pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool }
|
||||||
|
|
||||||
// TODO: Get rid of this
|
// TODO: Get rid of this
|
||||||
@ -70,23 +89,34 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the client's game state.
|
/// Get a reference to the client's game state.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn state(&self) -> &State { &self.state }
|
pub fn state(&self) -> &State { &self.state }
|
||||||
|
|
||||||
/// Get a mutable reference to the client's game state.
|
/// Get a mutable reference to the client's game state.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
||||||
|
|
||||||
/// Get the player entity
|
/// Get the player entity
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn player(&self) -> Option<EcsEntity> {
|
pub fn player(&self) -> Option<EcsEntity> {
|
||||||
self.player
|
self.player
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current tick number.
|
/// Get the current tick number.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn get_tick(&self) -> u64 {
|
pub fn get_tick(&self) -> u64 {
|
||||||
self.tick
|
self.tick
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a chat message to the server
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn send_chat(&mut self, msg: String) -> Result<(), Error> {
|
||||||
|
Ok(self.postbox.send(ClientMsg::Chat(msg))?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute a single client tick, handle input and update the game state by the given duration
|
/// Execute a single client tick, handle input and update the game state by the given duration
|
||||||
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<(), Error> {
|
#[allow(dead_code)]
|
||||||
|
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||||
// This tick function is the centre of the Veloren universe. Most client-side things are
|
// This tick function is the centre of the Veloren universe. Most client-side things are
|
||||||
// managed from here, and as such it's important that it stays organised. Please consult
|
// managed from here, and as such it's important that it stays organised. Please consult
|
||||||
// the core developers before making significant changes to this code. Here is the
|
// the core developers before making significant changes to this code. Here is the
|
||||||
@ -99,7 +129,13 @@ impl Client {
|
|||||||
// 4) Go through the terrain update queue and apply all changes to the terrain
|
// 4) Go through the terrain update queue and apply all changes to the terrain
|
||||||
// 5) Finish the tick, passing control of the main thread back to the frontend
|
// 5) Finish the tick, passing control of the main thread back to the frontend
|
||||||
|
|
||||||
// (step 1)
|
// Build up a list of events for this frame, to be passed to the frontend
|
||||||
|
let mut frontend_events = Vec::new();
|
||||||
|
|
||||||
|
// Handle new messages from the server
|
||||||
|
frontend_events.append(&mut self.handle_new_messages()?);
|
||||||
|
|
||||||
|
// Step 3
|
||||||
if let Some(p) = self.player {
|
if let Some(p) = self.player {
|
||||||
// TODO: remove this
|
// TODO: remove this
|
||||||
const PLAYER_VELOCITY: f32 = 100.0;
|
const PLAYER_VELOCITY: f32 = 100.0;
|
||||||
@ -113,12 +149,40 @@ impl Client {
|
|||||||
|
|
||||||
// Finish the tick, pass control back to the frontend (step 6)
|
// Finish the tick, pass control back to the frontend (step 6)
|
||||||
self.tick += 1;
|
self.tick += 1;
|
||||||
Ok(())
|
Ok(frontend_events)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up the client after a tick
|
/// Clean up the client after a tick
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn cleanup(&mut self) {
|
pub fn cleanup(&mut self) {
|
||||||
// Cleanup the local state
|
// Cleanup the local state
|
||||||
self.state.cleanup();
|
self.state.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle new server messages
|
||||||
|
fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> {
|
||||||
|
let mut frontend_events = Vec::new();
|
||||||
|
|
||||||
|
// Step 1
|
||||||
|
let new_msgs = self.postbox.new_messages();
|
||||||
|
|
||||||
|
if new_msgs.len() > 0 {
|
||||||
|
self.last_ping = self.state.get_time();
|
||||||
|
|
||||||
|
for msg in new_msgs {
|
||||||
|
match msg {
|
||||||
|
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
|
||||||
|
ServerMsg::Shutdown => return Err(Error::ServerShutdown),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(frontend_events)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Client {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.postbox.send(ClientMsg::Disconnect).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ extern crate serde_derive;
|
|||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod comp;
|
pub mod comp;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
|
pub mod msg;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
|
5
common/src/msg/client.rs
Normal file
5
common/src/msg/client.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum ClientMsg {
|
||||||
|
Chat(String),
|
||||||
|
Disconnect,
|
||||||
|
}
|
6
common/src/msg/mod.rs
Normal file
6
common/src/msg/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pub mod server;
|
||||||
|
pub mod client;
|
||||||
|
|
||||||
|
// Reexports
|
||||||
|
pub use server::ServerMsg;
|
||||||
|
pub use client::ClientMsg;
|
5
common/src/msg/server.rs
Normal file
5
common/src/msg/server.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum ServerMsg {
|
||||||
|
Chat(String),
|
||||||
|
Shutdown,
|
||||||
|
}
|
@ -112,7 +112,7 @@ where
|
|||||||
/// Non-blocking receiver method returning an iterator over already received and deserialized objects
|
/// Non-blocking receiver method returning an iterator over already received and deserialized objects
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// If the other side disconnects PostBox won't realize that until you try to send something
|
/// If the other side disconnects PostBox won't realize that until you try to send something
|
||||||
pub fn recv_iter(&mut self) -> impl Iterator<Item = R> {
|
pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item = R> {
|
||||||
let mut events = Events::with_capacity(4096);
|
let mut events = Events::with_capacity(4096);
|
||||||
let mut items = VecDeque::new();
|
let mut items = VecDeque::new();
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ where
|
|||||||
/// Non-blocking method returning an iterator over new connections wrapped in [`PostBox`]es
|
/// Non-blocking method returning an iterator over new connections wrapped in [`PostBox`]es
|
||||||
pub fn new_connections(
|
pub fn new_connections(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> impl Iterator<Item = PostBox<S, R>> {
|
) -> impl ExactSizeIterator<Item = PostBox<S, R>> {
|
||||||
let mut events = Events::with_capacity(256);
|
let mut events = Events::with_capacity(256);
|
||||||
let mut conns = VecDeque::new();
|
let mut conns = VecDeque::new();
|
||||||
|
|
||||||
|
@ -72,6 +72,19 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a component with the state's ECS
|
||||||
|
pub fn with_component<T: Component>(mut self) -> Self
|
||||||
|
where <T as Component>::Storage: Default
|
||||||
|
{
|
||||||
|
self.ecs_world.register::<T>();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an entity from the state's ECS, if it exists
|
||||||
|
pub fn delete_entity(&mut self, entity: EcsEntity) {
|
||||||
|
let _ = self.ecs_world.delete_entity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get rid of this
|
// TODO: Get rid of this
|
||||||
pub fn new_test_player(&mut self) -> EcsEntity {
|
pub fn new_test_player(&mut self) -> EcsEntity {
|
||||||
self.ecs_world
|
self.ecs_world
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
// Standard
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// Library
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use server::{Input, Event, Server};
|
||||||
// Project
|
|
||||||
use server::{self, Server};
|
|
||||||
use common::clock::Clock;
|
use common::clock::Clock;
|
||||||
|
|
||||||
const FPS: u64 = 60;
|
const FPS: u64 = 60;
|
||||||
@ -20,12 +15,21 @@ fn main() {
|
|||||||
let mut clock = Clock::new();
|
let mut clock = Clock::new();
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
let mut server = Server::new();
|
let mut server = Server::new()
|
||||||
|
.expect("Failed to create server instance");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
server.tick(server::Input {}, clock.get_last_delta())
|
let events = server.tick(Input::default(), clock.get_last_delta())
|
||||||
.expect("Failed to tick server");
|
.expect("Failed to tick server");
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
match event {
|
||||||
|
Event::ClientConnected { ecs_entity } => println!("Client connected!"),
|
||||||
|
Event::ClientDisconnected { ecs_entity } => println!("Client disconnected!"),
|
||||||
|
Event::Chat { msg, .. } => println!("[chat] {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up the server after a tick
|
// Clean up the server after a tick
|
||||||
server.cleanup();
|
server.cleanup();
|
||||||
|
|
||||||
|
11
server/src/client.rs
Normal file
11
server/src/client.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use specs::Entity as EcsEntity;
|
||||||
|
use common::{
|
||||||
|
msg::{ServerMsg, ClientMsg},
|
||||||
|
net::PostBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
pub ecs_entity: EcsEntity,
|
||||||
|
pub postbox: PostBox<ServerMsg, ClientMsg>,
|
||||||
|
pub last_ping: f64,
|
||||||
|
}
|
13
server/src/error.rs
Normal file
13
server/src/error.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use common::net::PostError;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Network(PostError),
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PostError> for Error {
|
||||||
|
fn from(err: PostError) -> Self {
|
||||||
|
Error::Network(err)
|
||||||
|
}
|
||||||
|
}
|
9
server/src/input.rs
Normal file
9
server/src/input.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub struct Input {
|
||||||
|
// TODO: Use this type to manage server input
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Input {
|
||||||
|
fn default() -> Self {
|
||||||
|
Input {}
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +1,81 @@
|
|||||||
// Standard
|
#![feature(drain_filter)]
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
// Internal
|
pub mod client;
|
||||||
use common::state::State;
|
pub mod error;
|
||||||
|
pub mod input;
|
||||||
|
|
||||||
|
// Reexports
|
||||||
|
pub use crate::{
|
||||||
|
error::Error,
|
||||||
|
input::Input,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
time::Duration,
|
||||||
|
net::SocketAddr,
|
||||||
|
};
|
||||||
|
use specs::Entity as EcsEntity;
|
||||||
|
use common::{
|
||||||
|
state::State,
|
||||||
|
net::PostOffice,
|
||||||
|
msg::{ServerMsg, ClientMsg},
|
||||||
|
};
|
||||||
use world::World;
|
use world::World;
|
||||||
|
use crate::client::Client;
|
||||||
|
|
||||||
#[derive(Debug)]
|
const CLIENT_TIMEOUT: f64 = 5.0; // Seconds
|
||||||
pub enum Error {
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Input {
|
pub enum Event {
|
||||||
// TODO: Use this type to manage server input
|
ClientConnected {
|
||||||
|
ecs_entity: EcsEntity,
|
||||||
|
},
|
||||||
|
ClientDisconnected {
|
||||||
|
ecs_entity: EcsEntity,
|
||||||
|
},
|
||||||
|
Chat {
|
||||||
|
ecs_entity: EcsEntity,
|
||||||
|
msg: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
state: State,
|
state: State,
|
||||||
world: World,
|
world: World,
|
||||||
|
|
||||||
// TODO: Add "meta" state here
|
postoffice: PostOffice<ServerMsg, ClientMsg>,
|
||||||
|
clients: Vec<Client>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
/// Create a new `Server`.
|
/// Create a new `Server`.
|
||||||
pub fn new() -> Self {
|
#[allow(dead_code)]
|
||||||
Self {
|
pub fn new() -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
state: State::new(),
|
state: State::new(),
|
||||||
world: World::new(),
|
world: World::new(),
|
||||||
}
|
|
||||||
|
postoffice: PostOffice::new(SocketAddr::from(([0; 4], 59003)))?,
|
||||||
|
clients: Vec::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the server's game state.
|
/// Get a reference to the server's game state.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn state(&self) -> &State { &self.state }
|
pub fn state(&self) -> &State { &self.state }
|
||||||
/// Get a mutable reference to the server's game state.
|
/// Get a mutable reference to the server's game state.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
||||||
|
|
||||||
/// Get a reference to the server's world.
|
/// Get a reference to the server's world.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn world(&self) -> &World { &self.world }
|
pub fn world(&self) -> &World { &self.world }
|
||||||
/// Get a mutable reference to the server's world.
|
/// Get a mutable reference to the server's world.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn world_mut(&mut self) -> &mut World { &mut self.world }
|
pub fn world_mut(&mut self) -> &mut World { &mut self.world }
|
||||||
|
|
||||||
/// Execute a single server tick, handle input and update the game state by the given duration
|
/// Execute a single server tick, handle input and update the game state by the given duration
|
||||||
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<(), Error> {
|
#[allow(dead_code)]
|
||||||
|
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||||
// This tick function is the centre of the Veloren universe. Most server-side things are
|
// This tick function is the centre of the Veloren universe. Most server-side things are
|
||||||
// managed from here, and as such it's important that it stays organised. Please consult
|
// managed from here, and as such it's important that it stays organised. Please consult
|
||||||
// the core developers before making significant changes to this code. Here is the
|
// the core developers before making significant changes to this code. Here is the
|
||||||
@ -56,16 +90,108 @@ impl Server {
|
|||||||
// 6) Send relevant state updates to all clients
|
// 6) Send relevant state updates to all clients
|
||||||
// 7) Finish the tick, passing control of the main thread back to the frontend
|
// 7) Finish the tick, passing control of the main thread back to the frontend
|
||||||
|
|
||||||
|
// Build up a list of events for this frame, to be passed to the frontend
|
||||||
|
let mut frontend_events = Vec::new();
|
||||||
|
|
||||||
|
// If networking has problems, handle them
|
||||||
|
if let Some(err) = self.postoffice.status() {
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle new client connections (step 2)
|
||||||
|
frontend_events.append(&mut self.handle_new_connections()?);
|
||||||
|
|
||||||
|
// Handle new messages from clients
|
||||||
|
frontend_events.append(&mut self.handle_new_messages()?);
|
||||||
|
|
||||||
// Tick the client's LocalState (step 3)
|
// Tick the client's LocalState (step 3)
|
||||||
self.state.tick(dt);
|
self.state.tick(dt);
|
||||||
|
|
||||||
// Finish the tick, pass control back to the frontend (step 6)
|
// Finish the tick, pass control back to the frontend (step 6)
|
||||||
Ok(())
|
Ok(frontend_events)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up the server after a tick
|
/// Clean up the server after a tick
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn cleanup(&mut self) {
|
pub fn cleanup(&mut self) {
|
||||||
// Cleanup the local state
|
// Cleanup the local state
|
||||||
self.state.cleanup();
|
self.state.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle new client connections
|
||||||
|
fn handle_new_connections(&mut self) -> Result<Vec<Event>, Error> {
|
||||||
|
let mut frontend_events = Vec::new();
|
||||||
|
|
||||||
|
for postbox in self.postoffice.new_connections() {
|
||||||
|
// TODO: Don't use this method
|
||||||
|
let ecs_entity = self.state.new_test_player();
|
||||||
|
|
||||||
|
frontend_events.push(Event::ClientConnected {
|
||||||
|
ecs_entity,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.clients.push(Client {
|
||||||
|
ecs_entity,
|
||||||
|
postbox,
|
||||||
|
last_ping: self.state.get_time(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(frontend_events)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle new client messages
|
||||||
|
fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> {
|
||||||
|
let mut frontend_events = Vec::new();
|
||||||
|
|
||||||
|
let state = &mut self.state;
|
||||||
|
let mut new_chat_msgs = Vec::new();
|
||||||
|
|
||||||
|
self.clients.drain_filter(|client| {
|
||||||
|
let mut disconnected = false;
|
||||||
|
let new_msgs = client.postbox.new_messages();
|
||||||
|
|
||||||
|
// Update client ping
|
||||||
|
if new_msgs.len() > 0 {
|
||||||
|
client.last_ping = state.get_time();
|
||||||
|
|
||||||
|
// Process incoming messages
|
||||||
|
for msg in new_msgs {
|
||||||
|
match msg {
|
||||||
|
ClientMsg::Chat(msg) => new_chat_msgs.push((client.ecs_entity, msg)),
|
||||||
|
ClientMsg::Disconnect => disconnected = true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if
|
||||||
|
state.get_time() - client.last_ping > CLIENT_TIMEOUT ||
|
||||||
|
client.postbox.status().is_some()
|
||||||
|
{
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if disconnected {
|
||||||
|
state.delete_entity(client.ecs_entity);
|
||||||
|
frontend_events.push(Event::ClientDisconnected {
|
||||||
|
ecs_entity: client.ecs_entity,
|
||||||
|
});
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle new chat messages
|
||||||
|
for (ecs_entity, msg) in new_chat_msgs {
|
||||||
|
for client in &mut self.clients {
|
||||||
|
let _ = client.postbox.send(ServerMsg::Chat(msg.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
frontend_events.push(Event::Chat {
|
||||||
|
ecs_entity,
|
||||||
|
msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(frontend_events)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ impl Animation for RunAnimation {
|
|||||||
//skeleton.br_foot.offset = Vec3::new(0.0, wavecos_slow * 1.0, wave_slow * 2.0 + wave_dip * 1.0);
|
//skeleton.br_foot.offset = Vec3::new(0.0, wavecos_slow * 1.0, wave_slow * 2.0 + wave_dip * 1.0);
|
||||||
//skeleton.br_foot.ori = Quaternion::rotation_x(0.0 + wave_slow * 10.1);
|
//skeleton.br_foot.ori = Quaternion::rotation_x(0.0 + wave_slow * 10.1);
|
||||||
|
|
||||||
skeleton.bl_foot.offset = Vec3::new(0.0, 0.0, 80.0);
|
skeleton.bl_foot.offset = Vec3::new(0.0, 0.0, 0.0);
|
||||||
skeleton.bl_foot.ori = Quaternion::rotation_x(wave_slow * 2.0);
|
skeleton.bl_foot.ori = Quaternion::rotation_x(wave_slow * 2.0);
|
||||||
//skeleton.bl_foot.offset = Vec3::new(0.0, wavecos_slow * 1.0, wave_slow * 2.0 + wave_dip * 1.0);
|
//skeleton.bl_foot.offset = Vec3::new(0.0, wavecos_slow * 1.0, wave_slow * 2.0 + wave_dip * 1.0);
|
||||||
//skeleton.bl_foot.ori = Quaternion::rotation_x(0.5 + wave_slow * 0.1);
|
//skeleton.bl_foot.ori = Quaternion::rotation_x(0.5 + wave_slow * 0.1);
|
||||||
|
@ -84,7 +84,7 @@ impl Scene {
|
|||||||
[
|
[
|
||||||
Some(load_segment("dragonhead.vox").generate_mesh(Vec3::new(2.0, -12.0, 2.0))),
|
Some(load_segment("dragonhead.vox").generate_mesh(Vec3::new(2.0, -12.0, 2.0))),
|
||||||
Some(load_segment("dragon_body.vox").generate_mesh(Vec3::new(0.0, 0.0, 0.0))),
|
Some(load_segment("dragon_body.vox").generate_mesh(Vec3::new(0.0, 0.0, 0.0))),
|
||||||
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(10.0, 10.0, -80.0))),
|
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(0.0, 10.0, -4.0))),
|
||||||
Some(load_segment("dragon_rfoot.vox").generate_mesh(Vec3::new(0.0, 10.0, -4.0))),
|
Some(load_segment("dragon_rfoot.vox").generate_mesh(Vec3::new(0.0, 10.0, -4.0))),
|
||||||
Some(load_segment("dragon_rfoot.vox").generate_mesh(Vec3::new(0.0, -10.0, -4.0))),
|
Some(load_segment("dragon_rfoot.vox").generate_mesh(Vec3::new(0.0, -10.0, -4.0))),
|
||||||
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(0.0, 0.0, 0.0))),
|
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(0.0, 0.0, 0.0))),
|
||||||
@ -95,7 +95,7 @@ impl Scene {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user