~starkingdoms/starkingdoms

63975cc0a233df1da0d741ce5e246b08059d20e4 — c0repwn3r 2 years ago a914780
extend module system in client
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')