M client/Cargo.toml => client/Cargo.toml +4 -2
@@ 54,6 54,8 @@ features = [
]
[features]
-default = ['textures-slow']
textures-slow = []
-textures-fast = ['image', 'ron', 'base64']>
\ No newline at end of file
+textures-fast = ['image', 'ron', 'base64']
+
+renderer-canvascentric = []
+renderer-playercentric = []<
\ No newline at end of file
M client/src/rendering/mod.rs => client/src/rendering/mod.rs +13 -0
@@ 1,8 1,21 @@
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<Self, Box<dyn Error>> where Self: Sized;
A client/src/rendering/renderer_canvascentric.rs => client/src/rendering/renderer_canvascentric.rs +110 -0
@@ 0,0 1,110 @@
+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<Self, Box<dyn Error>> {
+ Ok(Self {
+ canvas_element_id: canvas_element_id.to_string()
+ })
+ }
+
+ async fn render_frame(&self, _time_delta_ms: f64) -> Result<(), Box<dyn Error>> {
+ // 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::<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);
+
+ 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(())
+ }
+}
R client/src/rendering/renderer.rs => client/src/rendering/renderer_playercentric.rs +1 -1
@@ 21,7 21,7 @@ impl Renderer for WebRenderer {
}
async fn render_frame(&self, _time_delta_ms: f64) -> Result<(), Box<dyn Error>> {
- // TODO - core is working on this, please no touchy without telling him
+ // 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")?;
A client/src/rendering/util.rs => client/src/rendering/util.rs +8 -0
@@ 0,0 1,8 @@
+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::<HtmlImageElement>().unwrap()
+}<
\ No newline at end of file
M client/src/textures/mod.rs => client/src/textures/mod.rs +2 -2
@@ 2,9 2,9 @@ use std::error::Error;
use std::str::FromStr;
#[cfg(all(feature = "textures-fast", feature = "textures-slow"))]
-compile_error!("You cannot use both texture loaders. Please only enable one of the textures-fast or textures-slow feature.");
+compile_error!("Mutually exclusive modules textures-fast and textures-slow selected.");
#[cfg(not(any(feature = "textures-fast", feature = "textures-slow")))]
-compile_error!("You need to enable a texture loader. Please enable one of the textures-fast, textures-slow feature.");
+compile_error!("Required feature textures not specified. Please specify one of textures-fast, textures-slow");
#[cfg(feature = "textures-fast")]
#[path = "loader_fast.rs"]
M server/src/planet.rs => server/src/planet.rs +2 -1
@@ 4,7 4,8 @@ use starkingdoms_protocol::{PlanetType, ProtocolPlanet};
use crate::{SCALE, manager::ClientHandlerMessage};
-const GRAVITY: f64 = 0.001;
+//const GRAVITY: f64 = 0.001;
+const GRAVITY: f64 = 0.000006674;
#[derive(Clone)]
pub struct Planet {
M spacetime => spacetime +12 -10
@@ 4,11 4,13 @@ set -e
SCRIPT_PATH=$(readlink -f "${BASH_SOURCE:-$0}")
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
+CLIENT_MODS=${STK_CLIENT_MODULES:-"textures-slow renderer-playercentric"}
+SERVER_MODS=${STK_SERVER_MODULES:=""}
exec_spacetime() {
- # args: target, environment, build root, verbose?
+ # args: target, environment, build root, modules
echo "[*] Running configure command: 'python3 $SCRIPT_DIR/spacetime_py/spacetime.py $1 $2 $SCRIPT_DIR $SPACETIME_VERBOSE'"
- python3 "$SCRIPT_DIR/spacetime_py/spacetime.py" "$1" "$2" "$SCRIPT_DIR" "$SPACETIME_VERBOSE"
+ python3 "$SCRIPT_DIR/spacetime_py/spacetime.py" "$1" "$2" "$SCRIPT_DIR" "$SPACETIME_VERBOSE" "$4"
}
exec_ninja() {
@@ 79,50 81,50 @@ sub_install_tooling() {
sub_build_client_bundle() {
check_all
- exec_spacetime client dev "$SCRIPT_DIR"
+ exec_spacetime client dev "$SCRIPT_DIR" "$CLIENT_MODS"
exec_ninja client
}
sub_run_http() {
check_all
- exec_spacetime client dev "$SCRIPT_DIR"
+ exec_spacetime client dev "$SCRIPT_DIR" "$CLIENT_MODS"
exec_ninja client
cd web && python3 -m http.server
}
sub_build_client_bundle_prod() {
check_all
- exec_spacetime client prod "$SCRIPT_DIR"
+ exec_spacetime client prod "$SCRIPT_DIR" "$CLIENT_MODS"
exec_ninja client
}
sub_run_http_prod() {
check_all
- exec_spacetime client prod "$SCRIPT_DIR"
+ exec_spacetime client prod "$SCRIPT_DIR" "$CLIENT_MODS"
exec_ninja client
cd web && python3 -m http.server
}
sub_build_server() {
check_all
- exec_spacetime server dev "$SCRIPT_DIR"
+ exec_spacetime server dev "$SCRIPT_DIR" "$SERVER_MODS"
exec_ninja server
}
sub_run_server() {
check_all
- exec_spacetime server dev "$SCRIPT_DIR"
+ exec_spacetime server dev "$SCRIPT_DIR" "$SERVER_MODS"
exec_ninja server
exec "$SCRIPT_DIR/target/debug/starkingdoms-server"
}
sub_build_server_prod() {
check_all
- exec_spacetime server prod "$SCRIPT_DIR"
+ exec_spacetime server prod "$SCRIPT_DIR" "$SERVER_MODS"
exec_ninja server
}
sub_run_server_prod() {
check_all
- exec_spacetime server prod "$SCRIPT_DIR"
+ exec_spacetime server prod "$SCRIPT_DIR" "$SERVER_MODS"
exec_ninja server
exec "$SCRIPT_DIR/target/release/starkingdoms-server"
}
M spacetime_py/spacetime.py => spacetime_py/spacetime.py +13 -9
@@ 58,13 58,13 @@ def gen_inkscape_rules_for_asset(root, asset, writer, files_375, files_full, fil
writer.build([out_125], rule_125, [in_file])
-def gen_rules_for_client(root, env, writer):
+def gen_rules_for_client(root, env, writer, modules):
if env == 'dev':
- writer.rule('cargo-client', 'wasm-pack build --target web client',
+ writer.rule('cargo-client', f'wasm-pack build --target web client --features "{modules}"',
depfile=f'{root}/target/wasm32-unknown-unknown/release/starkingdoms_client.d', pool='console')
elif env == 'prod':
writer.rule('cargo-client',
- 'wasm-pack build --target web client --no-default-features --features textures-fast',
+ f'wasm-pack build --target web client --features "{modules}"',
depfile=f'{root}/target/wasm32-unknown-unknown/release/starkingdoms_client.d', pool='console')
writer.build(
[
@@ 115,14 115,14 @@ def gen_rules_for_client(root, env, writer):
writer.build(['client'], 'phony', [f'{root}/web/dist/starkingdoms_client.js'])
-def gen_rules_for_server(root, env, writer):
+def gen_rules_for_server(root, env, writer, modules):
if env == 'dev':
out_dir = 'debug'
- writer.rule('cargo-server', 'cargo build --bin starkingdoms-server',
+ writer.rule('cargo-server', f'cargo build --bin starkingdoms-server --features "{modules}"',
depfile=f'{root}/target/debug/starkingdoms-server.d', pool='console')
elif env == 'prod':
out_dir = 'release'
- writer.rule('cargo-server', 'cargo build --bin starkingdoms-server --release',
+ writer.rule('cargo-server', f'cargo build --bin starkingdoms-server --release --features "{modules}"',
depfile=f'{root}/target/release/starkingdoms-server.d', pool='console')
writer.build([f'{root}/target/{out_dir}/starkingdoms-server'], 'cargo-server', ['server/Cargo.toml'])
@@ 172,13 172,17 @@ def main():
target = sys.argv[1]
env = sys.argv[2]
root = sys.argv[3]
+ if len(sys.argv) > 5:
+ modules = sys.argv[5]
+ else:
+ modules = ""
verbose = False
if len(sys.argv) > 4:
if sys.argv[4] == '-v':
verbose = True
- print(f'[spacetime] Configuring ninja for PRIMARY_TARGET={target} with ENV={env}, BUILDROOT={root}')
+ print(f'[spacetime] Configuring ninja for PRIMARY_TARGET={target} with ENV={env}, BUILDROOT={root}, MODULES={modules}')
with open(f'{root}/build.ninja', 'w') as f:
writer = Writer(f)
@@ 193,9 197,9 @@ def main():
generate_assets_build_command(root, assets, writer)
if target == 'client':
- gen_rules_for_client(root, env, writer)
+ gen_rules_for_client(root, env, writer, modules)
elif target == 'server':
- gen_rules_for_server(root, env, writer)
+ gen_rules_for_server(root, env, writer, modules)
print(f'[spacetime] Configured build')