M client/src/rendering/renderer.rs => client/src/rendering/renderer.rs +39 -1
@@ 1,9 1,11 @@
use std::error::Error;
use async_trait::async_trait;
-use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
+use log::debug;
+use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, HtmlImageElement};
use crate::rendering::Renderer;
use wasm_bindgen::{JsCast, JsValue};
use crate::CLIENT;
+use crate::textures::TextureManager;
#[derive(Debug)]
pub struct WebRenderer {
@@ 28,6 30,10 @@ impl Renderer for WebRenderer {
let typed_canvas_element: HtmlCanvasElement = canvas_element.dyn_into::<web_sys::HtmlCanvasElement>().map_err(|_| ()).unwrap();
let context = typed_canvas_element.get_context("2d").unwrap().unwrap().dyn_into::<CanvasRenderingContext2d>().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);
@@ 35,8 41,40 @@ impl Renderer for WebRenderer {
let camera_translate_x = -client.x + (typed_canvas_element.width() / 2) as f64;
let camera_translate_y = -client.y + (typed_canvas_element.height() / 2) as f64;
+ debug!("translating to {} {}", camera_translate_x, camera_translate_y);
+
context.translate(camera_translate_x, camera_translate_y).map_err(|e: JsValue| e.as_string().unwrap())?;
+ for planet in &client.planets {
+ let texture_image = document.get_element_by_id(&format!("tex-{}", planet.planet_type.as_texture_id())).unwrap().dyn_into::<HtmlImageElement>().unwrap();
+ context.draw_image_with_html_image_element_and_dw_and_dh(&texture_image, 95f64, 65f64, planet.radius*2f64, planet.radius*2f64).map_err(|e: JsValue| 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(())
}
}=
\ No newline at end of file
M client/src/textures/loader_slow.rs => client/src/textures/loader_slow.rs +1 -1
@@ 15,6 15,6 @@ impl TextureManager for TextureLoader {
}
fn get_texture(&self, texture_id: &str) -> Option<String> {
- Some(format!("/../assets/final/{}/{}.png", self.size.to_string(), texture_id))
+ Some(format!("/assets/final/{}/{}.png", self.size.to_string(), texture_id))
}
}=
\ No newline at end of file
M protocol/src/lib.rs => protocol/src/lib.rs +8 -0
@@ 79,6 79,14 @@ pub enum PlanetType {
Earth
}
+impl PlanetType {
+ pub fn as_texture_id(&self) -> String {
+ match self {
+ PlanetType::Earth => "earth".to_string()
+ }
+ }
+}
+
pub fn pc2s(pkt: &MessageC2S) -> Vec<u8> {
rmp_serde::to_vec(pkt).unwrap()
}
M web/play.html => web/play.html +107 -83
@@ 6,95 6,119 @@
<meta charset="utf-8">
</head>
- <body>
- <div class="chatbox">
- <div id="chats">
+<body>
+<div class="chatbox">
+ <div id="chats">
+
+ </div>
+ <input id="chat-value" type="text" placeholder="chat text goes here"/>
+ <button id="chat-submit">submit</button>
+ <p id="status">Loading WASM module...</p>
+
+ <div id="textures" style="display: none;">
+
+ </div>
+</div>
+
+<canvas style="width: 100%; height: 100%; background-color: forestgreen;" id="canvas"></canvas>
+
+<script type="module">
+ // If you're getting build errors here | you need to run `just build_client_bundle` first, to compile client code
+ // v
+ import init, {
+ rust_init,
+ send_chat,
+ update_socket,
+ set_status,
+ get_texture,
+ render_frame,
+ send_ping_pong
+ } from "./dist/starkingdoms_client.js";
+
+ init().then(() => {
+ const urlSearchParams = new URLSearchParams(window.location.search);
+
+ if (!(urlSearchParams.has("server") || urlSearchParams.has("username") || urlSearchParams.has("textures"))) {
+ window.location.href = "/index.html";
+ }
+
+ rust_init(urlSearchParams.get("server"), urlSearchParams.get("username"), urlSearchParams.get("textures")).then(() => {
+ document.getElementById("chat-submit").addEventListener("click", e => {
+ send_chat(document.getElementById("chat-value").value);
+ });
+
+ let interval_id;
+ let interval_id2;
+
+ interval_id = setInterval(() => {
+ update_socket().catch((e) => {
+ clearInterval(interval_id);
+ clearInterval(interval_id2);
+ set_status("There was an error. Reload the page to reconnect.")
+ throw e;
+ });
+ }, 5);
+
+ interval_id2 = setInterval(() => {
+ send_ping_pong().catch((e) => {
+ clearInterval(interval_id2);
+ clearInterval(interval_id);
+ set_status("There was an error. Reload the page to reconnect.")
+ throw e;
+ });
+ }, 5);
+
+ let start;
- </div>
- <input id="chat-value" type="text" placeholder="chat text goes here" />
- <button id="chat-submit">submit</button>
- <p id="status">Loading WASM module...</p>
+ let textures = ["autoplr_cfg", "autoplr_error", "autoplr_on", "cargo_off", "cargo_on", "earth", "ecothruster_on", "hearty", "hub_off", "hub_on", "landingleg", "landingthruster_off", "landingthruster_on", "powerhub_off", "powerhub_on", "superthruster_off", "superthruster_on", "thruster_off", "thruster_on"];
- <div id="textures">
+ for (let i = 0; i < textures.length; i++) {
+ let texture = textures[i];
- </div>
- </div>
+ let fieldset_elem = document.createElement("fieldset");
+ fieldset_elem.style = "width: min-content;";
+ fieldset_elem.classList.add("texturebox")
+ let legend_elem = document.createElement("legend");
+ legend_elem.innerText = texture;
- <canvas style="width: 100%; height: 100%" id="canvas"></canvas>
+ let img_elem = document.createElement("img");
+ img_elem.src = get_texture(texture);
+ img_elem.id = "tex-" + texture;
- <script type="module">
- // If you're getting build errors here | you need to run `just build_client_bundle` first, to compile client code
- // v
- import init, { rust_init, send_chat, update_socket, set_status, get_texture, render_frame, send_ping_pong } from "./dist/starkingdoms_client.js";
- init().then(() => {
- const urlSearchParams = new URLSearchParams(window.location.search);
+ fieldset_elem.appendChild(legend_elem);
+ fieldset_elem.appendChild(img_elem);
+ document.getElementById("textures").appendChild(fieldset_elem);
+ }
+ if (urlSearchParams.has("showTextures")) {
+ document.getElementById("textures").style = "";
+ }
- if (!(urlSearchParams.has("server") || urlSearchParams.has("username") || urlSearchParams.has("textures"))) {
- window.location.href = "/index.html";
+ // Textures must be fully loaded (above) before rendering can start
+ // They are all put on the DOM, in a hidden element, so they arent visible to the user unless showTextures=1
+ // but they need to have been loaded for the canvas to render them
+
+ function animateFrame(time) {
+ if (start === undefined) {
+ start = time;
}
+ let delta = time - start;
- rust_init(urlSearchParams.get("server"), urlSearchParams.get("username"), urlSearchParams.get("textures")).then(() => {
- document.getElementById("chat-submit").addEventListener("click", e => {
- send_chat(document.getElementById("chat-value").value);
- });
-
- let interval_id;
- let interval_id2;
-
- interval_id = setInterval(() => {
- update_socket().catch((e) => {
- clearInterval(interval_id);
- clearInterval(interval_id2);
- set_status("There was an error. Reload the page to reconnect.")
- throw e;
- });
- }, 5);
-
- interval_id2 = setInterval(() => {
- send_ping_pong().catch((e) => {
- clearInterval(interval_id2);
- clearInterval(interval_id);
- set_status("There was an error. Reload the page to reconnect.")
- throw e;
- });
- }, 5);
-
- let start;
- function animateFrame(time) {
- if (start === undefined) {
- start = time;
- }
- let delta = time - start;
-
- render_frame(delta);
- start = time;
- //requestAnimationFrame(animateFrame)
- }
-
- //requestAnimationFrame(animateFrame);
-
- if (urlSearchParams.has("showTextures")) {
- let textures = ["autoplr_cfg", "autoplr_error", "autoplr_on", "cargo_off", "cargo_on", "earth", "ecothruster_on", "hearty", "hub_off", "hub_on", "landingleg", "landingthruster_off", "landingthruster_on", "powerhub_off", "powerhub_on", "superthruster_off", "superthruster_on", "thruster_off", "thruster_on"];
-
- for (let i = 0; i < textures.length; i++) {
- let texture = textures[i];
-
- let fieldset_elem = document.createElement("fieldset");
- fieldset_elem.style = "width: min-content;";
- fieldset_elem.classList.add("texturebox")
- let legend_elem = document.createElement("legend");
- legend_elem.innerText = texture;
-
- let img_elem = document.createElement("img");
- img_elem.src = get_texture(texture);
-
- fieldset_elem.appendChild(legend_elem);
- fieldset_elem.appendChild(img_elem);
- document.body.appendChild(fieldset_elem);
- }
- }
- });
- })
- </script>
- </body>
+ try {
+ render_frame(delta);
+ } catch (e) {
+ console.error("error in renderFrame: "+e);
+ return;
+ }
+ start = time;
+
+ document.getElementById("canvas").getContext("2d").drawImage(document.getElementById("tex-earth"), 0, 0, 150 -2025, 2000, 2000);
+
+ requestAnimationFrame(animateFrame);
+ }
+
+ requestAnimationFrame(animateFrame);
+ });
+ })
+</script>
+</body>
</html>