Improve session filtering; add password UI to account.
This commit is contained in:
parent
2cea7f4b86
commit
ee332c4852
@ -7,7 +7,7 @@ use tokio_tungstenite::{tungstenite::Message, WebSocketStream};
|
|||||||
|
|
||||||
use crate::app::{
|
use crate::app::{
|
||||||
authentication::AuthToken,
|
authentication::AuthToken,
|
||||||
session::SessionToken,
|
context::Context,
|
||||||
};
|
};
|
||||||
|
|
||||||
type StreamType = Arc<RwLock<SplitSink<WebSocketStream<TokioIo<Upgraded>>, Message>>>;
|
type StreamType = Arc<RwLock<SplitSink<WebSocketStream<TokioIo<Upgraded>>, Message>>>;
|
||||||
@ -17,7 +17,8 @@ pub struct Connection {
|
|||||||
pub bus:u32,
|
pub bus:u32,
|
||||||
pub stream:StreamType,
|
pub stream:StreamType,
|
||||||
pub auth:Option<AuthToken>,
|
pub auth:Option<AuthToken>,
|
||||||
pub session:Option<SessionToken>,
|
|
||||||
|
pub context:Context,
|
||||||
|
|
||||||
pub prev:u32,
|
pub prev:u32,
|
||||||
pub next:u32,
|
pub next:u32,
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
use super::session::SessionToken;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Context {
|
pub enum Context {
|
||||||
None,
|
None,
|
||||||
|
Game(Game),
|
||||||
|
AccountSettings(AccountSettings),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Game {
|
||||||
|
pub token:SessionToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct AccountSettings {
|
||||||
|
pub auth_token:[u8; 8],
|
||||||
}
|
}
|
||||||
|
49
server/src/app/session/filter.rs
Normal file
49
server/src/app/session/filter.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum SortOrder {
|
||||||
|
Recent,
|
||||||
|
Viewers,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Sort {
|
||||||
|
pub order:SortOrder,
|
||||||
|
pub reverse:bool,
|
||||||
|
}
|
||||||
|
impl Sort {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
order:SortOrder::Recent,
|
||||||
|
reverse:false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SessionFilter {
|
||||||
|
pub start:usize,
|
||||||
|
pub count:usize,
|
||||||
|
|
||||||
|
pub is_complete:Option<bool>,
|
||||||
|
pub is_live:Option<bool>,
|
||||||
|
pub is_player:Option<bool>,
|
||||||
|
pub player:[Option<String>; 2],
|
||||||
|
|
||||||
|
pub sort:Sort,
|
||||||
|
}
|
||||||
|
impl SessionFilter {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
start:0,
|
||||||
|
count:0,
|
||||||
|
|
||||||
|
is_complete:None,
|
||||||
|
is_live:None,
|
||||||
|
is_player:None,
|
||||||
|
player:[None, None],
|
||||||
|
|
||||||
|
sort:Sort::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
use game::Game;
|
use game::Game;
|
||||||
|
|
||||||
|
mod filter; pub use filter::SessionFilter;
|
||||||
|
|
||||||
pub type SessionToken = [u8; 8];
|
pub type SessionToken = [u8; 8];
|
||||||
pub type SessionSecret = [u8; 8];
|
pub type SessionSecret = [u8; 8];
|
||||||
|
|
@ -18,6 +18,15 @@ pub struct UserStatistics {
|
|||||||
pub games_played:u32,
|
pub games_played:u32,
|
||||||
pub games_won:u32,
|
pub games_won:u32,
|
||||||
}
|
}
|
||||||
|
impl UserStatistics {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
games_played:0,
|
||||||
|
games_won:0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
@ -30,5 +39,26 @@ pub struct User {
|
|||||||
pub connection:Option<u32>,
|
pub connection:Option<u32>,
|
||||||
|
|
||||||
pub status:UserStatus,
|
pub status:UserStatus,
|
||||||
|
pub statistics:UserStatistics,
|
||||||
|
|
||||||
pub challenges:Vec<u32>,
|
pub challenges:Vec<u32>,
|
||||||
}
|
}
|
||||||
|
impl User {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
id:0,
|
||||||
|
flags:0,
|
||||||
|
handle:String::new(),
|
||||||
|
secret:Vec::new(),
|
||||||
|
na_key:0,
|
||||||
|
|
||||||
|
connection:None,
|
||||||
|
|
||||||
|
status:UserStatus::new(),
|
||||||
|
statistics:UserStatistics::new(),
|
||||||
|
|
||||||
|
challenges:Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,9 +5,10 @@ use crate::{
|
|||||||
app::{
|
app::{
|
||||||
authentication::Authentication,
|
authentication::Authentication,
|
||||||
connection::Connection,
|
connection::Connection,
|
||||||
user::{User, UserStatus},
|
user::User,
|
||||||
App,
|
App,
|
||||||
session::Session,
|
session::{Session, SessionFilter},
|
||||||
|
context::{self, Context},
|
||||||
},
|
},
|
||||||
protocol,
|
protocol,
|
||||||
};
|
};
|
||||||
@ -27,9 +28,9 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
let qr = packet.data;
|
let qr = packet.data;
|
||||||
|
|
||||||
let mut user_id = None;
|
let mut user_id = None;
|
||||||
let mut session_id = None;
|
let mut context = Context::None;
|
||||||
if let Some(conn) = app.connections.get(qr.id as usize) {
|
if let Some(conn) = app.connections.get(qr.id as usize) {
|
||||||
session_id = conn.session;
|
context = conn.context.clone();
|
||||||
|
|
||||||
if let Some(auth_id) = conn.auth {
|
if let Some(auth_id) = conn.auth {
|
||||||
if let Some(auth) = app.auths.get(&auth_id) {
|
if let Some(auth) = app.auths.get(&auth_id) {
|
||||||
@ -44,7 +45,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
bus: request.bus_id,
|
bus: request.bus_id,
|
||||||
stream: request.stream,
|
stream: request.stream,
|
||||||
auth: None,
|
auth: None,
|
||||||
session: None,
|
|
||||||
|
context:Context::None,
|
||||||
|
|
||||||
prev:0,
|
prev:0,
|
||||||
next:0,
|
next:0,
|
||||||
@ -70,22 +72,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
// Uninitialize connection
|
// Uninitialize connection
|
||||||
if if let Some(conn) = app.connections.get(qr.id as usize).cloned() {
|
if if let Some(conn) = app.connections.get(qr.id as usize).cloned() {
|
||||||
|
|
||||||
// Disassociate session if present
|
// Disassociate context if present
|
||||||
if let Some(session_token) = conn.session {
|
change_context(&mut app, qr.id, user_id, Context::None).await;
|
||||||
if let Some(session) = app.sessions.get_mut(&session_token) {
|
|
||||||
if user_id == Some(session.p_dawn.user) {
|
|
||||||
session.remove_connection(0, qr.id);
|
|
||||||
}
|
|
||||||
else if user_id == Some(session.p_dusk.user) {
|
|
||||||
session.remove_connection(1, qr.id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session.remove_connection(2, qr.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.send_session_spectators(session_token).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove connection from chain.
|
// Remove connection from chain.
|
||||||
if let Some(auth_id) = conn.auth {
|
if let Some(auth_id) = conn.auth {
|
||||||
@ -168,18 +156,11 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
app.filesystem.handle_create(&handle, user_id).ok();
|
app.filesystem.handle_create(&handle, user_id).ok();
|
||||||
app.user_handle.set(handle.as_bytes(), user_id);
|
app.user_handle.set(handle.as_bytes(), user_id);
|
||||||
|
|
||||||
let user_data = User {
|
let mut user_data = User::new();
|
||||||
id:user_id,
|
user_data.id = user_id;
|
||||||
flags:0,
|
user_data.handle = display_name;
|
||||||
handle:display_name,
|
user_data.secret = secret;
|
||||||
secret,
|
user_data.na_key = salt_id;
|
||||||
na_key:salt_id,
|
|
||||||
|
|
||||||
connection:Some(qr.id),
|
|
||||||
|
|
||||||
status:UserStatus::new(),
|
|
||||||
challenges:Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
app.filesystem.user_create(&user_data).ok();
|
app.filesystem.user_create(&user_data).ok();
|
||||||
|
|
||||||
@ -433,78 +414,20 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
QRPacketData::QSessionList(request) => {
|
QRPacketData::QSessionList(request) => {
|
||||||
app.log.log("Request: Session List");
|
app.log.log("Request: Session List");
|
||||||
|
|
||||||
|
println!("range {} {}", request.filter.start, request.filter.count);
|
||||||
|
|
||||||
|
if let Some(value) = request.filter.is_complete {
|
||||||
|
println!("is_complete {}", value);
|
||||||
|
}
|
||||||
|
if let Some(value) = request.filter.is_live {
|
||||||
|
println!("is_live {}", value);
|
||||||
|
}
|
||||||
|
if let Some(value) = request.filter.is_player {
|
||||||
|
println!("is_player {}", value);
|
||||||
|
}
|
||||||
|
|
||||||
let mut response = PacketSessionListResponse::new();
|
let mut response = PacketSessionListResponse::new();
|
||||||
|
response.records = filter_sessions(&app, user_id, request.filter);
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
let mut next_id = app.session_time.begin();
|
|
||||||
while let Some(id) = next_id {
|
|
||||||
let token = app.session_time.get(id).unwrap();
|
|
||||||
if let Some(session) = app.sessions.get(token) {
|
|
||||||
|
|
||||||
let mut valid = match request.game_state {
|
|
||||||
1 => !session.game.is_complete(),
|
|
||||||
2 => !session.game.is_complete(),
|
|
||||||
3 => session.game.is_complete(),
|
|
||||||
_ => true,
|
|
||||||
};
|
|
||||||
valid &= !request.is_player || Some(session.p_dawn.user) == user_id || Some(session.p_dusk.user) == user_id;
|
|
||||||
valid &= !request.is_live || (session.p_dawn.connections.len() > 0 && session.p_dusk.connections.len() > 0);
|
|
||||||
|
|
||||||
if valid {
|
|
||||||
let player :u8 = if user_id.is_some() {
|
|
||||||
if Some(session.p_dawn.user) == user_id { 1 }
|
|
||||||
else if Some(session.p_dusk.user) == user_id { 2 }
|
|
||||||
else { 0 }
|
|
||||||
} else { 0 };
|
|
||||||
|
|
||||||
let is_turn = player != 0 && (session.game.turn & 1) == player as u16 - 1;
|
|
||||||
let is_complete = (session.game.is_complete() as u8) * (((session.game.turn & 1) == 0) as u8 + 1);
|
|
||||||
|
|
||||||
let dawn_handle = if let Some(user) = app.get_user_by_id(session.p_dawn.user) {
|
|
||||||
user.handle.clone()
|
|
||||||
} else { String::new() };
|
|
||||||
|
|
||||||
let dusk_handle = if let Some(user) = app.get_user_by_id(session.p_dusk.user) {
|
|
||||||
user.handle.clone()
|
|
||||||
} else { String::new() };
|
|
||||||
|
|
||||||
let mut last_move = 0;
|
|
||||||
|
|
||||||
let mut index = session.game.history.len();
|
|
||||||
let mut move_count = 0;
|
|
||||||
while move_count < 4 && index > 0 {
|
|
||||||
let play = session.game.history[index - 1];
|
|
||||||
if play.source <= 2 {
|
|
||||||
last_move <<= 8;
|
|
||||||
last_move |= 0x80 | play.meta as u32;
|
|
||||||
move_count += 1;
|
|
||||||
}
|
|
||||||
index -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
response.records.push(PacketSessionListResponseRecord {
|
|
||||||
token:session.token,
|
|
||||||
handles:[
|
|
||||||
dawn_handle,
|
|
||||||
dusk_handle,
|
|
||||||
],
|
|
||||||
turn:session.game.turn,
|
|
||||||
last_move,
|
|
||||||
viewers:session.connections.len() as u32,
|
|
||||||
player,
|
|
||||||
is_turn,
|
|
||||||
is_complete,
|
|
||||||
});
|
|
||||||
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if count >= 60 { break; }
|
|
||||||
next_id = app.session_time.next(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(QRPacket::new(qr.id, QRPacketData::RSessionList(response)))
|
Some(QRPacket::new(qr.id, QRPacketData::RSessionList(response)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +439,7 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
response.token = request.token;
|
response.token = request.token;
|
||||||
|
|
||||||
// Verify that session exists
|
// Verify that session exists
|
||||||
if let Some(session) = app.sessions.get_mut(&request.token) {
|
if if let Some(session) = app.sessions.get(&request.token) {
|
||||||
|
|
||||||
response.is_complete = session.game.is_complete();
|
response.is_complete = session.game.is_complete();
|
||||||
|
|
||||||
@ -527,7 +450,7 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join game as player
|
// Join game as player
|
||||||
if if request.join {
|
if request.join {
|
||||||
|
|
||||||
// Verify client is authenticated
|
// Verify client is authenticated
|
||||||
if user_id.is_some() {
|
if user_id.is_some() {
|
||||||
@ -545,21 +468,15 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
app.log.log("User spectates session.");
|
app.log.log("User spectates session.");
|
||||||
response.status = STATUS_OK;
|
response.status = STATUS_OK;
|
||||||
true
|
true
|
||||||
} {
|
|
||||||
// Associate session and connection on join
|
|
||||||
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
|
||||||
conn.session = Some(session.token);
|
|
||||||
}
|
}
|
||||||
let mode = if user_id == Some(session.p_dawn.user) {
|
|
||||||
0
|
|
||||||
} else if user_id == Some(session.p_dusk.user) {
|
|
||||||
1
|
|
||||||
} else {
|
} else {
|
||||||
2
|
false
|
||||||
};
|
} {
|
||||||
session.add_connection(mode, qr.id);
|
change_context(&mut app, qr.id, user_id, Context::Game(
|
||||||
app.send_session_spectators(request.token).await;
|
context::Game {
|
||||||
|
token:request.token,
|
||||||
}
|
}
|
||||||
|
)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(QRPacket::new(qr.id, QRPacketData::RSessionView(response)))
|
Some(QRPacket::new(qr.id, QRPacketData::RSessionView(response)))
|
||||||
@ -616,20 +533,11 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
app.log.log("Request: Session Leave");
|
app.log.log("Request: Session Leave");
|
||||||
|
|
||||||
// Verify that session exists.
|
// Verify that session exists.
|
||||||
if let Some(session_token) = session_id {
|
match &context {
|
||||||
if let Some(session) = app.sessions.get_mut(&session_token) {
|
Context::Game(_) => {
|
||||||
if user_id == Some(session.p_dawn.user) {
|
change_context(&mut app, qr.id, user_id, Context::None).await;
|
||||||
session.remove_connection(0, qr.id);
|
|
||||||
}
|
}
|
||||||
else if user_id == Some(session.p_dusk.user) {
|
_ => { }
|
||||||
session.remove_connection(1, qr.id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session.remove_connection(2, qr.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.send_session_spectators(session_token).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(QRPacket::new(0, QRPacketData::None))
|
Some(QRPacket::new(0, QRPacketData::None))
|
||||||
@ -661,8 +569,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
let mut packets = Vec::<QRPacket>::new();
|
let mut packets = Vec::<QRPacket>::new();
|
||||||
let mut response = QRPacketData::None;
|
let mut response = QRPacketData::None;
|
||||||
|
|
||||||
if let Some(sid) = session_id {
|
if let Context::Game(context) = &context {
|
||||||
if let Some(session) = app.sessions.get_mut(&sid) {
|
if let Some(session) = app.sessions.get_mut(&context.token) {
|
||||||
|
|
||||||
match request.data {
|
match request.data {
|
||||||
GameMessageData::PlayMove(turn, from, to)
|
GameMessageData::PlayMove(turn, from, to)
|
||||||
@ -938,9 +846,11 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
};
|
};
|
||||||
session.game.init();
|
session.game.init();
|
||||||
|
|
||||||
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
change_context(&mut app, qr.id, Some(user_id), Context::Game(
|
||||||
conn.session = Some(session.token);
|
context::Game {
|
||||||
|
token:session.token,
|
||||||
}
|
}
|
||||||
|
)).await;
|
||||||
|
|
||||||
session.id = app.filesystem.session_create(&session).unwrap();
|
session.id = app.filesystem.session_create(&session).unwrap();
|
||||||
|
|
||||||
@ -1013,6 +923,31 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
Some(QRPacket::new(qr.id, QRPacketData::RUserList(response)))
|
Some(QRPacket::new(qr.id, QRPacketData::RUserList(response)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserInfo
|
||||||
|
QRPacketData::QUserInfo(request) => {
|
||||||
|
app.log.log("Request: User Info");
|
||||||
|
|
||||||
|
let mut response = PacketUserInfoResponse::new();
|
||||||
|
|
||||||
|
if let Some(uid) = app.user_handle.get(&request.handle.to_lowercase().as_bytes()).cloned() {
|
||||||
|
response.status = STATUS_OK;
|
||||||
|
|
||||||
|
if let Some(user) = app.get_user_by_id(uid) {
|
||||||
|
response.handle = user.handle.clone();
|
||||||
|
response.is_online = user.connection.is_some();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response.status = STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user sessions
|
||||||
|
if response.status == STATUS_OK {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(QRPacket::new(qr.id, QRPacketData::RUserInfo(response)))
|
||||||
|
}
|
||||||
|
|
||||||
// InviteAcquire
|
// InviteAcquire
|
||||||
QRPacketData::QInviteAcquire => {
|
QRPacketData::QInviteAcquire => {
|
||||||
use crate::app::{Invitation, InviteToken};
|
use crate::app::{Invitation, InviteToken};
|
||||||
@ -1146,3 +1081,145 @@ fn generate_game_state(app:&App, session:&Session) -> protocol::PacketGameStateR
|
|||||||
|
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn change_context(app:&mut App, conn_id:u32, user_id:Option<u32>, context:Context)
|
||||||
|
{
|
||||||
|
// Clear existing context
|
||||||
|
if let Some(conn) = app.connections.get(conn_id as usize).cloned() {
|
||||||
|
match conn.context {
|
||||||
|
Context::Game(game) => {
|
||||||
|
if let Some(session) = app.sessions.get_mut(&game.token) {
|
||||||
|
let mode = if user_id == Some(session.p_dawn.user) {
|
||||||
|
0
|
||||||
|
} else if user_id == Some(session.p_dusk.user) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
};
|
||||||
|
session.remove_connection(mode, conn_id);
|
||||||
|
app.send_session_spectators(game.token).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new context
|
||||||
|
if let Some(conn) = app.connections.get_mut(conn_id as usize) {
|
||||||
|
conn.context = context.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
match context {
|
||||||
|
Context::Game(game) => {
|
||||||
|
if let Some(session) = app.sessions.get_mut(&game.token) {
|
||||||
|
let mode = if user_id == Some(session.p_dawn.user) {
|
||||||
|
0
|
||||||
|
} else if user_id == Some(session.p_dusk.user) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
};
|
||||||
|
session.add_connection(mode, conn_id);
|
||||||
|
app.send_session_spectators(game.token).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::protocol::PacketSessionListResponseRecord;
|
||||||
|
fn filter_sessions(app:&App, user_id:Option<u32>, filter:SessionFilter) -> Vec<PacketSessionListResponseRecord>
|
||||||
|
{
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
|
let mut count = 0;
|
||||||
|
let mut next_id = app.session_time.begin();
|
||||||
|
|
||||||
|
// Get first element in filter
|
||||||
|
while index < filter.start {
|
||||||
|
if let Some(id) = next_id {
|
||||||
|
next_id = app.session_time.next(id);
|
||||||
|
index += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather filtered sessions up to filter count
|
||||||
|
while let Some(id) = next_id {
|
||||||
|
if count >= filter.count { break; }
|
||||||
|
|
||||||
|
let token = app.session_time.get(id).unwrap();
|
||||||
|
if let Some(session) = app.sessions.get(token) {
|
||||||
|
|
||||||
|
let mut valid = true;
|
||||||
|
|
||||||
|
valid &= if let Some(is_complete) = filter.is_complete { is_complete == session.game.is_complete() } else { true };
|
||||||
|
valid &= if let Some(is_player) = filter.is_player { is_player == (Some(session.p_dawn.user) == user_id || Some(session.p_dusk.user) == user_id) } else { true };
|
||||||
|
valid &= if let Some(is_live) = filter.is_live { is_live == (session.p_dawn.connections.len() > 0 && session.p_dusk.connections.len() > 0) } else { true };
|
||||||
|
|
||||||
|
for i in 0..filter.player.len() {
|
||||||
|
if let Some(handle) = &filter.player[i] {
|
||||||
|
if let Some(uid) = app.user_handle.get(&handle.as_bytes()).cloned() {
|
||||||
|
valid &= session.p_dawn.user == uid || session.p_dusk.user == uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid {
|
||||||
|
let player :u8 = if user_id.is_some() {
|
||||||
|
if Some(session.p_dawn.user) == user_id { 1 }
|
||||||
|
else if Some(session.p_dusk.user) == user_id { 2 }
|
||||||
|
else { 0 }
|
||||||
|
} else { 0 };
|
||||||
|
|
||||||
|
let is_turn = player != 0 && (session.game.turn & 1) == player as u16 - 1;
|
||||||
|
let is_complete = (session.game.is_complete() as u8) * (((session.game.turn & 1) == 0) as u8 + 1);
|
||||||
|
|
||||||
|
let dawn_handle = if let Some(user) = app.get_user_by_id(session.p_dawn.user) {
|
||||||
|
user.handle.clone()
|
||||||
|
} else { String::new() };
|
||||||
|
|
||||||
|
let dusk_handle = if let Some(user) = app.get_user_by_id(session.p_dusk.user) {
|
||||||
|
user.handle.clone()
|
||||||
|
} else { String::new() };
|
||||||
|
|
||||||
|
let mut last_move = 0;
|
||||||
|
|
||||||
|
let mut index = session.game.history.len();
|
||||||
|
let mut move_count = 0;
|
||||||
|
while move_count < 4 && index > 0 {
|
||||||
|
let play = session.game.history[index - 1];
|
||||||
|
if play.source <= 2 {
|
||||||
|
last_move <<= 8;
|
||||||
|
last_move |= 0x80 | play.meta as u32;
|
||||||
|
move_count += 1;
|
||||||
|
}
|
||||||
|
index -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(PacketSessionListResponseRecord {
|
||||||
|
token:session.token,
|
||||||
|
handles:[
|
||||||
|
dawn_handle,
|
||||||
|
dusk_handle,
|
||||||
|
],
|
||||||
|
turn:session.game.turn,
|
||||||
|
last_move,
|
||||||
|
viewers:session.connections.len() as u32,
|
||||||
|
player,
|
||||||
|
is_turn,
|
||||||
|
is_complete,
|
||||||
|
});
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_id = app.session_time.next(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
@ -32,6 +32,11 @@ pub enum QRPacketData {
|
|||||||
QUserInfo(PacketUserInfo),
|
QUserInfo(PacketUserInfo),
|
||||||
RUserInfo(PacketUserInfoResponse),
|
RUserInfo(PacketUserInfoResponse),
|
||||||
|
|
||||||
|
QAccountInfo(PacketAccountInfo),
|
||||||
|
RAccountInfo(PacketAccountInfoResponse),
|
||||||
|
QAccountUpdate(PacketAccountUpdate),
|
||||||
|
RAccountUpdate(PacketAccountUpdateResponse),
|
||||||
|
|
||||||
QSessionList(PacketSessionList),
|
QSessionList(PacketSessionList),
|
||||||
RSessionList(PacketSessionListResponse),
|
RSessionList(PacketSessionListResponse),
|
||||||
|
|
||||||
|
71
server/src/protocol/packet/account_info.rs
Normal file
71
server/src/protocol/packet/account_info.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use crate::util::pack::{pack_u8, pack_u16};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Packet,
|
||||||
|
PacketSessionListResponseRecord,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PacketAccountInfo {
|
||||||
|
pub secret:Vec<u8>,
|
||||||
|
}
|
||||||
|
impl PacketAccountInfo {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
secret:Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Packet for PacketAccountInfo {
|
||||||
|
type Data = Self;
|
||||||
|
|
||||||
|
fn decode(_data:&Vec<u8>, _index:&mut usize) -> Result<Self::Data, ()>
|
||||||
|
{
|
||||||
|
Ok(Self::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PacketAccountInfoResponse {
|
||||||
|
pub status:u16,
|
||||||
|
pub handle:String,
|
||||||
|
pub is_online:bool,
|
||||||
|
pub history:Vec<PacketSessionListResponseRecord>,
|
||||||
|
}
|
||||||
|
impl PacketAccountInfoResponse {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
status:0,
|
||||||
|
handle:String::new(),
|
||||||
|
is_online:false,
|
||||||
|
history:Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Packet for PacketAccountInfoResponse {
|
||||||
|
type Data = Self;
|
||||||
|
|
||||||
|
fn encode(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let handle_bytes = self.handle.as_bytes().to_vec();
|
||||||
|
|
||||||
|
let flags = self.is_online as u16;
|
||||||
|
|
||||||
|
let mut history_bytes = pack_u16(self.history.len() as u16);
|
||||||
|
for record in &self.history {
|
||||||
|
history_bytes.append(&mut record.encode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[
|
||||||
|
pack_u16(self.status as u16),
|
||||||
|
pack_u16(flags),
|
||||||
|
|
||||||
|
pack_u8(handle_bytes.len() as u8),
|
||||||
|
handle_bytes,
|
||||||
|
|
||||||
|
history_bytes,
|
||||||
|
].concat()
|
||||||
|
}
|
||||||
|
}
|
72
server/src/protocol/packet/account_update.rs
Normal file
72
server/src/protocol/packet/account_update.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use crate::util::pack::{pack_u8, pack_u16};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Packet,
|
||||||
|
PacketSessionListResponseRecord,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PacketAccountUpdate {
|
||||||
|
pub handle:String,
|
||||||
|
|
||||||
|
}
|
||||||
|
impl PacketAccountUpdate {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
handle:String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Packet for PacketAccountUpdate {
|
||||||
|
type Data = Self;
|
||||||
|
|
||||||
|
fn decode(_data:&Vec<u8>, _index:&mut usize) -> Result<Self::Data, ()>
|
||||||
|
{
|
||||||
|
Ok(Self::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PacketAccountUpdateResponse {
|
||||||
|
pub status:u16,
|
||||||
|
pub handle:String,
|
||||||
|
pub is_online:bool,
|
||||||
|
pub history:Vec<PacketSessionListResponseRecord>,
|
||||||
|
}
|
||||||
|
impl PacketAccountUpdateResponse {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
status:0,
|
||||||
|
handle:String::new(),
|
||||||
|
is_online:false,
|
||||||
|
history:Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Packet for PacketAccountUpdateResponse {
|
||||||
|
type Data = Self;
|
||||||
|
|
||||||
|
fn encode(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
let handle_bytes = self.handle.as_bytes().to_vec();
|
||||||
|
|
||||||
|
let flags = self.is_online as u16;
|
||||||
|
|
||||||
|
let mut history_bytes = pack_u16(self.history.len() as u16);
|
||||||
|
for record in &self.history {
|
||||||
|
history_bytes.append(&mut record.encode());
|
||||||
|
}
|
||||||
|
|
||||||
|
[
|
||||||
|
pack_u16(self.status as u16),
|
||||||
|
pack_u16(flags),
|
||||||
|
|
||||||
|
pack_u8(handle_bytes.len() as u8),
|
||||||
|
handle_bytes,
|
||||||
|
|
||||||
|
history_bytes,
|
||||||
|
].concat()
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,9 @@ mod challenge_list; pub use challenge_list::*;
|
|||||||
mod user_list; pub use user_list::*;
|
mod user_list; pub use user_list::*;
|
||||||
mod user_info; pub use user_info::*;
|
mod user_info; pub use user_info::*;
|
||||||
|
|
||||||
|
mod account_info; pub use account_info::*;
|
||||||
|
mod account_update; pub use account_update::*;
|
||||||
|
|
||||||
mod invite_acquire; pub use invite_acquire::*;
|
mod invite_acquire; pub use invite_acquire::*;
|
||||||
mod invite_list; pub use invite_list::*;
|
mod invite_list; pub use invite_list::*;
|
||||||
|
|
||||||
|
@ -1,26 +1,29 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::session::SessionToken,
|
app::session::{SessionToken, SessionFilter},
|
||||||
util::pack::{pack_u16, pack_u32, unpack_u16},
|
util::pack::{pack_u16, pack_u32, unpack_u8, unpack_u16, unpack_u32},
|
||||||
};
|
};
|
||||||
use game::util::mask;
|
|
||||||
|
|
||||||
use super::Packet;
|
use super::Packet;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PacketSessionList {
|
pub struct PacketSessionList {
|
||||||
pub page:u16,
|
pub filter:SessionFilter,
|
||||||
pub game_state:u8,
|
|
||||||
pub is_player:bool,
|
//pub page:u16,
|
||||||
pub is_live:bool,
|
//pub game_state:u8,
|
||||||
|
//pub is_player:bool,
|
||||||
|
//pub is_live:bool,
|
||||||
}
|
}
|
||||||
impl PacketSessionList {
|
impl PacketSessionList {
|
||||||
pub fn new() -> Self
|
pub fn new() -> Self
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
page:0,
|
filter:SessionFilter::new(),
|
||||||
game_state:0,
|
|
||||||
is_player:false,
|
//page:0,
|
||||||
is_live:false,
|
//game_state:0,
|
||||||
|
//is_player:false,
|
||||||
|
//is_live:false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,18 +34,32 @@ impl Packet for PacketSessionList {
|
|||||||
{
|
{
|
||||||
let mut result = Self::new();
|
let mut result = Self::new();
|
||||||
|
|
||||||
/* Read flags
|
if data.len() - *index > 6 {
|
||||||
** 0:[2] - Game state
|
result.filter.start = unpack_u32(data, index) as usize;
|
||||||
** 2:[1] - User is player of session
|
result.filter.count = unpack_u32(data, index) as usize;
|
||||||
** 3:[1] - Both players are online
|
|
||||||
*/
|
|
||||||
if data.len() - *index == 4 {
|
|
||||||
let flags = unpack_u16(data, index);
|
|
||||||
result.game_state = (flags & mask(2, 0) as u16) as u8;
|
|
||||||
result.is_player = (flags & mask(1, 2) as u16) != 0;
|
|
||||||
result.is_live = (flags & mask(1, 3) as u16) != 0;
|
|
||||||
|
|
||||||
result.page = unpack_u16(data, index);
|
let filter_length = unpack_u16(data, index);
|
||||||
|
for _ in 0..filter_length {
|
||||||
|
let code = unpack_u8(data, index);
|
||||||
|
match code {
|
||||||
|
0x00 => { result.filter.is_complete = Some(unpack_u8(data, index) != 0); }
|
||||||
|
0x01 => { result.filter.is_live = Some(unpack_u8(data, index) != 0); }
|
||||||
|
0x02 => { result.filter.is_player = Some(unpack_u8(data, index) != 0); }
|
||||||
|
0x10 => {
|
||||||
|
let handle_length = unpack_u8(data, index) as usize;
|
||||||
|
if data.len() - *index >= handle_length {
|
||||||
|
if let Ok(handle) = String::from_utf8(data[*index..*index+handle_length].to_vec()) {
|
||||||
|
if result.filter.player[0].is_none() {
|
||||||
|
result.filter.player[0] = Some(handle);
|
||||||
|
} else if result.filter.player[1].is_none() {
|
||||||
|
result.filter.player[1] = Some(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::util::pack::{pack_u8, pack_u16};
|
use crate::util::pack::{pack_u8, pack_u16, unpack_u8};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Packet,
|
Packet,
|
||||||
@ -21,9 +21,16 @@ impl PacketUserInfo {
|
|||||||
impl Packet for PacketUserInfo {
|
impl Packet for PacketUserInfo {
|
||||||
type Data = Self;
|
type Data = Self;
|
||||||
|
|
||||||
fn decode(_data:&Vec<u8>, _index:&mut usize) -> Result<Self::Data, ()>
|
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
||||||
{
|
{
|
||||||
Ok(Self::new())
|
let mut result = Self::new();
|
||||||
|
|
||||||
|
let length = unpack_u8(data, index) as usize;
|
||||||
|
if data.len() - *index >= length {
|
||||||
|
result.handle = String::from_utf8(data[*index..*index + length].to_vec()).map_err(|_| ())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use game::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::{
|
app::{
|
||||||
session::{Session, SessionToken, SessionSecret},
|
session::{Session, SessionToken, SessionSecret},
|
||||||
user::{User, UserStatus},
|
user::User,
|
||||||
},
|
},
|
||||||
util::pack::*,
|
util::pack::*,
|
||||||
};
|
};
|
||||||
@ -436,18 +436,14 @@ impl FileSystem {
|
|||||||
|
|
||||||
let handle = String::from_utf8(handle).map_err(|_| ())?;
|
let handle = String::from_utf8(handle).map_err(|_| ())?;
|
||||||
|
|
||||||
Ok(User {
|
let mut user = User::new();
|
||||||
id,
|
user.id = id;
|
||||||
flags,
|
user.flags = flags;
|
||||||
handle,
|
user.handle = handle;
|
||||||
secret,
|
user.secret = secret;
|
||||||
na_key,
|
user.na_key = na_key;
|
||||||
|
|
||||||
connection:None,
|
Ok(user)
|
||||||
|
|
||||||
status:UserStatus::new(),
|
|
||||||
challenges:Vec::new(),
|
|
||||||
})
|
|
||||||
} else { Err(()) }
|
} else { Err(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,13 @@ const OpCode = {
|
|||||||
TestResult :0xFFFF,
|
TestResult :0xFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FilterCode = {
|
||||||
|
IsComplete :0x00,
|
||||||
|
IsLive :0x01,
|
||||||
|
IsPlayer :0x02,
|
||||||
|
Player :0x10,
|
||||||
|
};
|
||||||
|
|
||||||
const GameState = {
|
const GameState = {
|
||||||
Joinable :0x00,
|
Joinable :0x00,
|
||||||
Ongoing :0x01,
|
Ongoing :0x01,
|
||||||
|
6
www/js/filter.js
Normal file
6
www/js/filter.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class Filter {
|
||||||
|
constructor(code, value) {
|
||||||
|
this.code = code;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -779,11 +779,10 @@ const INTERFACE = {
|
|||||||
let message = null;
|
let message = null;
|
||||||
ctx.fillStyle = INTERFACE.Color.Text;
|
ctx.fillStyle = INTERFACE.Color.Text;
|
||||||
|
|
||||||
if(INTERFACE_DATA.Game.auto !== null) {
|
|
||||||
switch(INTERFACE_DATA.Game.auto) {
|
switch(INTERFACE_DATA.Game.auto) {
|
||||||
case 0: message = LANG("cpu") + " " + LANG("dawn"); break;
|
case 1: message = LANG("cpu") + " " + LANG("dawn"); break;
|
||||||
case 1: message = LANG("cpu") + " " + LANG("dusk"); break;
|
case 2: message = LANG("cpu") + " " + LANG("dusk"); break;
|
||||||
}
|
case 3: message = LANG("cpu"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(GAME_DATA.state.code) {
|
switch(GAME_DATA.state.code) {
|
||||||
@ -1233,7 +1232,7 @@ const INTERFACE = {
|
|||||||
board_state: [ ],
|
board_state: [ ],
|
||||||
history: [ ],
|
history: [ ],
|
||||||
history_begin: [ ],
|
history_begin: [ ],
|
||||||
auto: null,
|
auto: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
Ui: {
|
Ui: {
|
||||||
@ -1317,7 +1316,7 @@ const INTERFACE = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
INTERFACE_DATA.Game.auto = null;
|
INTERFACE_DATA.Game.auto = 0;
|
||||||
|
|
||||||
INTERFACE_DATA.Game.history = [ ];
|
INTERFACE_DATA.Game.history = [ ];
|
||||||
for(let i = 0; i < INTERFACE_DATA.Game.history_begin.length; ++i) {
|
for(let i = 0; i < INTERFACE_DATA.Game.history_begin.length; ++i) {
|
||||||
@ -1331,7 +1330,7 @@ const INTERFACE = {
|
|||||||
undo() {
|
undo() {
|
||||||
switch(INTERFACE_DATA.mode) {
|
switch(INTERFACE_DATA.mode) {
|
||||||
case INTERFACE.Mode.Local: {
|
case INTERFACE.Mode.Local: {
|
||||||
INTERFACE_DATA.Game.auto = null;
|
INTERFACE_DATA.Game.auto = 0;
|
||||||
if(INTERFACE_DATA.Game.history.length > 0) {
|
if(INTERFACE_DATA.Game.history.length > 0) {
|
||||||
INTERFACE_DATA.Replay.turn = INTERFACE_DATA.Game.history.length + 1;
|
INTERFACE_DATA.Replay.turn = INTERFACE_DATA.Game.history.length + 1;
|
||||||
INTERFACE_DATA.Game.history.pop();
|
INTERFACE_DATA.Game.history.pop();
|
||||||
@ -1501,7 +1500,7 @@ const INTERFACE = {
|
|||||||
case INTERFACE.Mode.Local: {
|
case INTERFACE.Mode.Local: {
|
||||||
INTERFACE.history_push(play, true);
|
INTERFACE.history_push(play, true);
|
||||||
|
|
||||||
if(INTERFACE_DATA.Game.auto !== null && INTERFACE_DATA.Game.auto == (GAME_DATA.turn & 1)) {
|
if((INTERFACE_DATA.Game.auto & (1 << (GAME_DATA.turn & 1))) != 0) {
|
||||||
setTimeout(INTERFACE.auto_play, 1000);
|
setTimeout(INTERFACE.auto_play, 1000);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@ -1676,23 +1675,34 @@ const INTERFACE = {
|
|||||||
|
|
||||||
|
|
||||||
auto() {
|
auto() {
|
||||||
if(INTERFACE_DATA.Game.auto === null) {
|
let bit = 1 << (INTERFACE_DATA.rotate ^ 1);
|
||||||
INTERFACE_DATA.Game.auto = INTERFACE_DATA.rotate ^ 1;
|
if((INTERFACE_DATA.Game.auto & bit) == 0) {
|
||||||
|
INTERFACE_DATA.Game.auto |= bit;
|
||||||
setTimeout(INTERFACE.auto_play, 500);
|
setTimeout(INTERFACE.auto_play, 500);
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.Game.auto = null;
|
INTERFACE_DATA.Game.auto &= ~bit;
|
||||||
}
|
}
|
||||||
INTERFACE.game_step();
|
INTERFACE.game_step();
|
||||||
},
|
},
|
||||||
|
|
||||||
auto_play() {
|
auto_play() {
|
||||||
if(INTERFACE_DATA.Game.auto !== (GAME_DATA.turn & 1) || GAME_DATA.state.checkmate) { return; }
|
let bit = 1 << (GAME_DATA.turn & 1);
|
||||||
|
if((INTERFACE_DATA.Game.auto & bit) == 0 || GAME_DATA.state.checkmate) { return; }
|
||||||
|
|
||||||
function state_score(state, player) {
|
function state_score(state, player) {
|
||||||
let score = 0;
|
let score = 0;
|
||||||
let opponent = player ^ 1;
|
let opponent = player ^ 1;
|
||||||
let turn = (state.turn & 1);
|
let turn = (state.turn & 1);
|
||||||
|
|
||||||
|
if(state.state.checkmate) {
|
||||||
|
if(turn == player) { score -= 1000; }
|
||||||
|
else { score += 1000; }
|
||||||
|
} else {
|
||||||
|
if(state.state.check != 0) {
|
||||||
|
if(turn == player) { score -= 20; }
|
||||||
|
else { score += 1; }
|
||||||
|
}
|
||||||
|
|
||||||
for(let i = 0; i < state.board.tiles.length; ++i) {
|
for(let i = 0; i < state.board.tiles.length; ++i) {
|
||||||
let tile = state.board.tiles[i];
|
let tile = state.board.tiles[i];
|
||||||
score += Math.floor((tile.threaten[player] - tile.threaten[opponent]) / 2);
|
score += Math.floor((tile.threaten[player] - tile.threaten[opponent]) / 2);
|
||||||
@ -1738,14 +1748,6 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
score += Math.floor(extent_score / 3);
|
score += Math.floor(extent_score / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state.state.check != 0) {
|
|
||||||
if(turn == player) { score -= 20; }
|
|
||||||
else { score += 1; }
|
|
||||||
}
|
|
||||||
if(state.state.checkmate) {
|
|
||||||
if(turn == player) { score -= 1000; }
|
|
||||||
else { score += 1000; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
|
@ -22,6 +22,7 @@ LANGUAGE.Terms = {
|
|||||||
reconnect: new LANGUAGE.Term( "Reconnect", "再接続" ),
|
reconnect: new LANGUAGE.Term( "Reconnect", "再接続" ),
|
||||||
register: new LANGUAGE.Term( "Register", "登録" ),
|
register: new LANGUAGE.Term( "Register", "登録" ),
|
||||||
login: new LANGUAGE.Term( "Log In", "ログイン" ),
|
login: new LANGUAGE.Term( "Log In", "ログイン" ),
|
||||||
|
auth: new LANGUAGE.Term( "Authenticate", "認証する" ),
|
||||||
|
|
||||||
challenge: new LANGUAGE.Term( "Challenge", "挑戦" ),
|
challenge: new LANGUAGE.Term( "Challenge", "挑戦" ),
|
||||||
|
|
||||||
|
@ -392,6 +392,8 @@ const SCENES = {
|
|||||||
table.appendChild(UI.session_table(this.data));
|
table.appendChild(UI.session_table(this.data));
|
||||||
UI.maincontent(table);
|
UI.maincontent(table);
|
||||||
|
|
||||||
|
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||||
|
|
||||||
history.pushState(null, "Dzura", "/");
|
history.pushState(null, "Dzura", "/");
|
||||||
} else {
|
} else {
|
||||||
SCENE.load(SCENES.Offline);
|
SCENE.load(SCENES.Offline);
|
||||||
@ -399,7 +401,9 @@ const SCENES = {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
refresh() {
|
refresh() {
|
||||||
MESSAGE_SESSION_LIST(this.page, 2, false, false);
|
MESSAGE_SESSION_LIST(this.page, [
|
||||||
|
filter(FilterCode.IsComplete, false),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
/*message(code, data) {
|
/*message(code, data) {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
@ -466,11 +470,16 @@ const SCENES = {
|
|||||||
table.appendChild(UI.session_table(this.data));
|
table.appendChild(UI.session_table(this.data));
|
||||||
UI.maincontent(table);
|
UI.maincontent(table);
|
||||||
|
|
||||||
|
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||||
|
|
||||||
history.pushState(null, "Dzura - Continue", "/continue/");
|
history.pushState(null, "Dzura - Continue", "/continue/");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
refresh() {
|
refresh() {
|
||||||
MESSAGE_SESSION_LIST(this.page, 2, true, false);
|
MESSAGE_SESSION_LIST(this.page, [
|
||||||
|
filter(FilterCode.IsComplete, false),
|
||||||
|
filter(FilterCode.IsPlayer, true),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
/*message(code, data) {
|
/*message(code, data) {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
@ -535,11 +544,16 @@ const SCENES = {
|
|||||||
table.appendChild(UI.session_table(this.data));
|
table.appendChild(UI.session_table(this.data));
|
||||||
UI.maincontent(table);
|
UI.maincontent(table);
|
||||||
|
|
||||||
|
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||||
|
|
||||||
history.pushState(null, "Dzura - Live", "/live/");
|
history.pushState(null, "Dzura - Live", "/live/");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
refresh() {
|
refresh() {
|
||||||
MESSAGE_SESSION_LIST(this.page, 2, false, true);
|
MESSAGE_SESSION_LIST(this.page, [
|
||||||
|
filter(FilterCode.IsComplete, false),
|
||||||
|
filter(FilterCode.IsLive, true),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
/*message(code, data) {
|
/*message(code, data) {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
@ -604,13 +618,17 @@ const SCENES = {
|
|||||||
table.appendChild(UI.session_table_history(this.data));
|
table.appendChild(UI.session_table_history(this.data));
|
||||||
UI.maincontent(table);
|
UI.maincontent(table);
|
||||||
|
|
||||||
|
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||||
|
|
||||||
history.pushState(null, "Dzura - History", "/history/");
|
history.pushState(null, "Dzura - History", "/history/");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
refresh() {
|
refresh() {
|
||||||
MESSAGE_SESSION_LIST(this.page, 3, false, false);
|
MESSAGE_SESSION_LIST(this.page, [
|
||||||
|
filter(FilterCode.IsComplete, true),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
/*message(code, data) {
|
message(code, data) {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case OpCode.SessionList: {
|
case OpCode.SessionList: {
|
||||||
let table = document.getElementById("content");
|
let table = document.getElementById("content");
|
||||||
@ -622,7 +640,7 @@ const SCENES = {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
disconnect() {
|
disconnect() {
|
||||||
SCENE.load(SCENES.Offline);
|
SCENE.load(SCENES.Offline);
|
||||||
}
|
}
|
||||||
@ -708,18 +726,18 @@ const SCENES = {
|
|||||||
};
|
};
|
||||||
this.history = [ ];
|
this.history = [ ];
|
||||||
}
|
}
|
||||||
/*preload(data) {
|
preload(data) {
|
||||||
this.data.handle = data.handle;
|
this.data.handle = data.handle;
|
||||||
MESSAGE_COMPOSE([
|
MESSAGE_COMPOSE([
|
||||||
PACK.u16(OpCode.UserInfo),
|
PACK.u16(OpCode.UserInfo),
|
||||||
PACK.string(this.data.handle, PACK.u8),
|
PACK.string(this.data.handle, PACK.u8),
|
||||||
]);
|
]);
|
||||||
return true;
|
return true;
|
||||||
}*/
|
}
|
||||||
load(msg) {
|
load(msg) {
|
||||||
/*if(msg.code != OpCode.UserInfo) {
|
if(msg.code != OpCode.UserInfo) {
|
||||||
return null;
|
return null;
|
||||||
}*/
|
}
|
||||||
this.handle = msg.handle;
|
this.handle = msg.handle;
|
||||||
|
|
||||||
UI.mainmenu_account(this.handle, "profile");
|
UI.mainmenu_account(this.handle, "profile");
|
||||||
@ -779,8 +797,51 @@ const SCENES = {
|
|||||||
UI.mainnav(buttons_left, buttons_right);
|
UI.mainnav(buttons_left, buttons_right);
|
||||||
|
|
||||||
// Main Content
|
// Main Content
|
||||||
|
let container = document.createElement("section");
|
||||||
|
let form = document.createElement("form");
|
||||||
|
|
||||||
history.pushState(null, "Dzura - About", "/u/" + CONTEXT.Auth.handle);
|
form.appendChild(UI.table(null, [
|
||||||
|
[ UI.label(LANG("secret"), "secret"), UI.password("secret") ],
|
||||||
|
]));
|
||||||
|
|
||||||
|
let button = UI.submit(LANG("auth"));
|
||||||
|
button.setAttribute("id", "submit");
|
||||||
|
form.appendChild(button);
|
||||||
|
|
||||||
|
form.addEventListener("submit", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
/*let secret = document.getElementById("secret");
|
||||||
|
|
||||||
|
secret.removeAttribute("class");
|
||||||
|
event.target.removeAttribute("class");
|
||||||
|
|
||||||
|
if(handle.value.length > 0 && handle.value.length <= 24 && secret.value.length > 0) {
|
||||||
|
event.target.setAttribute("disabled", "");
|
||||||
|
|
||||||
|
let enc = new TextEncoder();
|
||||||
|
let enc_secret = enc.encode(secret.value);
|
||||||
|
|
||||||
|
MESSAGE_COMPOSE([
|
||||||
|
PACK.u16(OpCode.Authenticate),
|
||||||
|
PACK.u16(enc_handle.length),
|
||||||
|
enc_handle,
|
||||||
|
PACK.u16(enc_secret.length),
|
||||||
|
enc_secret,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
if(handle.value.length == 0 || handle.value.length > 24) { handle.setAttribute("class", "error"); }
|
||||||
|
if(secret.value.length == 0) { secret.setAttribute("class", "error"); }
|
||||||
|
}*/
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(form);
|
||||||
|
MAIN.appendChild(container);
|
||||||
|
MAIN.setAttribute("class", "form");
|
||||||
|
|
||||||
|
document.getElementById("secret").focus();
|
||||||
|
|
||||||
|
history.pushState(null, "Dzura - Account", "/u/" + CONTEXT.Auth.handle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ function RECONNECT() {
|
|||||||
console.log("Websocket closed.");
|
console.log("Websocket closed.");
|
||||||
SOCKET = null;
|
SOCKET = null;
|
||||||
if(SCENE.disconnect !== undefined) { SCENE.disconnect(); }
|
if(SCENE.disconnect !== undefined) { SCENE.disconnect(); }
|
||||||
|
BADGE_UPDATE(false);
|
||||||
RECONNECT();
|
RECONNECT();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -597,17 +598,39 @@ function MESSAGE_COMPOSE(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function MESSAGE_SESSION_LIST(page, game_state, is_player, is_live) {
|
function MESSAGE_SESSION_LIST(page, filters) {
|
||||||
let flags = 0;
|
let request = [
|
||||||
flags |= game_state;
|
|
||||||
flags |= (+is_player) << 2;
|
|
||||||
flags |= (+is_live) << 3;
|
|
||||||
|
|
||||||
MESSAGE_COMPOSE([
|
|
||||||
PACK.u16(OpCode.SessionList),
|
PACK.u16(OpCode.SessionList),
|
||||||
PACK.u16(flags),
|
PACK.u32((page - 1) * 30),
|
||||||
PACK.u16(page),
|
PACK.u32(30),
|
||||||
]);
|
PACK.u16(filters.length),
|
||||||
|
];
|
||||||
|
|
||||||
|
for(let i = 0; i < filters.length; ++i) {
|
||||||
|
switch(filters[i].code) {
|
||||||
|
case FilterCode.IsComplete: {
|
||||||
|
request.push(PACK.u8(FilterCode.IsComplete));
|
||||||
|
request.push(PACK.u8(filters[i].value));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FilterCode.IsLive: {
|
||||||
|
request.push(PACK.u8(FilterCode.IsLive));
|
||||||
|
request.push(PACK.u8(filters[i].value));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FilterCode.IsPlayer: {
|
||||||
|
request.push(PACK.u8(FilterCode.IsPlayer));
|
||||||
|
request.push(PACK.u8(filters[i].value));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FilterCode.Player: {
|
||||||
|
request.push(PACK.u8(FilterCode.IsComplete));
|
||||||
|
request.push(PACK.string(filters[i].value, PACK.u8));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MESSAGE_COMPOSE(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MESSAGE_SESSION_VIEW(token, player) {
|
function MESSAGE_SESSION_VIEW(token, player) {
|
||||||
|
37
www/js/ui.js
37
www/js/ui.js
@ -320,43 +320,6 @@ const UI = {
|
|||||||
return tbody;
|
return tbody;
|
||||||
},
|
},
|
||||||
|
|
||||||
/*session_table_join(records) {
|
|
||||||
let rows = [ ];
|
|
||||||
|
|
||||||
for(let r = 0; r < records.length; ++r) {
|
|
||||||
let buttons = [ ];
|
|
||||||
let join_callback = function() {
|
|
||||||
SCENE.load(SCENES.Game, {
|
|
||||||
token:this.token,
|
|
||||||
mode:INTERFACE.Mode.Player,
|
|
||||||
});
|
|
||||||
MESSAGE_SESSION_VIEW(this.token, true);
|
|
||||||
};
|
|
||||||
join_callback = join_callback.bind({token: records[r].token});
|
|
||||||
|
|
||||||
if(records[r].player) {
|
|
||||||
buttons.push(UI.button("View", join_callback));
|
|
||||||
} else {
|
|
||||||
buttons.push(UI.button("Join", join_callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
let host = UI.text(records[r].dawn);
|
|
||||||
if(records[r].dawn == "") { dawn = UI.span([UI.text("Vacant")], "text-system"); }
|
|
||||||
|
|
||||||
rows.push([
|
|
||||||
host,
|
|
||||||
buttons,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tbody = UI.table_content(
|
|
||||||
[ "Host", "" ],
|
|
||||||
rows,
|
|
||||||
);
|
|
||||||
|
|
||||||
return tbody;
|
|
||||||
},*/
|
|
||||||
|
|
||||||
session_table_history(records) {
|
session_table_history(records) {
|
||||||
let rows = [ ];
|
let rows = [ ];
|
||||||
|
|
||||||
|
@ -290,3 +290,10 @@ const VALID = {
|
|||||||
return reg.test(text);
|
return reg.test(text);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function filter(code, value) {
|
||||||
|
return {
|
||||||
|
code: code,
|
||||||
|
value: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user