diff --git a/server/src/app/mod.rs b/server/src/app/mod.rs index 50aa4d5..0f60eba 100644 --- a/server/src/app/mod.rs +++ b/server/src/app/mod.rs @@ -202,12 +202,6 @@ impl App { )).await.ok(); } - QRPacketData::RGameHistory(response) => { - socket.send(Message::Binary( - encode_response(CODE_GAME_HISTORY, response.encode()) - )).await.ok(); - } - _ => { } } } diff --git a/server/src/manager/data.rs b/server/src/manager/data.rs index abd93e7..f373078 100644 --- a/server/src/manager/data.rs +++ b/server/src/manager/data.rs @@ -380,9 +380,6 @@ pub async fn thread_system(mut app:App, bus:Bus) app.sessions.set(&token, session); app.session_time.set(chain_id, token); - // Set player to Dawn. - response.mode = 0; - response.status = STATUS_OK; response.token = token; } @@ -419,10 +416,8 @@ pub async fn thread_system(mut app:App, bus:Bus) session.p_dusk = session.p_dawn.clone(); session.p_dawn.user = Some(uid); session.p_dawn.connections.clear(); - response.mode = 0; } else { session.p_dusk.user = Some(uid); - response.mode = 1; } true } else { @@ -444,7 +439,6 @@ pub async fn thread_system(mut app:App, bus:Bus) else { println!("User resumes session."); response.status = STATUS_OK; - response.mode = (session.p_dusk.user == user_id) as u8; true } } else { response.status = STATUS_NOAUTH; false } @@ -455,14 +449,20 @@ pub async fn thread_system(mut app:App, bus:Bus) println!("User spectates session."); response.status = STATUS_OK; - response.mode = 2; true } { // Associate session and connection on join if let Some(conn) = app.connections.get_mut(qr.id as usize) { conn.session = Some(session.token); } - session.add_connection(response.mode, qr.id); + let mode = if user_id == session.p_dawn.user { + 0 + } else if user_id == session.p_dusk.user { + 1 + } else { + 2 + }; + session.add_connection(mode, qr.id); } } @@ -618,21 +618,6 @@ pub async fn thread_system(mut app:App, bus:Bus) } } - QRPacketData::QGameHistory(request) => { - let mut response = PacketGameHistoryResponse::new(); - - println!("Request: Game History"); - - if let Some(session) = app.sessions.get(&request.token) { - response.status = STATUS_OK; - response = generate_game_history(&app, &session); - } else { - response.status = STATUS_ERROR; - } - - Some(QRPacket::new(qr.id, QRPacketData::RGameHistory(response))) - } - _ => { Some(QRPacket::new(0, QRPacketData::None)) } } } @@ -644,60 +629,13 @@ pub async fn thread_system(mut app:App, bus:Bus) fn generate_game_state(app:&App, session:&Session) -> protocol::PacketGameStateResponse { - use protocol::{PacketGameStateResponse, PacketGameStateResponsePiece}; + use protocol::PacketGameStateResponse; let mut response = PacketGameStateResponse::new(); - response.player = 2; - response.turn = session.game.turn; - if session.game.history.len() > 0 { - response.play = session.game.history[session.game.history.len() - 1]; - } - - // Get Dawn handle - if let Some(id) = session.p_dawn.user { - if let Some(user) = app.get_user_by_id(id) { - response.dawn_handle = user.handle.clone(); - } - } - - // Get Dusk handle - if let Some(id) = session.p_dusk.user { - if let Some(user) = app.get_user_by_id(id) { - response.dusk_handle = user.handle.clone(); - } - } - - // Get pool sizes - response.dawn_pool = session.game.pool[0]; - response.dusk_pool = session.game.pool[1]; - - // Get list of pieces - for i in 0..session.game.board.pieces.len() { - response.pieces[i] = if let Some(piece) = &session.game.board.pieces[i] { - PacketGameStateResponsePiece { - valid:true, - piece:piece.class, - promoted:piece.promoted, - player:piece.player, - tile:piece.tile, - } - } else { - PacketGameStateResponsePiece::new() - }; - } - - response -} - -fn generate_game_history(app:&App, session:&Session) -> protocol::PacketGameHistoryResponse -{ - use protocol::PacketGameHistoryResponse; - - let mut response = PacketGameHistoryResponse::new(); - response.token = session.token; - + response.player = 2; + // Get Dawn handle if let Some(id) = session.p_dawn.user { if let Some(user) = app.get_user_by_id(id) { @@ -712,6 +650,7 @@ fn generate_game_history(app:&App, session:&Session) -> protocol::PacketGameHist } } + // Get history response.history = session.game.history.clone(); response diff --git a/server/src/manager/ws.rs b/server/src/manager/ws.rs index deed771..676c1e1 100644 --- a/server/src/manager/ws.rs +++ b/server/src/manager/ws.rs @@ -161,20 +161,13 @@ pub async fn handle_ws(ws:WebSocketStream>, args:HttpServiceAr Err(_) => { println!("error: packet decode failed."); } } - CODE_GAME_HISTORY => match PacketGameHistory::decode(&data, &mut index) { - Ok(packet) => { - args.bus.send( - bus_ds, - QRPacket::new(conn_id, QRPacketData::QGameHistory(packet)) - ).ok(); - } - Err(_) => { println!("error: packet decode failed."); } - } - _ => { } } true } + + Message::Close(_) => { true } + _ => { println!("notice: received unexpected websocket data."); true diff --git a/server/src/protocol/code.rs b/server/src/protocol/code.rs index 0fe8741..49c1392 100644 --- a/server/src/protocol/code.rs +++ b/server/src/protocol/code.rs @@ -31,4 +31,3 @@ pub const CODE_SESSION_LEAVE :u16 = 0x002F; pub const CODE_GAME_STATE :u16 = 0x0030; pub const CODE_GAME_PLAY :u16 = 0x0031; -pub const CODE_GAME_HISTORY :u16 = 0x0032; diff --git a/server/src/protocol/mod.rs b/server/src/protocol/mod.rs index 1d0c1e6..9de9584 100644 --- a/server/src/protocol/mod.rs +++ b/server/src/protocol/mod.rs @@ -23,6 +23,9 @@ pub enum QRPacketData { QAuthRevoke, + QUserList(PacketUserList), + RUserList(PacketUserListResponse), + QSessionList(PacketSessionList), RSessionList(PacketSessionListResponse), @@ -40,9 +43,6 @@ pub enum QRPacketData { RGameState(PacketGameStateResponse), QGamePlay(PacketGamePlay), - - QGameHistory(PacketGameHistory), - RGameHistory(PacketGameHistoryResponse), } #[derive(Clone)] diff --git a/server/src/protocol/packet/game_history.rs b/server/src/protocol/packet/game_history.rs index cc14b9e..b5e4416 100644 --- a/server/src/protocol/packet/game_history.rs +++ b/server/src/protocol/packet/game_history.rs @@ -42,6 +42,7 @@ impl Packet for PacketGameHistory { pub struct PacketGameHistoryResponse { pub status:u16, pub token:SessionToken, + pub player:u8, pub dawn_handle:String, pub dusk_handle:String, pub history:Vec, diff --git a/server/src/protocol/packet/game_state.rs b/server/src/protocol/packet/game_state.rs index c968d12..a15efe3 100644 --- a/server/src/protocol/packet/game_state.rs +++ b/server/src/protocol/packet/game_state.rs @@ -3,7 +3,7 @@ use crate::{ util::pack::pack_u16, }; -use game::{game::Pool, history::Play}; +use game::history::Play; use super::Packet; @@ -38,53 +38,25 @@ impl Packet for PacketGameState { } } - -#[derive(Clone, Copy)] -pub struct PacketGameStateResponsePiece { - pub valid:bool, - pub piece:u8, - pub promoted:bool, - pub player:u8, - pub tile:u8, -} -impl PacketGameStateResponsePiece { - pub fn new() -> Self - { - Self { - valid:false, - piece:0, - promoted:false, - player:0, - tile:0, - } - } -} - #[derive(Clone)] pub struct PacketGameStateResponse { pub status:u16, - pub turn:u16, + pub token:SessionToken, pub player:u8, - pub play:Play, pub dawn_handle:String, pub dusk_handle:String, - pub dawn_pool:Pool, - pub dusk_pool:Pool, - pub pieces:[PacketGameStateResponsePiece; game::consts::PIECES_TOTAL], + pub history:Vec, } impl PacketGameStateResponse { pub fn new() -> Self { Self { status:0, - turn:0, - player:0, - play:Play::new(), + token:SessionToken::default(), + player:2, dawn_handle:String::new(), dusk_handle:String::new(), - dawn_pool:Pool::default(), - dusk_pool:Pool::default(), - pieces:[PacketGameStateResponsePiece::new(); game::consts::PIECES_TOTAL], + history:Vec::new(), } } } @@ -93,53 +65,28 @@ impl Packet for PacketGameStateResponse { fn encode(&self) -> Vec { - let mut flags = 0u16; - flags |= self.player as u16; - - let mut play = 0; - play |= self.play.source as u16; - play |= (self.play.from as u16) << 4; - play |= (self.play.to as u16) << 10; - - let mut piece_bytes = Vec::new(); - for piece in &self.pieces { - let piece_data: u16 = piece.valid as u16 - | ((piece.piece as u16) << 1) - | ((piece.promoted as u16) << 4) - | ((piece.player as u16) << 5) - | ((piece.tile as u16) << 6); - - piece_bytes.append(&mut pack_u16(piece_data)); + let mut history_bytes = Vec::new(); + for play in &self.history { + let mut data = 0; + data |= play.source as u16; + data |= (play.from as u16) << 4; + data |= (play.to as u16) << 10; + history_bytes.append(&mut pack_u16(data)); } - let dawn_pool_bytes :u16 = self.dawn_pool[0] as u16 - | ((self.dawn_pool[1] as u16) << 5) - | ((self.dawn_pool[2] as u16) << 7) - | ((self.dawn_pool[3] as u16) << 9) - | ((self.dawn_pool[4] as u16) << 11) - | ((self.dawn_pool[5] as u16) << 13) - | ((self.dawn_pool[6] as u16) << 14); - - let dusk_pool_bytes :u16 = self.dusk_pool[0] as u16 - | ((self.dusk_pool[1] as u16) << 5) - | ((self.dusk_pool[2] as u16) << 7) - | ((self.dusk_pool[3] as u16) << 9) - | ((self.dusk_pool[4] as u16) << 11) - | ((self.dusk_pool[5] as u16) << 13) - | ((self.dusk_pool[6] as u16) << 14); - + let mut flags = 0u16; + flags |= self.player as u16; + [ pack_u16(self.status), + self.token.to_vec(), pack_u16(flags), - pack_u16(play), - pack_u16(self.turn), pack_u16(self.dawn_handle.len() as u16), self.dawn_handle.as_bytes().to_vec(), pack_u16(self.dusk_handle.len() as u16), self.dusk_handle.as_bytes().to_vec(), - pack_u16(dawn_pool_bytes), - pack_u16(dusk_pool_bytes), - piece_bytes, + pack_u16(self.history.len() as u16), + history_bytes, ].concat() } } diff --git a/server/src/protocol/packet/mod.rs b/server/src/protocol/packet/mod.rs index bb20e12..8d5f47a 100644 --- a/server/src/protocol/packet/mod.rs +++ b/server/src/protocol/packet/mod.rs @@ -4,6 +4,8 @@ mod register; pub use register::*; mod auth; pub use auth::*; mod resume; pub use resume::*; +mod user_list; pub use user_list::*; + mod session_list; pub use session_list::*; mod session_create; pub use session_create::*; mod session_join; pub use session_join::*; @@ -11,7 +13,7 @@ mod session_retire; pub use session_retire::*; mod game_state; pub use game_state::*; mod game_play; pub use game_play::*; -mod game_history; pub use game_history::*; +//mod game_history; pub use game_history::*; mod prelude { pub trait Packet { diff --git a/server/src/protocol/packet/session_create.rs b/server/src/protocol/packet/session_create.rs index 87678da..45e667d 100644 --- a/server/src/protocol/packet/session_create.rs +++ b/server/src/protocol/packet/session_create.rs @@ -1,6 +1,6 @@ use crate::{ app::session::SessionToken, - util::pack::{pack_u8, pack_u16}, + util::pack::pack_u16, }; use super::Packet; @@ -29,7 +29,6 @@ impl Packet for PacketSessionCreate { pub struct PacketSessionCreateResponse { pub status:u16, pub token:SessionToken, - pub mode:u8, } impl PacketSessionCreateResponse { pub fn new() -> Self @@ -37,7 +36,6 @@ impl PacketSessionCreateResponse { Self { status:0, token:SessionToken::default(), - mode:0, } } } @@ -48,7 +46,6 @@ impl Packet for PacketSessionCreateResponse { { [ pack_u16(self.status), - pack_u8(self.mode), self.token.to_vec(), ].concat() } diff --git a/server/src/protocol/packet/session_join.rs b/server/src/protocol/packet/session_join.rs index 824ddf1..3d12333 100644 --- a/server/src/protocol/packet/session_join.rs +++ b/server/src/protocol/packet/session_join.rs @@ -1,6 +1,6 @@ use crate::{ app::session::SessionToken, - util::pack::{pack_u8, pack_u16}, + util::pack::pack_u16, }; use super::Packet; @@ -41,7 +41,6 @@ impl Packet for PacketSessionJoin { pub struct PacketSessionJoinResponse { pub status:u16, pub token:SessionToken, - pub mode:u8, } impl PacketSessionJoinResponse { pub fn new() -> Self @@ -49,7 +48,6 @@ impl PacketSessionJoinResponse { Self { status:0, token:SessionToken::default(), - mode:0, } } } @@ -60,7 +58,6 @@ impl Packet for PacketSessionJoinResponse { { [ pack_u16(self.status), - pack_u8(self.mode), self.token.to_vec(), ].concat() } diff --git a/server/src/protocol/packet/user_list.rs b/server/src/protocol/packet/user_list.rs new file mode 100644 index 0000000..f831da7 --- /dev/null +++ b/server/src/protocol/packet/user_list.rs @@ -0,0 +1,76 @@ +use crate::util::pack::{pack_u16, unpack_u16}; + +use super::Packet; + +#[derive(Clone)] +pub struct PacketUserList { + pub page:u16, +} +impl PacketUserList { + pub fn new() -> Self + { + Self { + page:0, + } + } +} +impl Packet for PacketUserList { + type Data = Self; + + fn decode(data:&Vec, index:&mut usize) -> Result + { + let mut result = Self::new(); + + if data.len() - *index == 2 { + result.page = unpack_u16(data, index); + + Ok(result) + } else { + Err(()) + } + } +} + + +#[derive(Clone)] +pub struct PacketUserListResponseRecord { + //pub token:UserToken, + pub handle:String, +} + +#[derive(Clone)] +pub struct PacketUserListResponse { + pub status:u16, + pub records:Vec, +} +impl PacketUserListResponse { + pub fn new() -> Self + { + Self { + status:0, + records:Vec::new(), + } + } +} +impl Packet for PacketUserListResponse { + type Data = Self; + + fn encode(&self) -> Vec + { + let mut result = pack_u16(self.status as u16); + + result.append(&mut pack_u16(self.records.len() as u16)); + + for record in &self.records { + let mut chunk = Vec::new(); //record.token.to_vec(); + + // Handle + let mut bytes = record.handle.as_bytes().to_vec(); + chunk.append(&mut pack_u16(bytes.len() as u16)); + if bytes.len() > 0 { chunk.append(&mut bytes); } + + result.append(&mut chunk); + } + result + } +} diff --git a/www/js/interface.js b/www/js/interface.js index acef0eb..ea8d0d4 100644 --- a/www/js/interface.js +++ b/www/js/interface.js @@ -3,8 +3,8 @@ let INTERFACE_DATA = null; const INTERFACE = { Mode: { Local: 0, - Online: 1, - Replay: 2, + Player: 1, + Review: 2, }, Color: { @@ -290,16 +290,17 @@ const INTERFACE = { draw() { if(INTERFACE_DATA === null) return; - if(INTERFACE_DATA.mode == INTERFACE.Mode.Replay) { - document.getElementById("ind_turn").innerText = INTERFACE_DATA.replay_turn + " of " + INTERFACE_DATA.history.length; - } - 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]; + } + let width = canvas.width; let height = canvas.height; @@ -369,7 +370,7 @@ const INTERFACE = { case 1: ctx.fillStyle = INTERFACE.Color.TileLight; break; case 2: ctx.fillStyle = INTERFACE.Color.TileDark; break; } - if(GAME_DATA.turn > 0 && INTERFACE_DATA.play.source < 2 && (INTERFACE_DATA.play.to == i || (INTERFACE_DATA.play.source == 0 && INTERFACE_DATA.play.from == i))) { + if(GAME_DATA.turn > 0 && play.source < 2 && (play.to == i || (play.source == 0 && play.from == i))) { ctx.fillStyle = INTERFACE.Color.HintPlay; } else if(GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Omen && piece.player == (GAME_DATA.turn & 1)) { ctx.fillStyle = INTERFACE.Color.HintCheck; @@ -704,35 +705,18 @@ const INTERFACE = { }, }, - init(data, mode) { + init(token, mode) { GAME.init(); - let token = null; - let player = 0; + let player = 2; + if(mode == INTERFACE.Mode.Local) { player = 0; } + let history = [ ]; let dawn = null; let dusk = null; - if(data !== null) { - switch(mode) { - case INTERFACE.Mode.Online: { - token = data.token; - player = data.mode; - } break; - - case INTERFACE.Mode.Replay: { - history = data.history; - player = 2; - } break; - } - - if(data.dawn !== undefined) { dawn = data.dawn; } - if(data.dusk !== undefined) { dusk = data.dusk; } - } - INTERFACE_DATA = { mode: mode, - token: token, canvas: document.getElementById("game"), @@ -747,15 +731,14 @@ const INTERFACE = { handles: [dawn, dusk], board_state: [ ], - play: null, retire:false, retire_warn:false, - auto_mode: null, + history: history, replay_turn: 0, replay_auto: false, - history: history, + auto_mode: null, Ui: { scale: 0, @@ -780,24 +763,18 @@ const INTERFACE = { window.addEventListener("resize", INTERFACE.draw); switch(INTERFACE_DATA.mode) { - case INTERFACE.Mode.Replay: case INTERFACE.Mode.Local: { INTERFACE.draw(); } break; - - case INTERFACE.Mode.Online: { - MESSAGE_COMPOSE([ - PACK.u16(OpCode.GameState), - INTERFACE_DATA.token, - ]); - } break; } + } else { + LOAD(SCENES.Browse); } }, uninit() { if(INTERFACE_DATA !== null) { - if(INTERFACE_DATA.mode == INTERFACE.Mode.Online) { + if(INTERFACE_DATA.mode != INTERFACE.Mode.Local) { MESSAGE_COMPOSE([ PACK.u16(OpCode.SessionLeave), ]); @@ -820,44 +797,51 @@ const INTERFACE = { if(data === null) { return; } switch(code) { - case OpCode.GameState: { - INTERFACE_DATA.player = data.player; - GAME_DATA.turn = data.turn; - INTERFACE_DATA.play = data.play; - if(INTERFACE_DATA.play.source == 2) { - GAME_DATA.state.code = 2; + case OpCode.SessionCreate: + case OpCode.SessionJoin: { + if(data.status != Status.Ok) { + LOAD(SCENES.Browse); + } + + switch(INTERFACE_DATA.mode) { + case INTERFACE.Mode.Review: + case INTERFACE.Mode.Player: { + MESSAGE_COMPOSE([ + PACK.u16(OpCode.GameState), + INTERFACE_DATA.token, + ]); + } break; + } + } break; + + case OpCode.GameState: { + if(INTERFACE_DATA.mode == INTERFACE.Mode.Player) { + INTERFACE_DATA.player = data.player; + } + + INTERFACE_DATA.history = [ ]; + for(let i = 0; i < data.history.length; ++i) { + INTERFACE.history_push(data.history[i]); + } + let turn = INTERFACE_DATA.history.length; + + if(INTERFACE_DATA.history.length > 0) { + if(INTERFACE_DATA.history[INTERFACE_DATA.history.length-1].source == 2) { + GAME_DATA.state.code = 2; + turn = 0; + } } if(data.dawn.length > 0) { INTERFACE_DATA.handles[0] = data.dawn; } if(data.dusk.length > 0) { INTERFACE_DATA.handles[1] = data.dusk; } - // Clear piece placement. - for(let i = 0; i < GAME_DATA.board.tiles.length; ++i) { - GAME_DATA.board.tiles[i].piece = null; - } - - // Update pools. - GAME_DATA.pools[0].pieces = data.pool_dawn; - GAME_DATA.pools[1].pieces = data.pool_dusk; - - // Replace pieces list. - for(let i = 0; i < GAME_DATA.board.pieces.length; ++i) { - GAME_DATA.board.pieces[i] = data.pieces[i]; - if(data.pieces[i] !== null) { - GAME_DATA.board.tiles[data.pieces[i].tile].piece = i; - } - } - - GAME_DATA.update_board(); - INTERFACE.draw(); + INTERFACE.replay_jump(turn); } break; case OpCode.GamePlay: { - if(data.status == Status.Ok && data.turn == GAME_DATA.turn) { - INTERFACE_DATA.play = data.play; - GAME_DATA.process(data.play); - INTERFACE.draw(); + if(data.status == Status.Ok && data.turn == INTERFACE_DATA.history.length) { + INTERFACE.history_push(data.play); } } break; } @@ -868,8 +852,7 @@ const INTERFACE = { switch(INTERFACE_DATA.mode) { // Apply action and change turn for local game. case INTERFACE.Mode.Local: { - INTERFACE_DATA.play = play; - GAME_DATA.process(play); + INTERFACE.history_push(play); INTERFACE_DATA.player = +(!INTERFACE_DATA.player); INTERFACE_DATA.rotate = +(!INTERFACE_DATA.rotate); @@ -877,12 +860,12 @@ const INTERFACE = { INTERFACE.draw(); if(INTERFACE_DATA.auto_mode !== null && INTERFACE_DATA.auto_mode == (GAME_DATA.turn & 1)) { - setTimeout(INTERFACE.auto_play, 500); + setTimeout(INTERFACE.auto_play, 1000); } } break; // Send action to server for validation. - case INTERFACE.Mode.Online: { + case INTERFACE.Mode.Player: { let move_data = play.source | (play.from << 1) | (play.to << 7); MESSAGE_COMPOSE([ PACK.u16(OpCode.GamePlay), @@ -891,11 +874,6 @@ const INTERFACE = { PACK.u16(move_data), ]); } break; - - // Branch into local game from here. - case INTERFACE.Mode.Replay: { - - } break; } }, @@ -910,7 +888,7 @@ const INTERFACE = { }, retire() { - if(INTERFACE_DATA.mode == INTERFACE.Mode.Online) { + if(INTERFACE_DATA.mode == INTERFACE.Mode.Player) { let button_retire = document.getElementById("button-retire"); if(INTERFACE_DATA.retire_warn) { @@ -939,25 +917,40 @@ const INTERFACE = { } }, + history_push(play) { + 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(); + } + }, + replay_jump(turn) { turn = +turn; - if(INTERFACE_DATA.mode == INTERFACE.Mode.Replay) { - if(turn >= 0 && turn <= INTERFACE_DATA.history.length) { - INTERFACE_DATA.replay_turn = turn; - + + if(turn >= 0 && turn <= INTERFACE_DATA.history.length) { + if(turn < INTERFACE_DATA.replay_turn) { GAME.init(); - for(let i = 0; i < INTERFACE_DATA.replay_turn; ++i) { + for(let i = 0; i < turn; ++i) { GAME_DATA.process(INTERFACE_DATA.history[i]); } - - INTERFACE_DATA.play = null; - if(INTERFACE_DATA.replay_turn > 0) { - INTERFACE_DATA.play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1]; + } else { + while(INTERFACE_DATA.replay_turn < turn) { + GAME_DATA.process(INTERFACE_DATA.history[INTERFACE_DATA.replay_turn]); + INTERFACE_DATA.replay_turn++; } - - document.getElementById("turn-slider").value = INTERFACE_DATA.replay_turn; - INTERFACE.draw(); } + INTERFACE_DATA.replay_turn = turn; + + 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").value = INTERFACE_DATA.replay_turn; + } + + INTERFACE.draw(); } }, replay_first() { diff --git a/www/js/scene.js b/www/js/scene.js index 842b7d8..5984f12 100644 --- a/www/js/scene.js +++ b/www/js/scene.js @@ -229,12 +229,6 @@ const SCENES = { table.appendChild(UI.session_table(data.records)); } } break; - case OpCode.SessionCreate: - case OpCode.SessionJoin: { - if(data.status == Status.Ok) { - LOAD(SCENES.Game, data); - } - } break; } }, disconnect() { @@ -398,8 +392,7 @@ const SCENES = { table.appendChild(UI.session_table(data.records)); } } break; - case OpCode.SessionCreate: - case OpCode.SessionJoin: { + { if(data.status == Status.Ok) { LOAD(SCENES.Game, data); } @@ -453,11 +446,6 @@ const SCENES = { table.appendChild(UI.session_table_history(data.records)); } } break; - case OpCode.GameHistory: { - if(data.status == Status.Ok) { - LOAD(SCENES.GameHistory, data); - } - } break; } }, disconnect() { @@ -525,10 +513,8 @@ const SCENES = { Game:{ load(data) { - if(data === null) { return false; } - let buttons_bottom = [ ]; - if(data.mode != 2) { + if(data.mode != INTERFACE.Mode.Review) { let button_retire = UI.button("Surrender", () => { INTERFACE.retire(); }); button_retire.setAttribute("id", "button-retire"); buttons_bottom.push(button_retire); @@ -540,11 +526,34 @@ const SCENES = { UI.button("Mirror", () => { INTERFACE.mirror(); }), ], buttons_bottom); + if(data.mode == INTERFACE.Mode.Review) { + let ind_turn = UI.div([UI.text("0 of 0")]); + ind_turn.setAttribute("id", "indicator-turn"); + + UI.mainnav( + [ ], + [ + UI.button("Auto", () => { INTERFACE.replay_toggle_auto(); }), + UI.button("◀", () => { INTERFACE.replay_first(); }), + UI.button("◁", () => { INTERFACE.replay_prev(); }), + ind_turn, + UI.button("▷", () => { INTERFACE.replay_next(); }), + UI.button("▶", () => { INTERFACE.replay_last(); }), + ] + ); + + let slider = UI.slider((event) => { INTERFACE.replay_jump(event.target.value); }); + slider.setAttribute("id", "turn-slider"); + slider.setAttribute("min", "0"); + slider.setAttribute("max", "0"); + MAIN.appendChild(UI.div([ slider ], "turn-slider-padding")); + } + let canvas = document.createElement("canvas"); canvas.setAttribute("id", "game"); MAIN.appendChild(canvas); - INTERFACE.init(data, INTERFACE.Mode.Online); + INTERFACE.init(data.token, data.mode); history.pushState(null, "Omen - Game", "/game/" + PACK.base64(data.token).slice(0, -1)); return true; @@ -554,13 +563,9 @@ const SCENES = { }, message(code, data) { switch(code) { - case OpCode.GameState: { - if(data.status == Status.Ok) { - INTERFACE.message(code, data); - } else { - LOAD(SCENES.Browse); - } - } break; + case OpCode.SessionCreate: + case OpCode.SessionJoin: + case OpCode.GameState: case OpCode.GamePlay: { INTERFACE.message(code, data); } break; @@ -587,7 +592,7 @@ const SCENES = { canvas.setAttribute("id", "game"); MAIN.appendChild(canvas); - INTERFACE.init(data, INTERFACE.Mode.Local); + INTERFACE.init(null, INTERFACE.Mode.Local); history.pushState(null, "Omen - Practice", "/practice/"); return true; @@ -596,51 +601,6 @@ const SCENES = { INTERFACE.uninit(); }, }, - - GameHistory:{ - load(data) { - let buttons_bottom = [ ]; - buttons_bottom.push(UI.button("Back", () => { LOAD(SCENES.History) })); - - UI.nav([ - UI.button("Rotate", () => { INTERFACE.rotate(); }), - UI.button("Mirror", () => { INTERFACE.mirror(); }), - ], buttons_bottom); - - let ind_turn = UI.div([UI.text("0 of 0")]); - ind_turn.setAttribute("id", "ind_turn"); - - UI.mainnav( - [ ], - [ - UI.button("Auto", () => { INTERFACE.replay_toggle_auto(); }), - UI.button("◀", () => { INTERFACE.replay_first(); }), - UI.button("◁", () => { INTERFACE.replay_prev(); }), - ind_turn, - UI.button("▷", () => { INTERFACE.replay_next(); }), - UI.button("▶", () => { INTERFACE.replay_last(); }), - ] - ); - - let slider = UI.slider((event) => { INTERFACE.replay_jump(event.target.value); }); - slider.setAttribute("id", "turn-slider"); - slider.setAttribute("min", "0"); - slider.setAttribute("max", data.history.length); - MAIN.appendChild(UI.div([ slider ], "turn-slider-padding")); - - let canvas = document.createElement("canvas"); - canvas.setAttribute("id", "game"); - MAIN.appendChild(canvas); - - INTERFACE.init(data, INTERFACE.Mode.Replay); - - history.pushState(null, "Omen - History", "/history/" + PACK.base64(data.token).slice(0, -1)); - return true; - }, - unload() { - INTERFACE.uninit(); - }, - }, }; function LOAD(scene, data=null) { @@ -665,17 +625,6 @@ function LOAD_URL() { case "guide": LOAD(SCENES.Guide); break; case "practice": LOAD(SCENES.About); break; - case "history": { - LOAD(SCENES.History); - if(parts[2]) { - let token = UNPACK.base64(parts[2] + "="); - MESSAGE_COMPOSE([ - PACK.u16(OpCode.GameHistory), - token, - ]); - } - } break; - case "join": { LOAD(SCENES.Join); if(parts[2]) { diff --git a/www/js/system.js b/www/js/system.js index 08a7ad0..8f2399c 100644 --- a/www/js/system.js +++ b/www/js/system.js @@ -185,21 +185,16 @@ function MESSAGE(event) { case OpCode.SessionJoin: { console.log("RECV SessionCreate/Join"); - if(bytes.length - index == 11) { + if(bytes.length - index == 10) { data = { status:0, token:new Uint8Array(8), - mode:2, }; result = UNPACK.u16(bytes, index); index = result.index; data.status = result.data; - result = UNPACK.u8(bytes, index); - index = result.index; - data.mode = result.data; - for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; } } } break; @@ -207,95 +202,54 @@ function MESSAGE(event) { case OpCode.GameState: { console.log("RECV GameState"); - //if(bytes.length - index >= 22) { - data = { - status:0, - player:2, - turn:0, - play:new GAME.Play(), - dawn:"", - dusk:"", - pool_dawn:[ ], - pool_dusk:[ ], - pieces:[ ], - }; + data = { + status:0, + token:new Uint8Array(8), + player:2, + dawn:"", + dusk:"", + history:[ ], + }; - // Status + // Status + result = UNPACK.u16(bytes, index); + index = result.index; + data.status = result.data; + + // Token + for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; } + + // Flags + result = UNPACK.u16(bytes, index); + index = result.index; + let flags = result.data; + + data.player = flags & 0x3; + + // Handles + result = UNPACK.string(bytes, index); + index = result.index; + data.dawn = result.data; + + result = UNPACK.string(bytes, index); + index = result.index; + data.dusk = result.data; + + // History + result = UNPACK.u16(bytes, index); + index = result.index; + let history_length = result.data; + + for(let i = 0; i < history_length; ++i) { result = UNPACK.u16(bytes, index); index = result.index; - data.status = result.data; - - // Flags - result = UNPACK.u16(bytes, index); - index = result.index; - let flags = result.data; - - data.player = flags & 0x3; - - // Last Play - result = UNPACK.u16(bytes, index); - index = result.index; - data.play.source = result.data & 0xF; - data.play.from = (result.data >> 4) & 0x3F; - data.play.to = (result.data >> 10) & 0x3F; - - // Turn - result = UNPACK.u16(bytes, index); - index = result.index; - data.turn = result.data; - - // Handles - result = UNPACK.string(bytes, index); - index = result.index; - data.dawn = result.data; - - result = UNPACK.string(bytes, index); - index = result.index; - data.dusk = result.data; - - // Dawn pool - result = UNPACK.u16(bytes, index); - index = result.index; - let dawn_pool_bits = result.data; - - data.pool_dawn.push(dawn_pool_bits & 0x1F); - data.pool_dawn.push((dawn_pool_bits >> 5) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 7) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 9) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 11) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 13) & 0x1); - data.pool_dawn.push((dawn_pool_bits >> 14) & 0x1); - - // Dusk pool - result = UNPACK.u16(bytes, index); - index = result.index; - let dusk_pool_bits = result.data; - - data.pool_dusk.push(dusk_pool_bits & 0x1f); - data.pool_dusk.push((dusk_pool_bits >> 5) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 7) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 9) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 11) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 13) & 0x1); - data.pool_dusk.push((dusk_pool_bits >> 14) & 0x1); - - // Pieces - for(let i = 0; i < GAME.Const.Count.Pieces; ++i) { - result = UNPACK.u16(bytes, index); - index = result.index; - let piece_data = result.data; - - if((piece_data & 1) != 0) { - let piece = new GAME.Piece((piece_data >> 1) & 0x7, (piece_data >> 5) & 1); - piece.promoted = ((piece_data >> 4) & 1) != 0; - piece.tile = (piece_data >> 6) & 0x3F; - - data.pieces.push(piece); - } else { - data.pieces.push(null); - } - } - //} + + data.history.push(new GAME.Play( + result.data & 0xF, + (result.data >> 4) & 0x3F, + (result.data >> 10) & 0x3F, + )); + } } break; case OpCode.GamePlay: { @@ -324,55 +278,12 @@ function MESSAGE(event) { data.play.to = (result.data >> 10) & 0x3F; } break; - case OpCode.GameHistory: { - console.log("RECV GameHistory"); - - data = { - status:0, - token:new Uint8Array(8), - dawn:"", - dusk:"", - history:[ ], - }; - - // Status - result = UNPACK.u16(bytes, index); - index = result.index; - data.status = result.data; - - // Token - for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; } - - // Handles - result = UNPACK.string(bytes, index); - index = result.index; - data.dawn = result.data; - - result = UNPACK.string(bytes, index); - index = result.index; - data.dusk = result.data; - - // Pieces - result = UNPACK.u16(bytes, index); - index = result.index; - let history_length = result.data; - - for(let i = 0; i < history_length; ++i) { - result = UNPACK.u16(bytes, index); - index = result.index; - - data.history.push(new GAME.Play( - result.data & 0xF, - (result.data >> 4) & 0x3F, - (result.data >> 10) & 0x3F, - )); - } - } break; - default: console.log("RECV Undefined " + code); return; } + + console.log(data); if(SCENE.message !== undefined) { SCENE.message(code, data) }; } diff --git a/www/js/ui.js b/www/js/ui.js index 4d260a5..d5ad3ad 100644 --- a/www/js/ui.js +++ b/www/js/ui.js @@ -163,22 +163,31 @@ const UI = { for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let join_callback = function() { + LOAD(SCENES.Game, { + token:this.token, + mode:INTERFACE.Mode.Player, + }); MESSAGE_SESSION_JOIN(this.token, true); }; join_callback = join_callback.bind({token: records[r].token}); let spectate_callback = function() { + LOAD(SCENES.Game, { + token:this.token, + mode:INTERFACE.Mode.Review, + }); MESSAGE_SESSION_JOIN(this.token, false); }; spectate_callback = spectate_callback.bind({token: records[r].token}); if(records[r].player) { buttons.push(UI.button("Resume", join_callback)); + buttons.push(UI.button("Review", spectate_callback)); } else { if(sessionStorage.getItem("auth") !== null && (records[r].dawn == "" || records[r].dusk == "")) { buttons.push(UI.button("Join", join_callback)); } - buttons.push(UI.button("Spectate", spectate_callback)); + buttons.push(UI.button("View", spectate_callback)); } let dawn = UI.text(records[r].dawn); @@ -210,6 +219,10 @@ const UI = { for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let join_callback = function() { + LOAD(SCENES.Game, { + token:this.token, + mode:INTERFACE.Mode.Player, + }); MESSAGE_SESSION_JOIN(this.token, true); }; join_callback = join_callback.bind({token: records[r].token}); @@ -243,10 +256,11 @@ const UI = { for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let view_callback = function() { - MESSAGE_COMPOSE([ - PACK.u16(OpCode.GameHistory), - this.token, - ]); + LOAD(SCENES.Game, { + token:this.token, + mode:INTERFACE.Mode.Review, + }); + MESSAGE_SESSION_JOIN(this.token, false); }; view_callback = view_callback.bind({token: records[r].token});