ship list logic
This commit is contained in:
parent
c1b40f63e1
commit
fc7b15c129
@ -19,4 +19,9 @@ mio = "0.6"
|
||||
mio-extras = "2.0.5"
|
||||
crc = "^1.0.0"
|
||||
bcrypt = "0.4"
|
||||
threadpool = "1.0"
|
||||
threadpool = "1.0"
|
||||
chrono = "*"
|
||||
|
||||
|
||||
[patch."http://git.sharnoth.com/jake/libpso"]
|
||||
libpso = { path = "../libpso" }
|
@ -10,11 +10,11 @@ use libpso::crypto::bb::PSOBBCipher;
|
||||
|
||||
use elseware::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
|
||||
use elseware::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
||||
use elseware::utf8_to_array;
|
||||
use elseware::{utf8_to_array, utf8_to_utf16_array};
|
||||
|
||||
use crate::dataaccess::DataAccess;
|
||||
use crate::login::get_login_status;
|
||||
use crate::entities::{UserAccount, Character};
|
||||
use crate::entities::{UserAccount, Character, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM};
|
||||
|
||||
pub const CHARACTER_PORT: u16 = 12001;
|
||||
|
||||
@ -33,6 +33,8 @@ pub enum RecvCharacterPacket {
|
||||
GuildcardDataChunkRequest(GuildcardDataChunkRequest),
|
||||
ParamDataRequest(ParamDataRequest),
|
||||
ParamDataChunkRequest(ParamDataChunkRequest),
|
||||
CharacterPreview(CharacterPreview),
|
||||
SetFlag(SetFlag)
|
||||
}
|
||||
|
||||
impl RecvServerPacket for RecvCharacterPacket {
|
||||
@ -46,6 +48,8 @@ impl RecvServerPacket for RecvCharacterPacket {
|
||||
0x3DC => Ok(RecvCharacterPacket::GuildcardDataChunkRequest(GuildcardDataChunkRequest::from_bytes(data)?)),
|
||||
0x4EB => Ok(RecvCharacterPacket::ParamDataRequest(ParamDataRequest::from_bytes(data)?)),
|
||||
0x3EB => Ok(RecvCharacterPacket::ParamDataChunkRequest(ParamDataChunkRequest::from_bytes(data)?)),
|
||||
0xE5 => Ok(RecvCharacterPacket::CharacterPreview(CharacterPreview::from_bytes(data)?)),
|
||||
0xEC => Ok(RecvCharacterPacket::SetFlag(SetFlag::from_bytes(data)?)),
|
||||
_ => Err(PacketParseError::WrongPacketForServerType)
|
||||
}
|
||||
}
|
||||
@ -64,6 +68,8 @@ pub enum SendCharacterPacket {
|
||||
GuildcardDataChunk(GuildcardDataChunk),
|
||||
ParamDataHeader(ParamDataHeader),
|
||||
ParamDataChunk(ParamDataChunk),
|
||||
Timestamp(Timestamp),
|
||||
ShipList(ShipList)
|
||||
}
|
||||
|
||||
impl SendServerPacket for SendCharacterPacket {
|
||||
@ -79,6 +85,8 @@ impl SendServerPacket for SendCharacterPacket {
|
||||
SendCharacterPacket::GuildcardDataChunk(pkt) => pkt.as_bytes(),
|
||||
SendCharacterPacket::ParamDataHeader(pkt) => pkt.as_bytes(),
|
||||
SendCharacterPacket::ParamDataChunk(pkt) => pkt.as_bytes(),
|
||||
SendCharacterPacket::Timestamp(pkt) => pkt.as_bytes(),
|
||||
SendCharacterPacket::ShipList(pkt) => pkt.as_bytes(),
|
||||
//SendLoginPacket::RedirectClient(pkt) => pkt.as_bytes(),
|
||||
}
|
||||
}
|
||||
@ -120,6 +128,7 @@ struct ClientState {
|
||||
user: Option<UserAccount>,
|
||||
characters: Option<[Option<Character>; 4]>,
|
||||
guildcard_data_buffer: Option<Vec<u8>>,
|
||||
security_data: [u8; 40],
|
||||
}
|
||||
|
||||
impl ClientState {
|
||||
@ -129,6 +138,7 @@ impl ClientState {
|
||||
user: None,
|
||||
characters: None,
|
||||
guildcard_data_buffer: None,
|
||||
security_data: [0; 40],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,18 +167,46 @@ impl<DA: DataAccess> CharacterServerState<DA> {
|
||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||
Ok(match get_login_status(&self.data_access, pkt) {
|
||||
Ok(user) => {
|
||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data);
|
||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, [0; 40]);
|
||||
response.guildcard = user.guildcard.map_or(0, |gc| gc) as u32;
|
||||
response.team_id = user.team_id.map_or(0, |ti| ti) as u32;
|
||||
client.user = Some(user);
|
||||
client.security_data = pkt.security_data;
|
||||
vec![SendCharacterPacket::LoginResponse(response)]
|
||||
},
|
||||
Err(err) => {
|
||||
vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, pkt.security_data))]
|
||||
vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, [0; 40]))]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn send_ship_list(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
||||
Ok(vec![SendCharacterPacket::Timestamp(Timestamp::new(chrono::Utc::now())),
|
||||
SendCharacterPacket::ShipList(ShipList {
|
||||
flag: 0,
|
||||
ships: vec![
|
||||
ShipListEntry {
|
||||
menu: 0,
|
||||
item: 1,
|
||||
flags: 0,
|
||||
name: utf8_to_utf16_array!("Sona-Nyl", 0x11),
|
||||
},
|
||||
ShipListEntry {
|
||||
menu: 0,
|
||||
item: 2,
|
||||
flags: 0,
|
||||
name: utf8_to_utf16_array!("Dylath-Leen", 0x11),
|
||||
},
|
||||
ShipListEntry {
|
||||
menu: 0,
|
||||
item: 2,
|
||||
flags: 0,
|
||||
name: utf8_to_utf16_array!("Innsmouth", 0x11),
|
||||
}
|
||||
]
|
||||
})])
|
||||
}
|
||||
|
||||
fn get_settings(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||
let user = client.user.as_ref().unwrap();
|
||||
@ -192,21 +230,38 @@ impl<DA: DataAccess> CharacterServerState<DA> {
|
||||
client.characters = Some(self.data_access.get_characters_by_user(client.user.as_ref().unwrap()));
|
||||
}
|
||||
|
||||
let chars = client.characters.as_ref().unwrap();
|
||||
Ok(if let Some(char) = &chars[select.slot as usize] {
|
||||
vec![SendCharacterPacket::CharacterPreview(CharacterPreview {
|
||||
flag: 0,
|
||||
slot: select.slot,
|
||||
character: char.character.as_select_screen(),
|
||||
})]
|
||||
if select.reason == 0 {
|
||||
let chars = client.characters.as_ref().unwrap();
|
||||
Ok(if let Some(char) = &chars[select.slot as usize] {
|
||||
vec![SendCharacterPacket::CharacterPreview(CharacterPreview {
|
||||
flag: 0,
|
||||
slot: select.slot,
|
||||
character: char.character.as_select_screen(),
|
||||
})]
|
||||
}
|
||||
else {
|
||||
vec![SendCharacterPacket::CharAck(CharAck {
|
||||
flag: 0,
|
||||
slot: select.slot,
|
||||
code: 2,
|
||||
})]
|
||||
})
|
||||
}
|
||||
else {
|
||||
vec![SendCharacterPacket::CharAck(CharAck {
|
||||
flag: 0,
|
||||
slot: select.slot,
|
||||
code: 2,
|
||||
})]
|
||||
})
|
||||
let user = client.user.as_ref().unwrap();
|
||||
client.security_data[0..4].clone_from_slice(&[1,3,3,7]);
|
||||
client.security_data[4] = select.slot as u8;
|
||||
client.security_data[5] = 1;
|
||||
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard.unwrap_or(1),
|
||||
user.team_id.unwrap_or(1),
|
||||
client.security_data)),
|
||||
SendCharacterPacket::CharAck(CharAck {
|
||||
flag: 0,
|
||||
slot: select.slot,
|
||||
code: 1,
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_checksum(&mut self) -> Vec<SendCharacterPacket> {
|
||||
@ -271,7 +326,12 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> {
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendCharacterPacket)>>, CharacterError> {
|
||||
Ok(match pkt {
|
||||
RecvCharacterPacket::Login(login) => {
|
||||
Box::new(self.validate_login(id, login)?.into_iter().map(move |pkt| (id, pkt)))
|
||||
if login.security_data[0..4] == [1,3,3,7] {
|
||||
Box::new(self.send_ship_list(id, login)?.into_iter().map(move |pkt| (id, pkt)))
|
||||
}
|
||||
else {
|
||||
Box::new(self.validate_login(id, login)?.into_iter().map(move |pkt| (id, pkt)))
|
||||
}
|
||||
},
|
||||
RecvCharacterPacket::RequestSettings(_req) => {
|
||||
Box::new(self.get_settings(id)?.into_iter().map(move |pkt| (id, pkt)))
|
||||
@ -291,6 +351,13 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> {
|
||||
RecvCharacterPacket::ParamDataRequest(_request) => {
|
||||
Box::new(vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt)))
|
||||
},
|
||||
RecvCharacterPacket::SetFlag(flags) => {
|
||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||
let mut user = client.user.as_mut().unwrap();
|
||||
user.flags = flags.flags;
|
||||
self.data_access.set_user(&user);
|
||||
Box::new(None.into_iter())
|
||||
},
|
||||
RecvCharacterPacket::ParamDataChunkRequest(_request) => {
|
||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||
let chunk = client.param_index;
|
||||
@ -309,6 +376,36 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> {
|
||||
data: data,
|
||||
}
|
||||
)].into_iter().map(move |pkt| (id, pkt)))
|
||||
},
|
||||
RecvCharacterPacket::CharacterPreview(preview) => {
|
||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||
let mut user = client.user.as_mut().unwrap();
|
||||
if user.flags == USERFLAG_NEWCHAR {
|
||||
let char = Character {
|
||||
id: 9,
|
||||
user_id: user.id,
|
||||
character: preview.character.as_character()
|
||||
};
|
||||
self.data_access.set_character_by_user(&user, preview.slot, char);
|
||||
}
|
||||
if user.flags == USERFLAG_DRESSINGROOM {
|
||||
// TODO: dressing room stuff
|
||||
}
|
||||
|
||||
client.security_data[0..4].clone_from_slice(&[1,3,3,7]);
|
||||
client.security_data[4] = preview.slot as u8;
|
||||
client.security_data[5] = 1;
|
||||
user.flags = 0;
|
||||
self.data_access.set_user(&user);
|
||||
Box::new(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard.unwrap_or(0),
|
||||
user.team_id.unwrap_or(0),
|
||||
client.security_data)),
|
||||
SendCharacterPacket::CharAck(CharAck {
|
||||
flag: 0,
|
||||
slot: preview.slot,
|
||||
code: 0
|
||||
})
|
||||
].into_iter().map(move |pkt| (id, pkt)))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -347,6 +444,7 @@ mod test {
|
||||
banned: false,
|
||||
muted_until: SystemTime::now(),
|
||||
created_at: SystemTime::now(),
|
||||
flags: 0,
|
||||
});
|
||||
server.clients.insert(ClientId(5), clientstate);
|
||||
|
||||
|
@ -4,6 +4,7 @@ mod dataaccess;
|
||||
mod entities;
|
||||
|
||||
use std::thread;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use bcrypt;
|
||||
|
||||
@ -22,12 +23,17 @@ use std::time::SystemTime;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LoginStubData {
|
||||
users: HashMap<String, UserAccount>,
|
||||
characters: [Option<Character> ;4],
|
||||
}
|
||||
|
||||
impl DataAccess for LoginStubData {
|
||||
fn get_user_by_name(&self, username: String) -> Option<UserAccount> {
|
||||
if username.as_str() == "hi" {
|
||||
Some(UserAccount {
|
||||
impl LoginStubData {
|
||||
fn new() -> LoginStubData {
|
||||
let mut c = pso_character::Character::default();
|
||||
c.name = utf8_to_utf16_array!("Test Char", 16);
|
||||
|
||||
let mut users = HashMap::new();
|
||||
users.insert("hi".to_string(), UserAccount {
|
||||
id: 1,
|
||||
username: "hi".to_owned(),
|
||||
password: bcrypt::hash("qwer", 5).unwrap(),
|
||||
@ -36,12 +42,26 @@ impl DataAccess for LoginStubData {
|
||||
banned: false,
|
||||
muted_until: SystemTime::now(),
|
||||
created_at: SystemTime::now(),
|
||||
})
|
||||
}
|
||||
else {
|
||||
None
|
||||
flags: 0,
|
||||
});
|
||||
|
||||
LoginStubData {
|
||||
users: users,
|
||||
|
||||
characters: [Some(Character {
|
||||
id: 1,
|
||||
user_id: 1,
|
||||
character: c,
|
||||
}),
|
||||
None, None, None]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataAccess for LoginStubData {
|
||||
fn get_user_by_name(&self, username: String) -> Option<UserAccount> {
|
||||
self.users.get(&username).map(|user| user.clone())
|
||||
}
|
||||
|
||||
fn get_user_settings_by_user(&self, user: &UserAccount) -> Option<UserSettings> {
|
||||
Some(UserSettings {
|
||||
@ -51,15 +71,16 @@ impl DataAccess for LoginStubData {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_characters_by_user(&self, user: &UserAccount) -> [Option<Character>; 4] {
|
||||
let mut c = pso_character::Character::default();
|
||||
c.name = utf8_to_utf16_array!("Test Char", 16);
|
||||
[Some(Character {
|
||||
id: 1,
|
||||
user_id: user.id,
|
||||
character: c,
|
||||
}),
|
||||
None, None, None]
|
||||
fn set_user(&mut self, user: &UserAccount) {
|
||||
self.users.insert(user.username.clone(), user.clone());
|
||||
}
|
||||
|
||||
fn get_characters_by_user(&self, _user: &UserAccount) -> [Option<Character>; 4] {
|
||||
self.characters
|
||||
}
|
||||
|
||||
fn set_character_by_user(&mut self, _user: &UserAccount, slot: u32, char: Character) {
|
||||
self.characters[slot as usize] = Some(char);
|
||||
}
|
||||
|
||||
fn get_guild_card_data_by_user(&self, user: &UserAccount) -> GuildCardData {
|
||||
@ -74,13 +95,12 @@ impl DataAccess for LoginStubData {
|
||||
fn main() {
|
||||
println!("[login+character] starting server");
|
||||
|
||||
// TODO: character mainloop
|
||||
let auth_thread = thread::spawn(|| {
|
||||
let auth_state = LoginServerState::new(LoginStubData {});
|
||||
let auth_state = LoginServerState::new(LoginStubData::new());
|
||||
elseware::common::mainloop::mainloop(auth_state, login::LOGIN_PORT);
|
||||
});
|
||||
let char_thread = thread::spawn(|| {
|
||||
let char_state = CharacterServerState::new(LoginStubData {});
|
||||
let char_state = CharacterServerState::new(LoginStubData::new());
|
||||
elseware::common::mainloop::mainloop(char_state, character::CHARACTER_PORT);
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user