diff --git a/assets/web/index.html b/assets/web/index.html index ce2730e..943f8ea 100644 --- a/assets/web/index.html +++ b/assets/web/index.html @@ -8,6 +8,7 @@ var mapScale = 1.0; var mapOffsetX = 0.0; var mapOffsetY = 0.0; + var draggedToken = { token: null, offX: 0, offY: 0 }; function init() { let view = document.getElementById('game-view'); @@ -15,6 +16,7 @@ view.onclick = (e) => console.log('click', e); view.onauxclick = (e) => console.log(e); view.onmousemove = onGameMouseMove; + view.onmouseup = onGameMouseUp; view.oncontextmenu = () => false; // allow sending chat message using enter (and shift-enter for new line) document.getElementById('newmsg-content').onkeypress = (e) => { @@ -95,13 +97,20 @@ console.log(t); let map = document.getElementById('map'); let token = document.createElement('div'); - token.className = 'token'; + token.className = 'token token-transition'; token.style.top = `${t.y * GRID_SIZE}px`; token.style.left = `${t.x * GRID_SIZE}px`; token.token_id = t.token_id; token.innerHTML = ` - + ` + token.onmousedown = (e) => { + token.classList.remove('token-transition'); + draggedToken.token = token; + draggedToken.offX = ((e.clientX - mapOffsetX) / mapScale) - parseInt(token.style.left); + draggedToken.offY = ((e.clientY - mapOffsetY) / mapScale) - parseInt(token.style.top); + token.children[0].style.cursor = 'grabbing'; + } map.append(token); } tavern.onmovetoken = (m) => { @@ -136,6 +145,25 @@ map.style.left = `${mapOffsetX}px`; map.style.top = `${mapOffsetY}px`; } + else if(draggedToken.token != null && event.buttons == 1) { + let top = (event.clientY - mapOffsetY) / mapScale - draggedToken.offY; + let left = (event.clientX - mapOffsetX) / mapScale - draggedToken.offX; + console.log(event.clientX, event.clientY, draggedToken.offX, draggedToken.offY); + draggedToken.token.style.top = `${top}px`; + draggedToken.token.style.left = `${left}px`; + } + } + function onGameMouseUp() { + if(draggedToken.token != null) { + let t = draggedToken.token; + let x = Math.floor(0.5 + parseInt(t.style.left) / GRID_SIZE); + let y = Math.floor(0.5 + parseInt(t.style.top) / GRID_SIZE); + let id = t.token_id; + t.classList.add('token-transition'); + t.children[0].style.cursor = ''; + tavern.move_token(id, x, y); + draggedToken.token = null; + } } function sendChatMessage() { let tb = document.getElementById('newmsg-content'); @@ -209,9 +237,11 @@ } .token { position: absolute; + } + .token-transition { transition: - top 0.5s ease-in, - left 0.5s ease-in; + top 0.5s ease-in, + left 0.5s ease-in; } .token img { cursor: grab; @@ -248,7 +278,7 @@
floating
stuff
-
+
diff --git a/src/api/game_actions.rs b/src/api/game_actions.rs index d6417c4..ebcf9b4 100644 --- a/src/api/game_actions.rs +++ b/src/api/game_actions.rs @@ -15,4 +15,21 @@ pub struct Ping { pub struct ShowImage { /// Which texture to show pub texture: String +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct SpawnToken { + pub token_id: usize, + pub x: i32, + pub y: i32, + pub img: String +} +impl std::fmt::Debug for SpawnToken { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SpawnToken") + .field("token_id", &self.token_id) + .field("x", &self.x) + .field("y", &self.y) + .finish() + } } \ No newline at end of file diff --git a/src/api/login.rs b/src/api/login.rs index f7a28b7..beb702a 100644 --- a/src/api/login.rs +++ b/src/api/login.rs @@ -6,7 +6,7 @@ pub struct LoginRequest { pub password: String, } -#[derive(Serialize, Clone)] +#[derive(Serialize, Clone, Debug)] pub struct LoginResult { pub success: bool, // TODO: Figure out what the user needs on successful login to reduce traffic diff --git a/src/api/mod.rs b/src/api/mod.rs index 2933afe..776b1a0 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -2,6 +2,7 @@ pub mod login; pub mod game_actions; pub mod map_actions; +use game_actions::SpawnToken; use serde::{Deserialize, Serialize}; use crate::game::chat_message::ChatMessage; @@ -22,7 +23,7 @@ pub enum Request { Kick(String), Shutdown } -#[derive(Serialize, Clone)] +#[derive(Serialize, Clone, Debug)] #[serde(rename_all = "snake_case")] pub enum Response { Error(RequestError), @@ -30,7 +31,7 @@ pub enum Response { Message(ChatMessage), GetChatHistory(Vec), MoveToken { token_id: usize, x: i32, y: i32 }, - SpawnToken { token_id: usize, x: i32, y: i32, img: String }, + SpawnToken(SpawnToken), Quit { id: String }, Shutdown, diff --git a/src/lib.rs b/src/lib.rs index ca90497..2992d57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +use api::game_actions::SpawnToken; use game::{chat_message::ChatMessage, Game, GameImpl}; use tokio::sync::{broadcast, mpsc}; @@ -87,7 +88,7 @@ impl GameServer { for (i, (path, x, y)) in self.tokens.iter().enumerate() { let bits = std::fs::read(path).expect("FAILED READING TOKEN IMAGE"); let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits); - _ = broadcast.send((Some(id.clone()), api::Response::SpawnToken { token_id: i, x: *x, y: *y, img })); + _ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id: i, x: *x, y: *y, img }))); } }, api::Request::SpawnToken { x, y, img_path } => { @@ -95,11 +96,15 @@ impl GameServer { self.tokens.push((img_path.clone(), x, y)); let bits = std::fs::read(img_path).expect("FAILED READING TOKEN IMAGE"); let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits); - _ = broadcast.send((Some(id.clone()), api::Response::SpawnToken { token_id, x, y, img })); + _ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id, x, y, img }))); }, api::Request::MoveToken { token_id, x, y } => { // TODO: add check to make sure the actor is authorized to move the token - _ = broadcast.send((None, api::Response::MoveToken { token_id, x, y })); + if token_id < self.tokens.len() { + self.tokens[token_id].1 = x; + self.tokens[token_id].2 = y; + _ = broadcast.send((None, api::Response::MoveToken { token_id, x, y })); + } }, api::Request::Quit => _ = broadcast.send((None, api::Response::Quit { id })), api::Request::Kick(id) => _ = broadcast.send((Some(id), api::Response::Shutdown)), diff --git a/src/main.rs b/src/main.rs index a921bb6..ff5f1f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,7 @@ async fn socket_receiver(mut recv: SplitStream, msend: mpsc::Send async fn socket_sender(id: String, mut send: SplitSink, mut brecv: broadcast::Receiver<(Option, Response)>) { while let Ok((to_id, msg)) = brecv.recv().await { if to_id.is_none() || to_id.map(|t| t == id).unwrap_or(false) { + println!("Sending a message to {}: {:?}", &id, &msg); let err = send.send(ws::Message::Text(serde_json::to_string(&msg).unwrap())).await.is_err(); if err || matches!(msg, Response::Shutdown) { _ = send.close().await;