diff --git a/server/src/manager/data.rs b/server/src/manager/data.rs index bb9f349..139fe45 100644 --- a/server/src/manager/data.rs +++ b/server/src/manager/data.rs @@ -646,13 +646,16 @@ pub async fn thread_system(mut app:App, bus:Bus) let mut response = PacketUserListResponse::new(); response.status = STATUS_NOAUTH; - if user_id.is_some() { - let users_list = app.users.list(); - for tid in users_list { - if let Some(user) = app.users.get(tid) { - response.records.push(PacketUserListData { - handle:user.handle.clone(), - }); + if let Some(user_id) = user_id { + for (_, uid) in app.user_id.pairs() { + let uid = *uid as u32; + + if uid != user_id { + if let Some(user) = app.get_user_by_id(uid) { + response.records.push(PacketUserListData { + handle:user.handle.clone(), + }); + } } } } diff --git a/www/js/interface.js b/www/js/interface.js index 531ed6c..3bfafe3 100644 --- a/www/js/interface.js +++ b/www/js/interface.js @@ -290,16 +290,15 @@ const INTERFACE = { draw() { if(INTERFACE_DATA === null) return; - let canvas = INTERFACE_DATA.canvas; - let ctx = INTERFACE_DATA.context; - INTERFACE.resize(); INTERFACE.resolve_board(); - let play = null; - if(INTERFACE_DATA.replay_turn > 0) { - play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1]; - } + INTERFACE.render(); + }, + + render() { + let canvas = INTERFACE_DATA.canvas; + let ctx = INTERFACE_DATA.context; let width = canvas.width; let height = canvas.height; @@ -308,6 +307,11 @@ const INTERFACE = { let gui_offset = INTERFACE_DATA.Ui.offset; let gui_scale = INTERFACE_DATA.Ui.scale; + let play = null; + if(INTERFACE_DATA.replay_turn > 0) { + play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1]; + } + // Draw background ctx.clearRect(0, 0, width, height); @@ -335,6 +339,13 @@ const INTERFACE = { let tile_state = INTERFACE_DATA.board_state[i][1]; let hover_state = INTERFACE_DATA.board_state[i][0]; + let draw_piece = true; + if(INTERFACE_DATA.Animate.play !== null) { + let play = INTERFACE_DATA.Animate.play; + draw_piece = draw_piece && !(play.source == 0 && (play.from == i || play.to == i)); + draw_piece = draw_piece && !(play.source == 1 && play.to == i); + } + let coord = HEX.tile_to_hex(i); if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) { coord.x = 8 - coord.x; @@ -352,7 +363,7 @@ const INTERFACE = { // Draw border ctx.fillStyle = INTERFACE.Color.TileBorder; - if(tile.piece !== null) { + if(draw_piece && tile.piece !== null) { if(GAME_DATA.board.pieces[tile.piece].player == GAME.Const.Player.Dawn) { ctx.fillStyle = INTERFACE.Color.DawnDark; } else { ctx.fillStyle = INTERFACE.Color.DuskDark; } } @@ -395,7 +406,7 @@ const INTERFACE = { ctx.fill(); // Draw tile content - if(piece !== null) { + if(draw_piece && piece !== null) { // Draw border hints if(!is_hover) { draw.hints(piece); } @@ -594,6 +605,75 @@ const INTERFACE = { ctx.textAlign = "left"; ctx.fillText(message, gui_margin, height - gui_margin); } + + if(INTERFACE_DATA.Animate.play !== null) { + let time = Math.min(1 - (INTERFACE_DATA.Animate.time - Date.now()) / 1000, 1); + time = time * time; + let play = INTERFACE_DATA.Animate.play; + + // Get to and from coordinates. + let coord_to = HEX.tile_to_hex(play.to); + if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) { + coord_to.x = 8 - coord_to.x; + coord_to.y = 8 - coord_to.y; + } + let to_x = basis_x + (1.5 * radius * coord_to.x); + let to_y = basis_y - (2 * gui_scale * coord_to.y) + (gui_scale * coord_to.x); + + let from_x = 0; + let from_y = 0; + switch(play.source) { + // Lerp between board positions. + case 0: { + let coord_from = HEX.tile_to_hex(play.from); + if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) { + coord_from.x = 8 - coord_from.x; + coord_from.y = 8 - coord_from.y; + } + from_x = basis_x + (1.5 * radius * coord_from.x); + from_y = basis_y - (2 * gui_scale * coord_from.y) + (gui_scale * coord_from.x); + } break; + + // Lerp between pool and board positions. + case 1: { + let coord_from = HEX.tile_to_hex(play.from); + if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) { + coord_from.x = 8 - coord_from.x; + coord_from.y = 8 - coord_from.y; + } + from_x = basis_x + (radius * 14); + from_y = basis_y - (9 - (2 * coord_from.y)) * gui_scale; + } break; + } + + // Get animation coordinates. + let x = MATH.lerp(from_x, to_x, time); + let y = MATH.lerp(from_y, to_y, time); + + let piece = INTERFACE_DATA.Animate.piece; + let target = INTERFACE_DATA.Animate.target; + + // Draw target piece. + if(target !== null) { + if(target.player == piece.player) { + let x = MATH.lerp(to_x, from_x, time); + let y = MATH.lerp(to_y, from_y, time); + draw.piece(target, x, y); + } else { + draw.piece(target, to_x, to_y); + } + } + + // Draw moving piece. + draw.piece(piece, x, y); + + if(Date.now() < INTERFACE_DATA.Animate.time) { + setTimeout(INTERFACE.render, 1000 / 30); + } else { + INTERFACE_DATA.Animate.play = null; + INTERFACE_DATA.Animate.time = 0; + } + } }, Draw: class { @@ -669,6 +749,44 @@ const INTERFACE = { moves &= ~mask; } } + + piece(piece, x, y) { + let radius = INTERFACE.Radius * this.scale; + let icon_radius = 0.69 * radius; + + this.ctx.save(); + this.ctx.translate(x, y); + + // Draw border + if(piece.player == GAME.Const.Player.Dawn) { this.ctx.fillStyle = INTERFACE.Color.DawnDark; } + else { this.ctx.fillStyle = INTERFACE.Color.DuskDark; } + + this.ctx.beginPath(); + this.hex(); + this.ctx.fill(); + + // Draw background. + this.ctx.fillStyle = INTERFACE.Color.TileDark; + this.ctx.beginPath(); + this.hex(0.94); + this.ctx.fill(); + + // Draw tile content + if(piece !== null) { + // Draw border hints + this.hints(piece); + + // Draw piece icon + if(INTERFACE_DATA.mirror && (piece.player ^ (INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate) != 0) { + this.ctx.rotate(Math.PI); + } + if(piece.promoted) { this.ctx.drawImage(GAME_ASSET.Image.Promote, -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.); } + this.ctx.drawImage(GAME_ASSET.Image.Piece[piece.piece][piece.player], -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.); + + } + + this.ctx.restore(); + } }, Ui: { @@ -749,6 +867,13 @@ const INTERFACE = { board_width: 0, pool_offset: 0, }, + + Animate: { + play: null, + piece: null, + target: null, + time: 0, + }, }; for(let i = 0; i < 61; ++i) { INTERFACE_DATA.board_state.push([0, 0]); } @@ -841,7 +966,7 @@ const INTERFACE = { case OpCode.GamePlay: { if(data.status == Status.Ok && data.turn == INTERFACE_DATA.history.length) { - INTERFACE.history_push(data.play); + INTERFACE.history_push(data.play, true); } } break; } @@ -852,7 +977,7 @@ const INTERFACE = { switch(INTERFACE_DATA.mode) { // Apply action and change turn for local game. case INTERFACE.Mode.Local: { - INTERFACE.history_push(play); + INTERFACE.history_push(play, true); INTERFACE_DATA.player = +(!INTERFACE_DATA.player); INTERFACE_DATA.rotate = +(!INTERFACE_DATA.rotate); @@ -917,31 +1042,53 @@ const INTERFACE = { } }, - history_push(play) { + history_push(play, animate=false) { INTERFACE_DATA.history.push(play); if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) { document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " of " + INTERFACE_DATA.history.length; document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.history.length); } if(INTERFACE_DATA.replay_turn == INTERFACE_DATA.history.length - 1) { - INTERFACE.replay_next(); + INTERFACE.replay_next(animate); } }, - replay_jump(turn) { + replay_jump(turn, animate=false) { turn = +turn; if(turn >= 0 && turn <= INTERFACE_DATA.history.length) { if(turn < INTERFACE_DATA.replay_turn) { + INTERFACE_DATA.replay_turn = 0; GAME.init(); - for(let i = 0; i < turn; ++i) { - GAME_DATA.process(INTERFACE_DATA.history[i]); + } + + let play = null; + let piece = null; + let target = null; + while(INTERFACE_DATA.replay_turn < turn) { + play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn]; + + if(play.source == 0) { + let piece_id = GAME_DATA.board.tiles[play.from].piece; + if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id]; } + piece_id = GAME_DATA.board.tiles[play.to].piece; + if(piece_id !== null) { target = GAME_DATA.board.pieces[piece_id]; } } - } else { - while(INTERFACE_DATA.replay_turn < turn) { - GAME_DATA.process(INTERFACE_DATA.history[INTERFACE_DATA.replay_turn]); - INTERFACE_DATA.replay_turn++; + + GAME_DATA.process(play); + + if(play.source == 1) { + let piece_id = GAME_DATA.board.tiles[play.to].piece; + if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id]; } } + + INTERFACE_DATA.replay_turn++; + } + if(animate) { + INTERFACE_DATA.Animate.time = Date.now() + 500; + INTERFACE_DATA.Animate.play = play; + INTERFACE_DATA.Animate.piece = piece; + INTERFACE_DATA.Animate.target = target; } INTERFACE_DATA.replay_turn = turn; @@ -965,9 +1112,9 @@ const INTERFACE = { INTERFACE_DATA.replay_auto = false; INTERFACE.replay_jump(INTERFACE_DATA.replay_turn - 1); }, - replay_next() { + replay_next(animate=false) { INTERFACE_DATA.replay_auto = false; - INTERFACE.replay_jump(INTERFACE_DATA.replay_turn + 1); + INTERFACE.replay_jump(INTERFACE_DATA.replay_turn + 1, animate); }, replay_toggle_auto() { INTERFACE_DATA.replay_auto = !INTERFACE_DATA.replay_auto; diff --git a/www/js/system.js b/www/js/system.js index d7add0b..62c5662 100644 --- a/www/js/system.js +++ b/www/js/system.js @@ -29,7 +29,6 @@ function RECONNECT() { } function RESUME() { - //sessionStorage.clear(); let b64_auth = sessionStorage.getItem("auth"); if(b64_auth !== null) { let auth = UNPACK.base64(b64_auth); diff --git a/www/js/util.js b/www/js/util.js index e1a8c95..62f1d9f 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -205,6 +205,10 @@ const MATH = { return ((a % b) + b) % b }, + lerp(a, b, t) { + return a + ((b - a) * t); + }, + sign_branch(v) { return (v * 2) - 1; },