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::{
|
||||
authentication::AuthToken,
|
||||
session::SessionToken,
|
||||
context::Context,
|
||||
};
|
||||
|
||||
type StreamType = Arc<RwLock<SplitSink<WebSocketStream<TokioIo<Upgraded>>, Message>>>;
|
||||
@ -17,7 +17,8 @@ pub struct Connection {
|
||||
pub bus:u32,
|
||||
pub stream:StreamType,
|
||||
pub auth:Option<AuthToken>,
|
||||
pub session:Option<SessionToken>,
|
||||
|
||||
pub context:Context,
|
||||
|
||||
pub prev:u32,
|
||||
pub next:u32,
|
||||
|
@ -1,3 +1,18 @@
|
||||
use super::session::SessionToken;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Context {
|
||||
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;
|
||||
|
||||
mod filter; pub use filter::SessionFilter;
|
||||
|
||||
pub type SessionToken = [u8; 8];
|
||||
pub type SessionSecret = [u8; 8];
|
||||
|
@ -18,6 +18,15 @@ pub struct UserStatistics {
|
||||
pub games_played:u32,
|
||||
pub games_won:u32,
|
||||
}
|
||||
impl UserStatistics {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
games_played:0,
|
||||
games_won:0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct User {
|
||||
@ -30,5 +39,26 @@ pub struct User {
|
||||
pub connection:Option<u32>,
|
||||
|
||||
pub status:UserStatus,
|
||||
pub statistics:UserStatistics,
|
||||
|
||||
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::{
|
||||
authentication::Authentication,
|
||||
connection::Connection,
|
||||
user::{User, UserStatus},
|
||||
user::User,
|
||||
App,
|
||||
session::Session,
|
||||
session::{Session, SessionFilter},
|
||||
context::{self, Context},
|
||||
},
|
||||
protocol,
|
||||
};
|
||||
@ -27,9 +28,9 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
let qr = packet.data;
|
||||
|
||||
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) {
|
||||
session_id = conn.session;
|
||||
context = conn.context.clone();
|
||||
|
||||
if let Some(auth_id) = conn.auth {
|
||||
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,
|
||||
stream: request.stream,
|
||||
auth: None,
|
||||
session: None,
|
||||
|
||||
context:Context::None,
|
||||
|
||||
prev:0,
|
||||
next:0,
|
||||
@ -70,22 +72,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
// Uninitialize connection
|
||||
if if let Some(conn) = app.connections.get(qr.id as usize).cloned() {
|
||||
|
||||
// Disassociate session if present
|
||||
if let Some(session_token) = conn.session {
|
||||
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;
|
||||
}
|
||||
// Disassociate context if present
|
||||
change_context(&mut app, qr.id, user_id, Context::None).await;
|
||||
|
||||
// Remove connection from chain.
|
||||
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.user_handle.set(handle.as_bytes(), user_id);
|
||||
|
||||
let user_data = User {
|
||||
id:user_id,
|
||||
flags:0,
|
||||
handle:display_name,
|
||||
secret,
|
||||
na_key:salt_id,
|
||||
|
||||
connection:Some(qr.id),
|
||||
|
||||
status:UserStatus::new(),
|
||||
challenges:Vec::new(),
|
||||
};
|
||||
let mut user_data = User::new();
|
||||
user_data.id = user_id;
|
||||
user_data.handle = display_name;
|
||||
user_data.secret = secret;
|
||||
user_data.na_key = salt_id;
|
||||
|
||||
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) => {
|
||||
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 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);
|
||||
}
|
||||
|
||||
response.records = filter_sessions(&app, user_id, request.filter);
|
||||
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;
|
||||
|
||||
// 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();
|
||||
|
||||
@ -527,7 +450,7 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
}
|
||||
|
||||
// Join game as player
|
||||
if if request.join {
|
||||
if request.join {
|
||||
|
||||
// Verify client is authenticated
|
||||
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.");
|
||||
response.status = STATUS_OK;
|
||||
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 {
|
||||
2
|
||||
};
|
||||
session.add_connection(mode, qr.id);
|
||||
app.send_session_spectators(request.token).await;
|
||||
false
|
||||
} {
|
||||
change_context(&mut app, qr.id, user_id, Context::Game(
|
||||
context::Game {
|
||||
token:request.token,
|
||||
}
|
||||
)).await;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
// Verify that session exists.
|
||||
if let Some(session_token) = session_id {
|
||||
if let Some(session) = app.sessions.get_mut(&session_token) {
|
||||
if user_id == Some(session.p_dawn.user) {
|
||||
session.remove_connection(0, qr.id);
|
||||
match &context {
|
||||
Context::Game(_) => {
|
||||
change_context(&mut app, qr.id, user_id, Context::None).await;
|
||||
}
|
||||
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))
|
||||
@ -661,8 +569,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
let mut packets = Vec::<QRPacket>::new();
|
||||
let mut response = QRPacketData::None;
|
||||
|
||||
if let Some(sid) = session_id {
|
||||
if let Some(session) = app.sessions.get_mut(&sid) {
|
||||
if let Context::Game(context) = &context {
|
||||
if let Some(session) = app.sessions.get_mut(&context.token) {
|
||||
|
||||
match request.data {
|
||||
GameMessageData::PlayMove(turn, from, to)
|
||||
@ -938,9 +846,11 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
};
|
||||
session.game.init();
|
||||
|
||||
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
||||
conn.session = Some(session.token);
|
||||
change_context(&mut app, qr.id, Some(user_id), Context::Game(
|
||||
context::Game {
|
||||
token:session.token,
|
||||
}
|
||||
)).await;
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
// 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
|
||||
QRPacketData::QInviteAcquire => {
|
||||
use crate::app::{Invitation, InviteToken};
|
||||
@ -1146,3 +1081,145 @@ fn generate_game_state(app:&App, session:&Session) -> protocol::PacketGameStateR
|
||||
|
||||
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),
|
||||
RUserInfo(PacketUserInfoResponse),
|
||||
|
||||
QAccountInfo(PacketAccountInfo),
|
||||
RAccountInfo(PacketAccountInfoResponse),
|
||||
QAccountUpdate(PacketAccountUpdate),
|
||||
RAccountUpdate(PacketAccountUpdateResponse),
|
||||
|
||||
QSessionList(PacketSessionList),
|
||||
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_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_list; pub use invite_list::*;
|
||||
|
||||
|
@ -1,26 +1,29 @@
|
||||
use crate::{
|
||||
app::session::SessionToken,
|
||||
util::pack::{pack_u16, pack_u32, unpack_u16},
|
||||
app::session::{SessionToken, SessionFilter},
|
||||
util::pack::{pack_u16, pack_u32, unpack_u8, unpack_u16, unpack_u32},
|
||||
};
|
||||
use game::util::mask;
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketSessionList {
|
||||
pub page:u16,
|
||||
pub game_state:u8,
|
||||
pub is_player:bool,
|
||||
pub is_live:bool,
|
||||
pub filter:SessionFilter,
|
||||
|
||||
//pub page:u16,
|
||||
//pub game_state:u8,
|
||||
//pub is_player:bool,
|
||||
//pub is_live:bool,
|
||||
}
|
||||
impl PacketSessionList {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
page:0,
|
||||
game_state:0,
|
||||
is_player:false,
|
||||
is_live:false,
|
||||
filter:SessionFilter::new(),
|
||||
|
||||
//page:0,
|
||||
//game_state:0,
|
||||
//is_player:false,
|
||||
//is_live:false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,18 +34,32 @@ impl Packet for PacketSessionList {
|
||||
{
|
||||
let mut result = Self::new();
|
||||
|
||||
/* Read flags
|
||||
** 0:[2] - Game state
|
||||
** 2:[1] - User is player of session
|
||||
** 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;
|
||||
if data.len() - *index > 6 {
|
||||
result.filter.start = unpack_u32(data, index) as usize;
|
||||
result.filter.count = unpack_u32(data, index) as usize;
|
||||
|
||||
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)
|
||||
} 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::{
|
||||
Packet,
|
||||
@ -21,9 +21,16 @@ impl PacketUserInfo {
|
||||
impl Packet for PacketUserInfo {
|
||||
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::{
|
||||
app::{
|
||||
session::{Session, SessionToken, SessionSecret},
|
||||
user::{User, UserStatus},
|
||||
user::User,
|
||||
},
|
||||
util::pack::*,
|
||||
};
|
||||
@ -436,18 +436,14 @@ impl FileSystem {
|
||||
|
||||
let handle = String::from_utf8(handle).map_err(|_| ())?;
|
||||
|
||||
Ok(User {
|
||||
id,
|
||||
flags,
|
||||
handle,
|
||||
secret,
|
||||
na_key,
|
||||
let mut user = User::new();
|
||||
user.id = id;
|
||||
user.flags = flags;
|
||||
user.handle = handle;
|
||||
user.secret = secret;
|
||||
user.na_key = na_key;
|
||||
|
||||
connection:None,
|
||||
|
||||
status:UserStatus::new(),
|
||||
challenges:Vec::new(),
|
||||
})
|
||||
Ok(user)
|
||||
} else { Err(()) }
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,13 @@ const OpCode = {
|
||||
TestResult :0xFFFF,
|
||||
};
|
||||
|
||||
const FilterCode = {
|
||||
IsComplete :0x00,
|
||||
IsLive :0x01,
|
||||
IsPlayer :0x02,
|
||||
Player :0x10,
|
||||
};
|
||||
|
||||
const GameState = {
|
||||
Joinable :0x00,
|
||||
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;
|
||||
ctx.fillStyle = INTERFACE.Color.Text;
|
||||
|
||||
if(INTERFACE_DATA.Game.auto !== null) {
|
||||
switch(INTERFACE_DATA.Game.auto) {
|
||||
case 0: message = LANG("cpu") + " " + LANG("dawn"); break;
|
||||
case 1: message = LANG("cpu") + " " + LANG("dusk"); break;
|
||||
}
|
||||
case 1: message = LANG("cpu") + " " + LANG("dawn"); break;
|
||||
case 2: message = LANG("cpu") + " " + LANG("dusk"); break;
|
||||
case 3: message = LANG("cpu"); break;
|
||||
}
|
||||
|
||||
switch(GAME_DATA.state.code) {
|
||||
@ -1233,7 +1232,7 @@ const INTERFACE = {
|
||||
board_state: [ ],
|
||||
history: [ ],
|
||||
history_begin: [ ],
|
||||
auto: null,
|
||||
auto: 0,
|
||||
},
|
||||
|
||||
Ui: {
|
||||
@ -1317,7 +1316,7 @@ const INTERFACE = {
|
||||
},
|
||||
|
||||
reset() {
|
||||
INTERFACE_DATA.Game.auto = null;
|
||||
INTERFACE_DATA.Game.auto = 0;
|
||||
|
||||
INTERFACE_DATA.Game.history = [ ];
|
||||
for(let i = 0; i < INTERFACE_DATA.Game.history_begin.length; ++i) {
|
||||
@ -1331,7 +1330,7 @@ const INTERFACE = {
|
||||
undo() {
|
||||
switch(INTERFACE_DATA.mode) {
|
||||
case INTERFACE.Mode.Local: {
|
||||
INTERFACE_DATA.Game.auto = null;
|
||||
INTERFACE_DATA.Game.auto = 0;
|
||||
if(INTERFACE_DATA.Game.history.length > 0) {
|
||||
INTERFACE_DATA.Replay.turn = INTERFACE_DATA.Game.history.length + 1;
|
||||
INTERFACE_DATA.Game.history.pop();
|
||||
@ -1501,7 +1500,7 @@ const INTERFACE = {
|
||||
case INTERFACE.Mode.Local: {
|
||||
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);
|
||||
}
|
||||
} break;
|
||||
@ -1676,23 +1675,34 @@ const INTERFACE = {
|
||||
|
||||
|
||||
auto() {
|
||||
if(INTERFACE_DATA.Game.auto === null) {
|
||||
INTERFACE_DATA.Game.auto = INTERFACE_DATA.rotate ^ 1;
|
||||
let bit = 1 << (INTERFACE_DATA.rotate ^ 1);
|
||||
if((INTERFACE_DATA.Game.auto & bit) == 0) {
|
||||
INTERFACE_DATA.Game.auto |= bit;
|
||||
setTimeout(INTERFACE.auto_play, 500);
|
||||
} else {
|
||||
INTERFACE_DATA.Game.auto = null;
|
||||
INTERFACE_DATA.Game.auto &= ~bit;
|
||||
}
|
||||
INTERFACE.game_step();
|
||||
},
|
||||
|
||||
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) {
|
||||
let score = 0;
|
||||
let opponent = player ^ 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) {
|
||||
let tile = state.board.tiles[i];
|
||||
score += Math.floor((tile.threaten[player] - tile.threaten[opponent]) / 2);
|
||||
@ -1738,14 +1748,6 @@ const INTERFACE = {
|
||||
}
|
||||
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;
|
||||
|
@ -22,6 +22,7 @@ LANGUAGE.Terms = {
|
||||
reconnect: new LANGUAGE.Term( "Reconnect", "再接続" ),
|
||||
register: new LANGUAGE.Term( "Register", "登録" ),
|
||||
login: new LANGUAGE.Term( "Log In", "ログイン" ),
|
||||
auth: new LANGUAGE.Term( "Authenticate", "認証する" ),
|
||||
|
||||
challenge: new LANGUAGE.Term( "Challenge", "挑戦" ),
|
||||
|
||||
|
@ -392,6 +392,8 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table(this.data));
|
||||
UI.maincontent(table);
|
||||
|
||||
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||
|
||||
history.pushState(null, "Dzura", "/");
|
||||
} else {
|
||||
SCENE.load(SCENES.Offline);
|
||||
@ -399,7 +401,9 @@ const SCENES = {
|
||||
return true;
|
||||
}
|
||||
refresh() {
|
||||
MESSAGE_SESSION_LIST(this.page, 2, false, false);
|
||||
MESSAGE_SESSION_LIST(this.page, [
|
||||
filter(FilterCode.IsComplete, false),
|
||||
]);
|
||||
}
|
||||
/*message(code, data) {
|
||||
switch(code) {
|
||||
@ -466,11 +470,16 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table(this.data));
|
||||
UI.maincontent(table);
|
||||
|
||||
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||
|
||||
history.pushState(null, "Dzura - Continue", "/continue/");
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
switch(code) {
|
||||
@ -535,11 +544,16 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table(this.data));
|
||||
UI.maincontent(table);
|
||||
|
||||
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||
|
||||
history.pushState(null, "Dzura - Live", "/live/");
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
switch(code) {
|
||||
@ -604,13 +618,17 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table_history(this.data));
|
||||
UI.maincontent(table);
|
||||
|
||||
UI.page_indicator((this.data.length > 0)? 1 : 0, this.data.length, this.data.length);
|
||||
|
||||
history.pushState(null, "Dzura - History", "/history/");
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
case OpCode.SessionList: {
|
||||
let table = document.getElementById("content");
|
||||
@ -622,7 +640,7 @@ const SCENES = {
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
disconnect() {
|
||||
SCENE.load(SCENES.Offline);
|
||||
}
|
||||
@ -708,18 +726,18 @@ const SCENES = {
|
||||
};
|
||||
this.history = [ ];
|
||||
}
|
||||
/*preload(data) {
|
||||
preload(data) {
|
||||
this.data.handle = data.handle;
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.UserInfo),
|
||||
PACK.string(this.data.handle, PACK.u8),
|
||||
]);
|
||||
return true;
|
||||
}*/
|
||||
}
|
||||
load(msg) {
|
||||
/*if(msg.code != OpCode.UserInfo) {
|
||||
if(msg.code != OpCode.UserInfo) {
|
||||
return null;
|
||||
}*/
|
||||
}
|
||||
this.handle = msg.handle;
|
||||
|
||||
UI.mainmenu_account(this.handle, "profile");
|
||||
@ -779,8 +797,51 @@ const SCENES = {
|
||||
UI.mainnav(buttons_left, buttons_right);
|
||||
|
||||
// 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;
|
||||
}
|
||||
},
|
||||
|
@ -18,6 +18,7 @@ function RECONNECT() {
|
||||
console.log("Websocket closed.");
|
||||
SOCKET = null;
|
||||
if(SCENE.disconnect !== undefined) { SCENE.disconnect(); }
|
||||
BADGE_UPDATE(false);
|
||||
RECONNECT();
|
||||
});
|
||||
|
||||
@ -597,17 +598,39 @@ function MESSAGE_COMPOSE(data) {
|
||||
}
|
||||
}
|
||||
|
||||
function MESSAGE_SESSION_LIST(page, game_state, is_player, is_live) {
|
||||
let flags = 0;
|
||||
flags |= game_state;
|
||||
flags |= (+is_player) << 2;
|
||||
flags |= (+is_live) << 3;
|
||||
|
||||
MESSAGE_COMPOSE([
|
||||
function MESSAGE_SESSION_LIST(page, filters) {
|
||||
let request = [
|
||||
PACK.u16(OpCode.SessionList),
|
||||
PACK.u16(flags),
|
||||
PACK.u16(page),
|
||||
]);
|
||||
PACK.u32((page - 1) * 30),
|
||||
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) {
|
||||
|
37
www/js/ui.js
37
www/js/ui.js
@ -320,43 +320,6 @@ const UI = {
|
||||
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) {
|
||||
let rows = [ ];
|
||||
|
||||
|
@ -290,3 +290,10 @@ const VALID = {
|
||||
return reg.test(text);
|
||||
},
|
||||
};
|
||||
|
||||
function filter(code, value) {
|
||||
return {
|
||||
code: code,
|
||||
value: value,
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user