did some server work, its still shit tho
This commit is contained in:
parent
9895a4797f
commit
50976d0f3f
9 changed files with 212 additions and 68 deletions
18
readme.md
18
readme.md
|
@ -1,5 +1,23 @@
|
||||||
# WTF how do i implement a game???
|
# WTF how do i implement a game???
|
||||||
|
|
||||||
|
## Short range todo list to keep me going
|
||||||
|
|
||||||
|
[x] Move tokens into `Game` from `GameServer`
|
||||||
|
[x] Move login into `GameServer` from the web server socket handler (and prevent multiple logins for the same user)
|
||||||
|
[ ] Add admin settings panel
|
||||||
|
[ ] Only show to admins
|
||||||
|
[ ] Adding new players (as in, login stuff, but this will be unimplemented in the actual server until i do the login database or something similar)
|
||||||
|
[ ] Creating new characters
|
||||||
|
[ ] Allow creation of characters for admins
|
||||||
|
|
||||||
|
shit that needs to be done with characters handling:
|
||||||
|
|
||||||
|
[ ] Create character: admins only
|
||||||
|
[ ] view character list (all pc characters i think, or maybe only scene available characters?)
|
||||||
|
[ ] get character info
|
||||||
|
[ ] set character info
|
||||||
|
[ ] assign character to user
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
[x] Simple chat
|
[x] Simple chat
|
||||||
|
|
|
@ -20,8 +20,8 @@ pub struct ShowImage {
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct SpawnToken {
|
pub struct SpawnToken {
|
||||||
pub token_id: usize,
|
pub token_id: usize,
|
||||||
pub x: i32,
|
pub x: f32,
|
||||||
pub y: i32,
|
pub y: f32,
|
||||||
pub img: String
|
pub img: String
|
||||||
}
|
}
|
||||||
impl std::fmt::Debug for SpawnToken {
|
impl std::fmt::Debug for SpawnToken {
|
||||||
|
|
|
@ -9,5 +9,6 @@ pub struct LoginRequest {
|
||||||
#[derive(Serialize, Clone, Debug)]
|
#[derive(Serialize, Clone, Debug)]
|
||||||
pub struct LoginResult {
|
pub struct LoginResult {
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
|
pub username: String,
|
||||||
// TODO: Figure out what the user needs on successful login to reduce traffic
|
// TODO: Figure out what the user needs on successful login to reduce traffic
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ pub mod map_actions;
|
||||||
use game_actions::SpawnToken;
|
use game_actions::SpawnToken;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::game::{chat_message::ChatMessage, entry::ActionResult};
|
use crate::game::{character_sheet::EntryType, chat_message::ChatMessage, entry::ActionResult};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Debug)]
|
#[derive(Serialize, Deserialize, Default, Debug)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
@ -17,17 +17,25 @@ pub enum Request {
|
||||||
Quit,
|
Quit,
|
||||||
Kick(String),
|
Kick(String),
|
||||||
Shutdown,
|
Shutdown,
|
||||||
|
// Character stuff
|
||||||
|
CreateCharacter,
|
||||||
|
CharacterDisplay { id: usize },
|
||||||
|
CharacterInputs { id: usize },
|
||||||
|
CharacterGetField { id: usize, field: String },
|
||||||
|
CharacterSetField { id: usize, field: String, val: EntryType },
|
||||||
|
CharacterAssign { id: usize, user: String },
|
||||||
// Chat requests
|
// Chat requests
|
||||||
Message(ChatMessage),
|
Message(ChatMessage),
|
||||||
GetChatHistory { amount: usize, from: usize },
|
GetChatHistory { amount: usize, from: usize },
|
||||||
GetLastMessages { amount: usize, },
|
GetLastMessages { amount: usize, },
|
||||||
// Map requests
|
// Map requests
|
||||||
GetTokens,
|
GetTokens,
|
||||||
SpawnToken { x: i32, y: i32, img_path: String },
|
SpawnToken { map_id: usize, character: String, x: f32, y: f32, img_path: String },
|
||||||
MoveToken { token_id: usize, x: i32, y: i32 },
|
MoveToken { token_id: usize, x: f32, y: f32 },
|
||||||
// Actions requests
|
// Actions requests
|
||||||
ActionResult(ActionResult)
|
ActionResult(ActionResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone, Debug)]
|
#[derive(Serialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
|
@ -35,7 +43,7 @@ pub enum Response {
|
||||||
Login(login::LoginResult),
|
Login(login::LoginResult),
|
||||||
Message(ChatMessage),
|
Message(ChatMessage),
|
||||||
GetChatHistory(Vec<ChatMessage>),
|
GetChatHistory(Vec<ChatMessage>),
|
||||||
MoveToken { token_id: usize, x: i32, y: i32 },
|
MoveToken { token_id: usize, x: f32, y: f32 },
|
||||||
SpawnToken(SpawnToken),
|
SpawnToken(SpawnToken),
|
||||||
Quit { id: String },
|
Quit { id: String },
|
||||||
Shutdown,
|
Shutdown,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{entry::{ActionDefinition, ActionResult, GameEntry}, chat_message::ChatMessage};
|
use super::{entry::{ActionDefinition, ActionResult, GameEntry}, chat_message::ChatMessage};
|
||||||
|
|
||||||
pub trait Character<E: GameEntry> : CharacterSheet {
|
pub trait Character<E: GameEntry> : CharacterSheet {
|
||||||
|
@ -38,7 +40,7 @@ impl AccessLevel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum EntryType {
|
pub enum EntryType {
|
||||||
Number(i32),
|
Number(i32),
|
||||||
Text(String),
|
Text(String),
|
||||||
|
|
|
@ -1,36 +1,89 @@
|
||||||
//! Game Parser and Data types
|
//! Game Parser and Data types
|
||||||
use std::marker::PhantomData;
|
use std::{collections::HashMap, marker::PhantomData};
|
||||||
|
|
||||||
use character_sheet::Character;
|
use character_sheet::Character;
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod character_sheet;
|
pub mod character_sheet;
|
||||||
pub mod chat_message;
|
pub mod chat_message;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
|
|
||||||
pub trait GameImpl<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> {
|
pub trait GameImpl<'a, C: Character<A> + Serialize + Deserialize<'a>, A: entry::GameEntry + Serialize + Deserialize<'a>> {
|
||||||
/// Creates a new game
|
/// Creates a new game
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
/// Creates a new character, returning the character id
|
/// Creates a new character, returning the character id
|
||||||
fn create_character(&mut self) -> usize;
|
fn create_character(&mut self) -> usize;
|
||||||
|
fn create_token(&mut self, map_id: usize, character: String, img_source: String, x: f32, y: f32) -> usize;
|
||||||
|
fn move_token(&mut self, map_id: usize, token_id: usize, x: f32, y: f32) -> bool;
|
||||||
|
fn token_info(&self, map_id: usize, token_id: usize) -> Option<&TokenInfo>;
|
||||||
|
fn available_tokens(&self) -> impl Iterator<Item = usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Game<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> {
|
pub struct Game<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> {
|
||||||
_c: PhantomData<C>,
|
|
||||||
_a: PhantomData<A>,
|
_a: PhantomData<A>,
|
||||||
characters: Vec<C>,
|
characters: Vec<C>,
|
||||||
|
tokens: HashMap<usize, TokenInfo>,
|
||||||
}
|
}
|
||||||
impl<C: Character<A> + Serialize, A: entry::GameEntry + Serialize> GameImpl<C, A> for Game<C, A> {
|
impl<'a, C: Character<A> + Serialize + Deserialize<'a>, A: entry::GameEntry + Serialize + Deserialize<'a>> GameImpl<'a, C, A> for Game<C, A> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
_c: PhantomData,
|
|
||||||
_a: PhantomData,
|
_a: PhantomData,
|
||||||
characters: Vec::new(),
|
characters: Vec::new(),
|
||||||
|
tokens: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_character(&mut self) -> usize {
|
fn create_character(&mut self) -> usize {
|
||||||
self.characters.push(C::default());
|
self.characters.push(C::default());
|
||||||
self.characters.len() - 1
|
self.characters.len() - 1
|
||||||
}
|
}
|
||||||
|
fn move_token(&mut self, _map_id: usize, token_id: usize, x: f32, y: f32) -> bool {
|
||||||
|
if let Some(ti) = self.tokens.get_mut(&token_id) {
|
||||||
|
ti.x = x;
|
||||||
|
ti.y = y;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn token_info(&self, _map_id: usize, token_id: usize) -> Option<&TokenInfo> {
|
||||||
|
if let Some(ti) = self.tokens.get(&token_id) {
|
||||||
|
Some(ti)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn available_tokens(&self) -> impl Iterator<Item = usize> {
|
||||||
|
self.tokens
|
||||||
|
.keys()
|
||||||
|
.into_iter()
|
||||||
|
.map(|k| *k) // this map feels stupid but keys() turns into a &usize iterator so :shrug:
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_token(&mut self, map_id: usize, character: String, img_source: String, x: f32, y: f32) -> usize {
|
||||||
|
let mut id = 0;
|
||||||
|
while self.tokens.contains_key(&id) {
|
||||||
|
id += 1;
|
||||||
|
}
|
||||||
|
self.tokens.insert(id, TokenInfo { character, map_id, img_source, x, y });
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct TokenInfo {
|
||||||
|
/// Which character the token refers to
|
||||||
|
pub character: String,
|
||||||
|
/// Which map does the token exists in (allowing multiple tokens in multiple maps)
|
||||||
|
pub map_id: usize,
|
||||||
|
/// Token image source, as path relative to the data directory
|
||||||
|
pub img_source: String,
|
||||||
|
// x, y are floats to allow 'free movement'
|
||||||
|
/// X position, in grid slots units (integers are grid aligned)
|
||||||
|
pub x: f32,
|
||||||
|
/// Y position, in grid slots units (integers are grid aligned)
|
||||||
|
pub y: f32,
|
||||||
}
|
}
|
79
src/lib.rs
79
src/lib.rs
|
@ -1,5 +1,8 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use api::game_actions::SpawnToken;
|
use api::game_actions::SpawnToken;
|
||||||
use game::{chat_message::ChatMessage, entry::{ActionDefinition, DiceRoll}, Game, GameImpl};
|
use game::{chat_message::ChatMessage, entry::{ActionDefinition, DiceRoll}, Game, GameImpl};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{broadcast, mpsc};
|
use tokio::sync::{broadcast, mpsc};
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
@ -8,16 +11,23 @@ pub mod pathfinder2r_impl;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GameServer {
|
pub struct GameServer {
|
||||||
_game: Game<pathfinder2r_impl::Pathfinder2rCharacterSheet, pathfinder2r_impl::entry::Entry>,
|
game: Game<pathfinder2r_impl::Pathfinder2rCharacterSheet, pathfinder2r_impl::entry::Entry>,
|
||||||
tokens: Vec<(String, i32, i32)>,
|
|
||||||
chat: Vec<(String, ChatMessage)>,
|
chat: Vec<(String, ChatMessage)>,
|
||||||
|
#[serde(skip)] // we dont want to save the logged users as it will always be empty when the server restarts
|
||||||
|
users: HashMap<String, bool>,
|
||||||
|
// TODO: JEESH REPLACE THIS WITH A DATABASE AND PROPER SECURITY ONCE ITS DONE PLEASE GOD
|
||||||
|
creds: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
impl GameServer {
|
impl GameServer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let mut creds = HashMap::new();
|
||||||
|
creds.insert("rusty".to_string(), String::new());
|
||||||
|
creds.insert("artist".to_string(), "artist".to_string());
|
||||||
|
creds.insert("dragonfly".to_string(), "cool".to_string());
|
||||||
Self {
|
Self {
|
||||||
_game: Game::new(),
|
game: Game::new(),
|
||||||
tokens: vec![("assets/pf2r/tokens/louise.jpg".to_string(), 2, 2)],
|
|
||||||
chat: vec![
|
chat: vec![
|
||||||
(
|
(
|
||||||
"Server".to_string(),
|
"Server".to_string(),
|
||||||
|
@ -34,6 +44,8 @@ impl GameServer {
|
||||||
.with_action(ActionDefinition::new("Attack -1".to_string()))
|
.with_action(ActionDefinition::new("Attack -1".to_string()))
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
users: HashMap::new(),
|
||||||
|
creds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,9 +60,18 @@ impl GameServer {
|
||||||
println!("Got message from {}: {:?}", &id, &req);
|
println!("Got message from {}: {:?}", &id, &req);
|
||||||
|
|
||||||
match req {
|
match req {
|
||||||
// ignore errors and re-login requests
|
// ignore errors, should probably be blocked before they are sent here
|
||||||
api::Request::Error => {}
|
api::Request::Error => {}
|
||||||
api::Request::Login(_) => {}
|
api::Request::Login(login) => {
|
||||||
|
println!("login req from {}: {:?}", &id, &login);
|
||||||
|
if !self.users.contains_key(&login.username) && self.creds.get(&login.username).map(|p| p == &login.password).unwrap_or(false) {
|
||||||
|
self.users.insert(login.username.clone(), login.username == "rusty"); // rusty will be admin for now :)
|
||||||
|
_ = broadcast.send((Some(id), api::Response::Login(api::login::LoginResult { success: true, username: login.username })));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_ = broadcast.send((Some(id.clone()), api::Response::Login(api::login::LoginResult { success: false, username: login.username })));
|
||||||
|
}
|
||||||
|
}
|
||||||
api::Request::Message(mut msg) => {
|
api::Request::Message(mut msg) => {
|
||||||
if msg.id == 0 || msg.id > self.chat.len() {
|
if msg.id == 0 || msg.id > self.chat.len() {
|
||||||
msg.id = self.chat.len() + 1; // set the message id, 0 is invalid
|
msg.id = self.chat.len() + 1; // set the message id, 0 is invalid
|
||||||
|
@ -101,24 +122,24 @@ impl GameServer {
|
||||||
_ = broadcast.send((Some(id), api::Response::GetChatHistory(history)));
|
_ = broadcast.send((Some(id), api::Response::GetChatHistory(history)));
|
||||||
},
|
},
|
||||||
api::Request::GetTokens => {
|
api::Request::GetTokens => {
|
||||||
for (i, (path, x, y)) in self.tokens.iter().enumerate() {
|
for token_id in self.game.available_tokens() {
|
||||||
let bits = std::fs::read(path).expect("FAILED READING TOKEN IMAGE");
|
if let Some(ti) = self.game.token_info(0, token_id) {
|
||||||
|
let bits = std::fs::read(&ti.img_source).expect("FAILED READING TOKEN IMAGE");
|
||||||
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
||||||
_ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id: i, x: *x, y: *y, img })));
|
_ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id: token_id, x: ti.x, y: ti.y, img })));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
api::Request::SpawnToken { x, y, img_path } => {
|
api::Request::SpawnToken { map_id, character, x, y, img_path } => {
|
||||||
let token_id = self.tokens.len();
|
let token_id = self.game.create_token(map_id, character, img_path.clone(), x, y);
|
||||||
self.tokens.push((img_path.clone(), x, y));
|
let bits = std::fs::read(&img_path).expect("FAILED READING TOKEN IMAGE");
|
||||||
let bits = std::fs::read(img_path).expect("FAILED READING TOKEN IMAGE");
|
|
||||||
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
let img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
|
||||||
_ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id, x, y, img })));
|
_ = broadcast.send((Some(id.clone()), api::Response::SpawnToken(SpawnToken { token_id, x, y, img })));
|
||||||
},
|
},
|
||||||
api::Request::MoveToken { token_id, x, y } => {
|
api::Request::MoveToken { token_id, x, y } => {
|
||||||
// TODO: add check to make sure the actor is authorized to move the token
|
// TODO: add check to make sure the actor is authorized to move the token
|
||||||
if token_id < self.tokens.len() {
|
if self.game.move_token(0, token_id, x, y) {
|
||||||
self.tokens[token_id].1 = x;
|
// TODO: maybe chage move_token to return optional x,y values if succeeded to make sure the token is where it was going to be
|
||||||
self.tokens[token_id].2 = y;
|
|
||||||
_ = broadcast.send((None, api::Response::MoveToken { token_id, x, y }));
|
_ = broadcast.send((None, api::Response::MoveToken { token_id, x, y }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -135,10 +156,32 @@ impl GameServer {
|
||||||
self.chat.push((id, msg.clone()));
|
self.chat.push((id, msg.clone()));
|
||||||
_ = broadcast.send((None, api::Response::Message(msg)));
|
_ = broadcast.send((None, api::Response::Message(msg)));
|
||||||
|
|
||||||
|
},
|
||||||
|
api::Request::CreateCharacter => {
|
||||||
|
// check if user is admin
|
||||||
|
if self.users.get(&id).map(|a| *a).unwrap_or(false) {
|
||||||
|
let new_id = self.game.create_character();
|
||||||
|
// return the new id with the character i think
|
||||||
|
}
|
||||||
|
},
|
||||||
|
api::Request::Quit => {
|
||||||
|
if self.users.contains_key(&id) {
|
||||||
|
self.users.remove(&id);
|
||||||
|
}
|
||||||
|
_ = broadcast.send((None, api::Response::Quit { id }));
|
||||||
|
},
|
||||||
|
api::Request::Kick(id) => {
|
||||||
|
if self.users.contains_key(&id) {
|
||||||
|
self.users.remove(&id);
|
||||||
|
}
|
||||||
|
_ = broadcast.send((Some(id), api::Response::Shutdown));
|
||||||
}
|
}
|
||||||
api::Request::Quit => _ = broadcast.send((None, api::Response::Quit { id })),
|
|
||||||
api::Request::Kick(id) => _ = broadcast.send((Some(id), api::Response::Shutdown)),
|
|
||||||
api::Request::Shutdown => break,
|
api::Request::Shutdown => break,
|
||||||
|
api::Request::CharacterDisplay { id } => todo!(),
|
||||||
|
api::Request::CharacterInputs { id } => todo!(),
|
||||||
|
api::Request::CharacterGetField { id, field } => todo!(),
|
||||||
|
api::Request::CharacterSetField { id, field, val } => todo!(),
|
||||||
|
api::Request::CharacterAssign { id, user } => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = broadcast.send((None, api::Response::Shutdown));
|
_ = broadcast.send((None, api::Response::Shutdown));
|
||||||
|
|
67
src/main.rs
67
src/main.rs
|
@ -64,46 +64,65 @@ async fn socket_sender(id: String, mut send: SplitSink<ws::WebSocket, ws::Messag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, Request)>, brecv: broadcast::Receiver<(Option<String>, Response)>) {
|
async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, Request)>, mut brecv: broadcast::Receiver<(Option<String>, Response)>) {
|
||||||
let mut id: Option<String> = None;
|
let mut id: Option<String> = None;
|
||||||
|
// this is a temp id, and as long as 2 people dont try to connect to the socket at the same milisecond and to the same user it would be fine (i hope)
|
||||||
|
let temp_id = format!("temp_id_{}", std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).map(|t| t.as_micros()).unwrap_or(0));
|
||||||
|
let mut last_login_req = std::time::Instant::now();
|
||||||
loop {
|
loop {
|
||||||
if let Some(msg) = socket.recv().await {
|
tokio::select! {
|
||||||
if let Ok(msg) = msg {
|
b = brecv.recv() => {
|
||||||
match msg {
|
println!("{} trying to log in: {:?}", &temp_id, &b);
|
||||||
Message::Text(t) => {
|
if let Ok((to_id, msg)) = b {
|
||||||
let req = serde_json::from_str::<Request>(&t).unwrap_or_default();
|
if let Response::Login(open_tavern::api::login::LoginResult { success, username }) = msg.clone() {
|
||||||
println!("Got unauthorized message: {:?}", t);
|
let to_id = to_id.map(|ti| ti == temp_id).unwrap_or(false);
|
||||||
match req {
|
if to_id && success && id.as_ref().map(|id| id == &username).unwrap_or(false) {
|
||||||
// TODO: Actual signing in mechanism with multiple ids :)
|
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default())).await;
|
||||||
Request::Login(r) => if r.username == "rusty" || r.username == "honey" {
|
|
||||||
_ = socket.send(Message::Text(
|
|
||||||
serde_json::to_string(&Response::Login(open_tavern::api::login::LoginResult { success: true })).unwrap()
|
|
||||||
)).await;
|
|
||||||
id = Some(String::from(r.username));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_ = socket.send(Message::Text(
|
id = None;
|
||||||
serde_json::to_string(&Response::Login(open_tavern::api::login::LoginResult { success: false })).unwrap()
|
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default())).await;
|
||||||
)).await;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
msg = socket.recv() => {
|
||||||
|
if let Some(msg) = msg.map(|m| m.ok()).flatten() {
|
||||||
|
match msg {
|
||||||
|
Message::Text(t) => {
|
||||||
|
let req = serde_json::from_str::<Request>(&t).unwrap_or_default();
|
||||||
|
println!("{} trying to log in incoming: {:?}", &temp_id, t);
|
||||||
|
match req {
|
||||||
|
// TODO: Actual signing in mechanism with multiple ids :)
|
||||||
|
Request::Login(r) => {
|
||||||
|
// allow 1 login attempt every 3 seconds
|
||||||
|
if last_login_req.elapsed() > std::time::Duration::from_secs(1) {
|
||||||
|
last_login_req = std::time::Instant::now();
|
||||||
|
id = Some(r.username.clone());
|
||||||
|
_ = msend.send((temp_id.clone(), Request::Login(r))).await;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("Failed too early");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
_ = socket.send(Message::Text(serde_json::to_string(&Response::Error(RequestError::InvalidRequest)).unwrap())).await;
|
_ = socket.send(Message::Text(serde_json::to_string(&Response::Error(RequestError::InvalidRequest)).unwrap())).await;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ws::Message::Binary(_) => todo!(),
|
ws::Message::Close(_) => {
|
||||||
ws::Message::Ping(_) => todo!(),
|
id = None;
|
||||||
ws::Message::Pong(_) => todo!(),
|
break;
|
||||||
ws::Message::Close(_) => break,
|
},
|
||||||
|
_ => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
};
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(id) = id {
|
if let Some(id) = id {
|
||||||
|
// maybe i should not spawn 2 different routines and just have 1 routine that uses tokio::select!
|
||||||
println!("Got id for socket: {}", &id);
|
println!("Got id for socket: {}", &id);
|
||||||
let (send, recv) = socket.split();
|
let (send, recv) = socket.split();
|
||||||
tokio::spawn(socket_receiver(recv, msend, id.clone()));
|
tokio::spawn(socket_receiver(recv, msend, id.clone()));
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::game::{character_sheet::*, chat_message::ChatMessage, entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry}};
|
use crate::game::{character_sheet::*, chat_message::ChatMessage, entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry}};
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use tavern_macros::CharacterSheet;
|
use tavern_macros::CharacterSheet;
|
||||||
|
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
use entry::{Entry, Weapon};
|
use entry::{Entry, Weapon};
|
||||||
|
|
||||||
#[derive(Default, CharacterSheet, Serialize)]
|
#[derive(Default, CharacterSheet, Serialize, Deserialize)]
|
||||||
pub struct Pathfinder2rCharacterSheet {
|
pub struct Pathfinder2rCharacterSheet {
|
||||||
// Genral stuff
|
// Genral stuff
|
||||||
#[Input("Name")]
|
#[Input("Name")]
|
||||||
|
|
Loading…
Reference in a new issue