From d49dd5b55d4ec326d307920092734825300527f6 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 4 May 2021 11:35:19 +0100 Subject: [PATCH] Server GUI 2 --- server-gui/Cargo.toml | 20 +++++ server-gui/src/main.rs | 169 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 server-gui/Cargo.toml create mode 100644 server-gui/src/main.rs diff --git a/server-gui/Cargo.toml b/server-gui/Cargo.toml new file mode 100644 index 0000000000..6a16870891 --- /dev/null +++ b/server-gui/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "server-gui" +version = "0.7.0" +authors = ["Joshua Barretto "] +edition = "2018" + +[features] +worldgen = ["server/worldgen"] +default = ["worldgen"] + +[dependencies] +server = { package = "veloren-server", path = "../server", default-features = false } +common = { package = "veloren-common", path = "../common" } +world = { package = "veloren-world", path = "../world" } + +tracing = { version = "0.1", default-features = false } +tracing-subscriber = { version = "0.2.3", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] } +vek = { version = "0.12.0", features = ["platform_intrinsics", "serde"] } + +iced = { git = "https://github.com/hecrj/iced.git", features = ["image", "debug", "tokio"] } diff --git a/server-gui/src/main.rs b/server-gui/src/main.rs new file mode 100644 index 0000000000..ff98ad9bd6 --- /dev/null +++ b/server-gui/src/main.rs @@ -0,0 +1,169 @@ +#![deny(unsafe_code)] + +use common::clock::Clock; +use iced::{ + executor, image, scrollable, Align, Application, Command, Element, Image, Length, Scrollable, + Settings, Subscription, +}; +use server::{Event, Input, Server, ServerSettings}; +use std::{ + sync::{Arc, Mutex}, + thread::{self, JoinHandle}, + time::Duration, +}; +use tracing::{info, Level}; +use tracing_subscriber::{filter::LevelFilter, EnvFilter, FmtSubscriber}; + +struct Gui { + server: Arc>, + server_worker: JoinHandle<()>, + scroll: scrollable::State, + map_image: image::Handle, +} + +#[derive(Debug, Clone)] +enum Message {} + +impl Application for Gui { + type Executor = executor::Default; + type Flags = (); + type Message = Message; + + fn new(_flags: Self::Flags) -> (Self, Command) { + // Create server + let server = + Server::new(ServerSettings::load()).expect("Failed to create server instance!"); + + // Create image of map + let map_image = { + let sz = server.map().dimensions_lg.map(|e| 1 << e); + let max_height = server.map().max_height; + let bytes = server.map().rgba + .iter() + //.map(|px| (0..4).map(move |i| (((*px & ((1 << 15) - 1)) >> 2) as f32 * 255.0 / max_height) as u8)) + .map(|px| { + let rgba = px.to_le_bytes(); + let b = [rgba[2], rgba[1], rgba[0], 0xFF]; + (0..4).map(move |i| b[i]) + }) + .flatten() + .collect::>(); + image::Handle::from_pixels(sz.x, sz.y, bytes) + }; + + let server = Arc::new(Mutex::new(server)); + + // Start server worker + let server_worker = { + let server = server.clone(); + thread::spawn(|| server_worker(server)) + }; + + ( + Gui { + server, + server_worker, + scroll: scrollable::State::default(), + map_image, + }, + Command::none(), + ) + } + + fn title(&self) -> String { "Veloren Server".to_string() } + + fn update(&mut self, msg: Self::Message) -> Command { + match msg {} + + //Command::none() + } + + fn subscription(&self) -> Subscription { Subscription::none() } + + fn view(&mut self) -> Element { + Scrollable::new(&mut self.scroll) + .align_items(Align::Center) + .width(Length::Fill) + .height(Length::Fill) + .push( + Image::new(self.map_image.clone()) + .width(Length::Units(4096)) + .height(Length::Units(4096)), + ) + .into() + } +} + +fn server_worker(server: Arc>) { + const TPS: u64 = 30; + const RUST_LOG_ENV: &str = "RUST_LOG"; + + info!("Starting server..."); + + // Set up an fps clock + let mut clock = Clock::start(); + + info!("Server is ready to accept connections."); + let game_addr = server.lock().unwrap().settings().gameserver_address.port(); + info!(?game_addr, "starting server at port"); + let metrics_addr = server.lock().unwrap().settings().metrics_address.port(); + info!(?metrics_addr, "starting metrics at port"); + + loop { + let events = { + let mut server = server.lock().unwrap(); + + let events = server + .tick(Input::default(), clock.get_last_delta()) + .expect("Failed to tick server"); + + // Clean up the server after a tick. + server.cleanup(); + + events + }; + + 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), + } + } + + // Wait for the next tick. + clock.tick(Duration::from_millis(1000 / TPS)); + } +} + +const TPS: u64 = 30; +const RUST_LOG_ENV: &str = "RUST_LOG"; + +fn main() { + // Init logging + let filter = match std::env::var_os(RUST_LOG_ENV).map(|s| s.into_string()) { + Some(Ok(env)) => { + let mut filter = EnvFilter::new("veloren_world::sim=info") + .add_directive("veloren_world::civ=info".parse().unwrap()) + .add_directive(LevelFilter::INFO.into()); + for s in env.split(',').into_iter() { + match s.parse() { + Ok(d) => filter = filter.add_directive(d), + Err(err) => println!("WARN ignoring log directive: `{}`: {}", s, err), + }; + } + filter + }, + _ => EnvFilter::from_env(RUST_LOG_ENV) + .add_directive("veloren_world::sim=info".parse().unwrap()) + .add_directive("veloren_world::civ=info".parse().unwrap()) + .add_directive(LevelFilter::INFO.into()), + }; + + FmtSubscriber::builder() + .with_max_level(Level::ERROR) + .with_env_filter(filter) + .init(); + + Gui::run(Settings::default()) +}