From f7606751a9bff2eca82a1424cefb10ea11aa6465 Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Fri, 14 Apr 2023 08:09:44 -0400 Subject: [PATCH] add typescript framework --- client/Cargo.toml | 62 ---- client/src/chat.rs | 25 -- client/src/lib.rs | 327 ------------------ client/src/macros.rs | 64 ---- client/src/rendering/mod.rs | 23 -- .../src/rendering/renderer_canvascentric.rs | 110 ------ .../src/rendering/renderer_playercentric.rs | 120 ------- client/src/rendering/util.rs | 8 - client/src/textures/loader_fast.rs | 96 ----- client/src/textures/loader_slow.rs | 20 -- client/src/textures/mod.rs | 48 --- 11 files changed, 903 deletions(-) delete mode 100644 client/Cargo.toml delete mode 100644 client/src/chat.rs delete mode 100644 client/src/lib.rs delete mode 100644 client/src/macros.rs delete mode 100644 client/src/rendering/mod.rs delete mode 100644 client/src/rendering/renderer_canvascentric.rs delete mode 100644 client/src/rendering/renderer_playercentric.rs delete mode 100644 client/src/rendering/util.rs delete mode 100644 client/src/textures/loader_fast.rs delete mode 100644 client/src/textures/loader_slow.rs delete mode 100644 client/src/textures/mod.rs diff --git a/client/Cargo.toml b/client/Cargo.toml deleted file mode 100644 index 6fb9f2bf27ebee66810da33cba849d44b5edb731..0000000000000000000000000000000000000000 --- a/client/Cargo.toml +++ /dev/null @@ -1,62 +0,0 @@ -[package] -name = "starkingdoms-client" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib"] - -[dependencies] -wasm-bindgen = "0.2" -js-sys = "0.3" -console_log = { version = "1", features = ["color"] } -log = "0.4" -futures = { version = "0.3", default-features = false } -wasm-bindgen-futures = "0.4" -url = "2.3" -starkingdoms-protocol = { version = "0.1.0", path = "../protocol" } -rmp-serde = "1.1" -ws_stream_wasm = "0.7" -serde = { version = "1", features = ["derive"] } -lazy_static = "1.4" -markdown = "1.0.0-alpha.7" # DO NOT DOWNGRADE -async-recursion = "1" -console_error_panic_hook = "0.1" -async-trait = "0.1.68" -image = { version = "0.24.6", optional = true } -ron = { version = "0.8", optional = true } -base64 = { version = "0.21.0", optional = true } - -[dependencies.web-sys] -version = "0.3.4" -features = [ - 'Document', - 'Element', - 'HtmlCanvasElement', - 'Window', - 'CanvasRenderingContext2d', - 'HtmlImageElement', - 'SvgImageElement', - 'HtmlVideoElement', - 'ImageBitmap', - 'OffscreenCanvas', - 'VideoFrame', - 'CanvasWindingRule', - 'Path2d', - 'CanvasPattern', - 'CanvasGradient', - 'HitRegionOptions', - 'ImageData', - 'TextMetrics', - 'DomMatrix', - 'CssStyleDeclaration' -] - -[features] -textures-slow = [] -textures-fast = ['image', 'ron', 'base64'] - -renderer-canvascentric = [] -renderer-playercentric = [] \ No newline at end of file diff --git a/client/src/chat.rs b/client/src/chat.rs deleted file mode 100644 index b682366dfa2aa04eb417eca489917c6f2df1327e..0000000000000000000000000000000000000000 --- a/client/src/chat.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::error::Error; -use wasm_bindgen::prelude::*; -use starkingdoms_protocol::MessageC2S; -use crate::CLIENT; -use futures::SinkExt; -use starkingdoms_protocol::message_c2s::MessageC2SChat; - -#[wasm_bindgen] -// TODO: Switch to async-aware mutexes -#[allow(clippy::await_holding_lock)] -pub async fn send_chat(message: &str) -> Result<(), JsError> { - let client_data = &mut CLIENT.write()?.client_data; - - if let Some(data) = client_data { - let msg = MessageC2S::Chat(MessageC2SChat { - message: message.to_string(), - special_fields: Default::default(), - }).try_into().map_err(|e: Box | JsError::new(&e.to_string()))?; - send!(data.tx, msg).await?; - } else { - return Err(JsError::new("Client not yet connected to server")); - } - - Ok(()) -} \ No newline at end of file diff --git a/client/src/lib.rs b/client/src/lib.rs deleted file mode 100644 index 55f30f827ea860c296cea2896425ef9f860b414c..0000000000000000000000000000000000000000 --- a/client/src/lib.rs +++ /dev/null @@ -1,327 +0,0 @@ -use std::error::Error; -use std::panic; -use std::str::FromStr; -use futures::stream::{SplitSink, SplitStream}; -use futures::{StreamExt}; -use log::{error, info, Level, trace, warn}; -use wasm_bindgen::prelude::*; -use ws_stream_wasm::{WsErr, WsMessage, WsMeta, WsStream}; -use futures::SinkExt; -use lazy_static::lazy_static; -use std::sync::Arc; -use std::sync::RwLock; -use async_recursion::async_recursion; -use futures::FutureExt; -use wasm_bindgen_futures::JsFuture; -use web_sys::{Window}; -use starkingdoms_protocol::message_c2s::{MessageC2SGoodbye, MessageC2SHello, MessageC2SPing}; -use starkingdoms_protocol::{MessageC2S, MessageS2C, PROTOCOL_VERSION}; -use starkingdoms_protocol::goodbye_reason::GoodbyeReason; -use starkingdoms_protocol::planet::Planet; -use starkingdoms_protocol::player::Player; -use starkingdoms_protocol::state::State; - -use crate::rendering::Renderer; -use crate::rendering::renderer::WebRenderer; -use crate::textures::loader::TextureLoader; -use crate::textures::{TextureManager, TextureSize}; - - -#[macro_use] -pub mod macros; -pub mod chat; -pub mod rendering; -pub mod textures; - -#[wasm_bindgen] -extern { - pub fn alert(s: &str); -} - -#[derive(Debug)] -pub struct Client { - pub client_data: Option, - pub planets: Vec, - pub x: f64, - pub y: f64, - pub players: Vec -} - -#[derive(Debug)] -pub struct ClientData { - pub state: State, - pub tx: SplitSink, - pub rx: SplitStream, - pub pong_timeout: u64, - pub textures: TextureLoader, - pub renderer: WebRenderer, - pub username: String -} - -pub const PONG_MAX_TIMEOUT: u64 = 5; - -lazy_static! { - pub static ref CLIENT: Arc> = Arc::new(RwLock::new(Client { - client_data: None, - planets: vec![], - x: 0f64, - y: 0f64, - players: vec![] - })); - //pub static ref BUTTONS: Arc = Arc::new(Buttons { up: false, left: false, right: false, down: false }); -} - -pub const MAX_CONNECTION_TRIES: i32 = 10; - -#[wasm_bindgen] -pub async fn rust_init(gateway: &str, username: &str, texture_size: &str) -> Result<(), JsValue> { - panic::set_hook(Box::new(console_error_panic_hook::hook)); - - set_status("Starting logger..."); - - console_log::init_with_level(Level::Debug).unwrap(); - - info!("Logger setup successfully"); - - info!("Loading sprites..."); - set_status("Loading sprites.."); - - let textures = TextureLoader::load(TextureSize::from_str(texture_size).unwrap()).map_err(|e| e.to_string())?; - - match main(gateway, username, 1, textures, WebRenderer::get("canvas").await.unwrap()).await { - Ok(c) => c, - Err(e) => { - error!("Error initializing gateway client: {}", e); - return Err(JsValue::from_str(&e.to_string())); - } - }; - - info!("StarKingdoms client set up successfully"); - - Ok(()) -} - -#[async_recursion(?Send)] -pub async fn main(gateway: &str, username: &str, backoff: i32, textures: TextureLoader, renderer: WebRenderer) -> Result<(), Box> { - if backoff != 1 { - info!("Backing off connection: waiting {} seconds", backoff * backoff); - wait_for(sleep(backoff * backoff * 1000)).await; - } - - if backoff > MAX_CONNECTION_TRIES { - set_status("Connection to server failed"); - return Err("Hit backoff limit during reconnection attempt".into()); - } - if backoff == 1 { - set_status("Connecting to server..."); - } else { - set_status(&format!("Connection failed, retrying... (try {}/10)", backoff)); - } - - info!("FAST CONNECT: {}", gateway); - let gateway_url = url::Url::parse(gateway)?; - trace!("Gateway URL parsed"); - let (_ws, ws_stream) = match WsMeta::connect(gateway_url, None).await { - Ok(r) => r, - Err(e) => { - return match e { - WsErr::ConnectionFailed { .. } => { - main(gateway, username, backoff + 1, textures, renderer).await - }, - _ => { - Err(e.into()) - } - } - } - }; - trace!("Connected to gateway socket"); - let (tx, rx) = ws_stream.split(); - - let mut client_data = ClientData { - state: State::Handshake, - tx, - rx, - pong_timeout: (js_sys::Date::now() as u64 / 1000) + 5, - textures, - renderer, - username: username.to_string() - }; - - trace!("Split stream, handshaking with server"); - - set_status("Handshaking with server..."); - - let msg = MessageC2S::Hello(MessageC2SHello { - version: PROTOCOL_VERSION, - requested_username: username.to_string(), - next_state: State::Play.into(), - special_fields: Default::default(), - }).try_into()?; - send!(client_data.tx, msg).await?; - - trace!("Sent handshake start packet"); - - if let Some(msg) = recv_now!(client_data.rx)? { - let typed_msg: MessageS2C = msg; - - match typed_msg { - MessageS2C::Hello(pkt) => { - info!("FAST CONNECT - connected to server protocol {} given username {}, switching to state {:?}", pkt.version, pkt.given_username, pkt.next_state); - client_data.state = pkt.next_state.unwrap(); - }, - MessageS2C::Goodbye(pkt) => { - error!("server disconnected before finishing handshake: {:?}", pkt.reason); - return Err(format!("disconnected by server: {:?}", pkt.reason).into()); - }, - _ => { - warn!("received unexpected packet from server: {:?}", typed_msg); - } - } - } else { - error!("Server closed the connection") - } - - CLIENT.write()?.client_data = Some(client_data); - - set_status(&format!("Connected! Username: {}", username)); - - Ok(()) -} - -#[wasm_bindgen] -pub async fn send_ping_pong() -> Result<(), JsError> { - let mut client = CLIENT.write()?; - - if client.client_data.is_none() { - return Err(JsError::new("Client not yet initialized")); - } - - let client_data = client.client_data.as_mut().unwrap(); - - - send!(client_data.tx, MessageC2S::Ping(MessageC2SPing {special_fields: Default::default()}).try_into().map_err(|_| JsError::new("I/O Error"))?).await?; - - Ok(()) -} - -#[wasm_bindgen] -pub async fn update_socket() -> Result<(), JsError> { - - let mut client = CLIENT.write()?; - - if client.client_data.is_none() { - return Err(JsError::new("Client not yet initialized")); - } - - let client_data = client.client_data.as_mut().unwrap(); - - if client_data.pong_timeout < (js_sys::Date::now() as u64 / 1000) { - error!("Connection timed out"); - let msg = MessageC2S::Goodbye(MessageC2SGoodbye { - reason: GoodbyeReason::PingPongTimeout.into(), - special_fields: Default::default(), - }).try_into().map_err(|e: Box | JsError::new(&e.to_string()))?; - send!(client_data.tx, msg).await?; - client.client_data = None; - set_status("Connection timed out. Reload to reconnect"); - return Err(JsError::new("Connection timed out")); - } - - let maybe_msg: Option = match recv!(client_data.rx) { - Ok(r) => r, - Err(e) => { - return Err(JsError::new(e)) - } - }; - - if let Some(msg) = maybe_msg { - match msg { - MessageS2C::Goodbye(pkt) => { - info!("server sent disconnect: {:?}", pkt.reason); - client.client_data = None; - return Err(JsError::new("disconnected by server")); - } - MessageS2C::Chat(pkt) => { - info!("[CHAT] {}: {}", pkt.from, pkt.message); - - let window: Window = web_sys::window().expect("no global `window` exists"); - let document = window.document().expect("should have a document on window"); - let chatbox = document.get_element_by_id("chats").expect("chatbox does not exist"); - - let new_elem = document.create_element("div").expect("could not create element"); - - let msg_formatted = markdown::to_html(&format!("**[{}]** {}", pkt.from, pkt.message)); - - new_elem.set_inner_html(&msg_formatted); - - chatbox.append_child(&new_elem).unwrap(); - }, - MessageS2C::Pong(_) => { - client_data.pong_timeout = (js_sys::Date::now() as u64 / 1000) + PONG_MAX_TIMEOUT - }, - MessageS2C::PlanetData(pkt) => { - client.planets = pkt.planets; - }, - MessageS2C::PlayersUpdate(pkt) => { - let me = pkt.players.iter().find(|i| i.username == client_data.username); - if let Some(me) = me { - client.x = me.x as f64; - client.y = me.y as f64; - } - client.players = pkt.players; - } - _ => { - warn!("server sent unexpected packet {:?}, ignoring", msg); - } - } - } - - Ok(()) -} - -#[wasm_bindgen] -pub fn set_status(new_status: &str) { - let window: Window = web_sys::window().expect("no global `window` exists"); - let document = window.document().expect("should have a document on window"); - let status = document.get_element_by_id("status").expect("statusbox does not exist"); - status.set_inner_html(new_status); -} - -#[wasm_bindgen] -pub fn sleep(ms: i32) -> js_sys::Promise { - js_sys::Promise::new(&mut |resolve, _| { - web_sys::window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, ms) - .unwrap(); - }) -} - -pub async fn wait_for(promise: js_sys::Promise) -> JsFuture { - wasm_bindgen_futures::JsFuture::from(promise) -} - -#[wasm_bindgen] -pub fn version() -> u32 { - PROTOCOL_VERSION -} - -#[wasm_bindgen] -pub fn get_texture(texture_id: &str) -> Option { - let client = CLIENT.read().unwrap(); - if let Some(client_data) = &client.client_data { - client_data.textures.get_texture(texture_id) - } else { - None - } -} - -#[wasm_bindgen] -pub async fn render_frame(delta: f64) -> Result<(), JsError> { - let client = CLIENT.read().unwrap(); - if let Some(client_data) = &client.client_data { - Ok(client_data.renderer.render_frame(delta).await.map_err(|e| JsError::new(&format!("{}", e)))?) - } else { - Err(JsError::new("Client not yet initialized")) - } -} diff --git a/client/src/macros.rs b/client/src/macros.rs deleted file mode 100644 index 5eba8726c9b6c94606bf4b69f107e136412544df..0000000000000000000000000000000000000000 --- a/client/src/macros.rs +++ /dev/null @@ -1,64 +0,0 @@ -use ws_stream_wasm::WsMessage; - -#[macro_export] -macro_rules! send { - ($writer:expr,$pkt:expr) => { - $writer.send($crate::macros::__generic_packet_to_message($pkt)) - }; -} - -#[macro_export] -macro_rules! recv { - ($reader:expr) => { - { - if let Some(future_result) = $reader.next().now_or_never() { - if let Some(msg) = future_result { - if let WsMessage::Binary(msg) = msg { - match MessageS2C::try_from(msg.as_slice()) { - Ok(d) => Ok(Some(d)), - Err(e) => { - log::error!("error deserializing message: {}", e); - Ok(None) - } - } - } else { - Ok(None) - } - } else { - log::error!("pipe closed"); - Err("Pipe closed") - } - } else { - Ok(None) - } - } - } -} - -#[macro_export] -macro_rules! recv_now { - ($reader:expr) => { - { - if let Some(msg) = $reader.next().await { - if let WsMessage::Binary(msg) = msg { - match MessageS2C::try_from(msg.as_slice()) { - Ok(d) => Ok(Some(d)), - Err(e) => { - log::error!("error deserializing message: {}", e); - Ok(None) - } - } - } else { - Ok(None) - } - } else { - log::error!("pipe closed"); - Err("Pipe closed") - } - } - }; -} - -pub fn __generic_packet_to_message(pkt: Vec) -> WsMessage { - WsMessage::from(pkt) -} \ No newline at end of file diff --git a/client/src/rendering/mod.rs b/client/src/rendering/mod.rs deleted file mode 100644 index e54bda979a3c9ce2802fb1870f69d26859f53f3c..0000000000000000000000000000000000000000 --- a/client/src/rendering/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::error::Error; -use async_trait::async_trait; - -#[cfg(all(feature = "renderer-playercentric", feature = "renderer-canvascentric"))] -compile_error!("Mutually exclusive features renderer-playercentric and renderer-canvascentric selected"); -#[cfg(not(any(feature = "renderer-playercentric", feature = "renderer-canvascentric")))] -compile_error!("Required feature renderer not selected"); - -#[cfg(feature = "renderer-canvascentric")] -#[path = "renderer_canvascentric.rs"] -pub mod renderer; - -#[cfg(feature = "renderer-playercentric")] -#[path = "renderer_playercentric.rs"] -pub mod renderer; - -pub mod util; - -#[async_trait] -pub trait Renderer { - async fn get(canvas_element_id: &str) -> Result> where Self: Sized; - async fn render_frame(&self, time_delta_ms: f64) -> Result<(), Box>; -} \ No newline at end of file diff --git a/client/src/rendering/renderer_canvascentric.rs b/client/src/rendering/renderer_canvascentric.rs deleted file mode 100644 index 8183bcc7313ad678a656ad97b715269cdff5369d..0000000000000000000000000000000000000000 --- a/client/src/rendering/renderer_canvascentric.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::error::Error; -use async_trait::async_trait; -use log::debug; -use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, HtmlImageElement}; -use crate::rendering::Renderer; -use wasm_bindgen::{JsCast, JsValue}; -use crate::CLIENT; -use crate::rendering::util::texid_to_html_image_unchecked; -use crate::textures::TextureManager; - -#[derive(Debug)] -pub struct WebRenderer { - canvas_element_id: String -} - -pub const USERNAME_TEXT_ALIGN: &str = "center"; -pub const USERNAME_FONT: &str = "30px Segoe UI"; -pub const USERNAME_COLOR: &str = "white"; -pub const USERNAME_OFFSET_X: f64 = 0f64; -pub const USERNAME_OFFSET_Y: f64 = -35f64; - -pub const HEARTY_OFFSET_X: f64 = -25f64; -pub const HEARTY_OFFSET_Y: f64 = -25f64; -pub const HEARTY_WIDTH: f64 = 50f64; -pub const HEARTY_HEIGHT: f64 = 50f64; - -#[async_trait] -impl Renderer for WebRenderer { - async fn get(canvas_element_id: &str) -> Result> { - Ok(Self { - canvas_element_id: canvas_element_id.to_string() - }) - } - - async fn render_frame(&self, _time_delta_ms: f64) -> Result<(), Box> { - // TODO - core is working on this, please no touchy without telling him - // TODO - until this notice is removed - // time_delta_ms is the delta, in ms, from when the last render_frame was called by the browser - let window = web_sys::window().ok_or("window needs to exist")?; - let document = window.document().ok_or("window.document needs to exist")?; - let canvas_element = document.get_element_by_id(&self.canvas_element_id).ok_or("canvas element does not exist")?; - let typed_canvas_element: HtmlCanvasElement = canvas_element.dyn_into::().map_err(|_| ()).unwrap(); - let context = typed_canvas_element.get_context("2d").unwrap().unwrap().dyn_into::().unwrap(); - let client = CLIENT.read()?; - if client.client_data.is_none() { - return Err("client not yet initialized".into()); - } - let client_data = client.client_data.as_ref().unwrap(); - - context.set_transform(1f64, 0f64, 0f64, 1f64, 0f64, 0f64).map_err(|e: JsValue| e.as_string().unwrap())?; - context.clear_rect(0f64, 0f64, typed_canvas_element.width() as f64, typed_canvas_element.height() as f64); - - let hearty = texid_to_html_image_unchecked("hearty"); - - // draw players - for player in &client.players { - context.save(); // save current position - - // teleport to the player's location - context.translate(-player.x, -player.y).map_err(|e| e.as_string().unwrap())?; - - debug!("[render] PL: ({}, {}) {}", player.x, player.y, player.username); - - // draw username - context.set_text_align(USERNAME_TEXT_ALIGN); - context.set_font(USERNAME_FONT); - context.set_fill_style(&JsValue::from_str(USERNAME_COLOR)); // CssStyleColor - context.fill_text(&player.username, USERNAME_OFFSET_X, USERNAME_OFFSET_Y).map_err(|e: JsValue| e.as_string().unwrap())?; - - // rotate the canvas so we can draw hearty - context.rotate(player.rotation).map_err(|e| e.as_string().unwrap())?; - - // draw hearty - context.draw_image_with_html_image_element_and_dw_and_dh(&hearty, HEARTY_OFFSET_X, HEARTY_OFFSET_Y, HEARTY_WIDTH, HEARTY_HEIGHT).map_err(|e| e.as_string().unwrap())?; - - context.restore(); // return to canvas base - } - - // finally, translate to hearty - context.translate(-client.x + ((typed_canvas_element.width() / 2) as f64), -client.y + ((typed_canvas_element.height() / 2) as f64)).map_err(|e| e.as_string().unwrap())?; - -/* - context.begin_path(); - - // Draw the outer circle. - context - .arc(75.0, 75.0, 50.0, 0.0, std::f64::consts::PI * 2.0) - .unwrap(); - - // Draw the mouth. - context.move_to(110.0, 75.0); - context.arc(75.0, 75.0, 35.0, 0.0, std::f64::consts::PI).unwrap(); - - // Draw the left eye. - context.move_to(65.0, 65.0); - context - .arc(60.0, 65.0, 5.0, 0.0, std::f64::consts::PI * 2.0) - .unwrap(); - - // Draw the right eye. - context.move_to(95.0, 65.0); - context - .arc(90.0, 65.0, 5.0, 0.0, std::f64::consts::PI * 2.0) - .unwrap(); - - context.stroke(); -*/ - Ok(()) - } -} diff --git a/client/src/rendering/renderer_playercentric.rs b/client/src/rendering/renderer_playercentric.rs deleted file mode 100644 index 1969b928fb9bc9998cb8ac1bbc655d07ff4ae935..0000000000000000000000000000000000000000 --- a/client/src/rendering/renderer_playercentric.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::error::Error; -use async_trait::async_trait; -use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, HtmlImageElement}; -use crate::rendering::Renderer; -use wasm_bindgen::{JsCast, JsValue}; -use crate::CLIENT; - -// TODO: Remove all the f32s - -pub const STARFIELD_RENDER_SCALE: f64 = 1.0; - -#[derive(Debug)] -pub struct WebRenderer { - canvas_element_id: String -} - -#[async_trait] -impl Renderer for WebRenderer { - async fn get(canvas_element_id: &str) -> Result> { - Ok(Self { - canvas_element_id: canvas_element_id.to_string() - }) - } - - async fn render_frame(&self, _time_delta_ms: f64) -> Result<(), Box> { - // TODO - terra is working on this, please no touchy without telling him - // TODO - until this notice is removed - // time_delta_ms is the delta, in ms, from when the last render_frame was called by the browser - let window = web_sys::window().ok_or("window needs to exist")?; - let document = window.document().ok_or("window.document needs to exist")?; - let canvas_element = document.get_element_by_id(&self.canvas_element_id).ok_or("canvas element does not exist")?; - let typed_canvas_element: HtmlCanvasElement = canvas_element.dyn_into::().map_err(|_| ()).unwrap(); - let context = typed_canvas_element.get_context("2d").unwrap().unwrap().dyn_into::().unwrap(); - let client = CLIENT.read()?; - if client.client_data.is_none() { - return Err("client not yet initialized".into()); - } - let _client_data = client.client_data.as_ref().unwrap(); - - //let camera_translate_x = -client.x + (typed_canvas_element.width() / 2) as f64; - let viewer_size_x = typed_canvas_element.width() as f64; - //let camera_translate_y = -client.y + (typed_canvas_element.height() / 2) as f64; - let viewer_size_y = typed_canvas_element.height() as f64; - - typed_canvas_element.style().set_property("background-position", &format!("{}px {}px", -client.x / STARFIELD_RENDER_SCALE, -client.y / STARFIELD_RENDER_SCALE)).map_err(|e| e.as_string().unwrap())?; - - context.set_transform(1f64, 0f64, 0f64, 1f64, 0f64, 0f64).map_err(|e: JsValue| e.as_string().unwrap())?; - context.clear_rect(0f64, 0f64, viewer_size_x, viewer_size_y); - - // *dont* translate the camera. we're movign everything else around us. cameracentrism. - // only translation will be to center our core module. - //context.translate(camera_translate_x, camera_translate_y).map_err(|e: JsValue| e.as_string().unwrap())?; - context.translate(viewer_size_x / 2.0, viewer_size_y / 2.0).map_err(|e: JsValue| e.as_string().unwrap())?; - - for planet in &client.planets { - //context.save(); - - //context.set_transform(1f64, 0f64, 0f64, 1f64, 0f64, 0f64).map_err(|e: JsValue| e.as_string().unwrap())?; - //context.translate(-planet.x, -planet.y).map_err(|e: JsValue| e.as_string().unwrap())?; - - let texture_image = document.get_element_by_id(&format!("tex-{}", planet.planet_type.unwrap().as_texture_id())).unwrap().dyn_into::().unwrap(); - // pos: - //debug!("P {} {}", planet.x - planet.radius - client.x, planet.y - planet.radius - client.y); - context.draw_image_with_html_image_element_and_dw_and_dh(&texture_image, (planet.x - planet.radius - client.x as f32) as f64, (planet.y - planet.radius - client.y as f32) as f64, planet.radius as f64 * 2f64, planet.radius as f64 * 2f64).map_err(|e: JsValue| e.as_string().unwrap())?; - - //context.restore(); - } - - for player in &client.players { - context.save(); - - //context.translate(player.x, player.y).map_err(|e: JsValue| e.as_string().unwrap())?; - //gaah fuck why noo i didnt want this. godforsaken canvas rotation - context.translate(player.x as f64 - client.x, player.y as f64 - client.y).map_err(|e: JsValue| e.as_string().unwrap())?; // fwip - - context.set_text_align("center"); - context.set_font("30px Segoe UI"); - context.set_fill_style(&JsValue::from_str("white")); // CssStyleColor - context.fill_text(&player.username, 0f64, -35f64).map_err(|e: JsValue| e.as_string().unwrap())?; - - context.rotate(player.rotation as f64).map_err(|e: JsValue| e.as_string().unwrap())?; // fwip - - let texture_image = document.get_element_by_id("tex-hearty").unwrap().dyn_into::().unwrap(); - //context.draw_image_with_html_image_element_and_dw_and_dh(&texture_image, player.x - 25f64 - client.x, player.y - 25f64 - client.y, 50f64, 50f64).map_err(|e: JsValue| e.as_string().unwrap())?; - context.draw_image_with_html_image_element_and_dw_and_dh(&texture_image, -25f64, -25f64, 50f64, 50f64).map_err(|e: JsValue| e.as_string().unwrap())?; // sktch - - //context.rotate(-player.rotation).map_err(|e: JsValue| e.as_string().unwrap())?; // fwoop - - context.restore(); - } - -/* - context.begin_path(); - - // Draw the outer circle. - context - .arc(75.0, 75.0, 50.0, 0.0, std::f64::consts::PI * 2.0) - .unwrap(); - - // Draw the mouth. - context.move_to(110.0, 75.0); - context.arc(75.0, 75.0, 35.0, 0.0, std::f64::consts::PI).unwrap(); - - // Draw the left eye. - context.move_to(65.0, 65.0); - context - .arc(60.0, 65.0, 5.0, 0.0, std::f64::consts::PI * 2.0) - .unwrap(); - - // Draw the right eye. - context.move_to(95.0, 65.0); - context - .arc(90.0, 65.0, 5.0, 0.0, std::f64::consts::PI * 2.0) - .unwrap(); - - context.stroke(); -*/ - Ok(()) - } -} diff --git a/client/src/rendering/util.rs b/client/src/rendering/util.rs deleted file mode 100644 index a6864cee49d6bb7037e814cad56c2bb303334f15..0000000000000000000000000000000000000000 --- a/client/src/rendering/util.rs +++ /dev/null @@ -1,8 +0,0 @@ -use web_sys::HtmlImageElement; -use wasm_bindgen::JsCast; - -pub fn texid_to_html_image_unchecked(tex: &str) -> HtmlImageElement { - let window = web_sys::window().expect("window needs to exist"); - let document = window.document().expect("window.document needs to exist"); - document.get_element_by_id(&format!("tex-{}", tex)).unwrap().dyn_into::().unwrap() -} \ No newline at end of file diff --git a/client/src/textures/loader_fast.rs b/client/src/textures/loader_fast.rs deleted file mode 100644 index 2dd3e4ce278bacc016665eefbf8810e1a1e83631..0000000000000000000000000000000000000000 --- a/client/src/textures/loader_fast.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::collections::HashMap; -use std::error::Error; -use std::io::Cursor; -use base64::Engine; -use image::ImageOutputFormat; -use log::debug; -use serde::{Deserialize, Serialize}; -use crate::textures::{TextureManager, TextureSize}; - -pub const SPRITESHEET_IMAGE_FILE_FULL: &[u8] = include_bytes!("../../../assets/dist/spritesheet-full.png"); -pub const SPRITESHEET_DATA_FILE_FULL: &str = include_str!("../../../assets/dist/spritesheet-full.ron"); - -pub const SPRITESHEET_IMAGE_FILE_375: &[u8] = include_bytes!("../../../assets/dist/spritesheet-375.png"); -pub const SPRITESHEET_DATA_FILE_375: &str = include_str!("../../../assets/dist/spritesheet-375.ron"); - -pub const SPRITESHEET_IMAGE_FILE_125: &[u8] = include_bytes!("../../../assets/dist/spritesheet-125.png"); -pub const SPRITESHEET_DATA_FILE_125: &str = include_str!("../../../assets/dist/spritesheet-125.ron"); - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SpritePosition { - pub name: String, - pub x: f32, - pub y: f32, - pub width: f32, - pub height: f32, - pub offsets: Option<[f32; 2]>, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SerializedSpriteSheet { - pub texture_width: f32, - pub texture_height: f32, - pub sprites: Vec, -} - -#[derive(Debug)] -pub struct TextureLoader { - pub sprites: HashMap -} -impl TextureManager for TextureLoader { - fn load(size: TextureSize) -> Result> where Self: Sized { - debug!("Loading textures - starting fast texture loader (size: {})", size.to_string()); - let start = js_sys::Date::now() as u64; - // load the generated spritesheet data - let spritesheet_data: SerializedSpriteSheet = ron::from_str(pick_data_file(size))?; - - // load the generated spritesheet image - let spritesheet_image = image::load_from_memory(pick_image_file(size))?; - - if spritesheet_image.width() as f32 != spritesheet_data.texture_width { - return Err("Image width mismatch between spritesheet and data file".into()); - } - if spritesheet_image.height() as f32 != spritesheet_data.texture_height { - return Err("Image height mismatch between spritesheet and data file".into()); - } - - let mut sprites = HashMap::new(); - - for sprite in spritesheet_data.sprites { - debug!("Loading texture {} ({}x{}, start at {}, {})", sprite.name, sprite.width, sprite.height, sprite.x, sprite.y); - let sprite_img = spritesheet_image.crop_imm(sprite.x as u32, sprite.y as u32, sprite.width as u32, sprite.height as u32); - let mut image_data: Vec = Vec::new(); - sprite_img.write_to(&mut Cursor::new(&mut image_data), ImageOutputFormat::Png) - .unwrap(); - let res_base64 = base64::engine::general_purpose::STANDARD.encode(image_data); - sprites.insert(sprite.name, format!("data:image/png;base64,{}", res_base64)); - } - - let end = js_sys::Date::now() as u64; - debug!("Loaded {} sprites from spritesheet in {} ms", sprites.len(), end - start); - - Ok(Self { - sprites, - }) - } - - fn get_texture(&self, texture_id: &str) -> Option { - self.sprites.get(texture_id).map(|u| u.clone()) - } -} - -fn pick_data_file(for_size: TextureSize) -> &'static str { - match for_size { - TextureSize::Full => SPRITESHEET_DATA_FILE_FULL, - TextureSize::Scaled375 => SPRITESHEET_DATA_FILE_375, - TextureSize::Scaled125 => SPRITESHEET_DATA_FILE_125 - } -} - -fn pick_image_file(for_size: TextureSize) -> &'static [u8] { - match for_size { - TextureSize::Full => SPRITESHEET_IMAGE_FILE_FULL, - TextureSize::Scaled375 => SPRITESHEET_IMAGE_FILE_375, - TextureSize::Scaled125 => SPRITESHEET_IMAGE_FILE_125 - } -} \ No newline at end of file diff --git a/client/src/textures/loader_slow.rs b/client/src/textures/loader_slow.rs deleted file mode 100644 index f15eaae4f0682cf604f37c1f8e69ebee4e7ab368..0000000000000000000000000000000000000000 --- a/client/src/textures/loader_slow.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::textures::{TextureManager, TextureSize}; -use std::error::Error; -use log::debug; - -#[derive(Debug)] -pub struct TextureLoader { - size: TextureSize -} -impl TextureManager for TextureLoader { - fn load(size: TextureSize) -> Result> where Self: Sized { - debug!("Using slow texture loader, textures will be loaded on-the-fly"); - Ok(TextureLoader { - size - }) - } - - fn get_texture(&self, texture_id: &str) -> Option { - Some(format!("/assets/final/{}/{}.png", self.size.to_string(), texture_id)) - } -} \ No newline at end of file diff --git a/client/src/textures/mod.rs b/client/src/textures/mod.rs deleted file mode 100644 index dfcb5ede664076305e5e6c49ef361e57b93375ac..0000000000000000000000000000000000000000 --- a/client/src/textures/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::error::Error; -use std::str::FromStr; - -#[cfg(all(feature = "textures-fast", feature = "textures-slow"))] -compile_error!("Mutually exclusive modules textures-fast and textures-slow selected."); -#[cfg(not(any(feature = "textures-fast", feature = "textures-slow")))] -compile_error!("Required feature textures not specified. Please specify one of textures-fast, textures-slow"); - -#[cfg(feature = "textures-fast")] -#[path = "loader_fast.rs"] -pub mod loader; - -#[cfg(feature = "textures-slow")] -#[path = "loader_slow.rs"] -pub mod loader; - -pub trait TextureManager { - fn load(size: TextureSize) -> Result> where Self: Sized; - fn get_texture(&self, texture_id: &str) -> Option; -} - -#[derive(Debug, Copy, Clone)] -pub enum TextureSize { - Full, - Scaled375, - Scaled125 -} -impl ToString for TextureSize { - fn to_string(&self) -> String { - match self { - TextureSize::Full => "full".to_string(), - TextureSize::Scaled375 => "375".to_string(), - TextureSize::Scaled125 => "125".to_string() - } - } -} -impl FromStr for TextureSize { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "full" => Ok(TextureSize::Full), - "375" => Ok(TextureSize::Scaled375), - "125" => Ok(TextureSize::Scaled125), - _ => Err(()) - } - } -} \ No newline at end of file