2020-05-02 22:08:37 -03:00
#![ allow(dead_code, unused_assignments) ]
2019-09-13 19:21:33 -07:00
use std ::io ::Read ;
2020-11-01 07:49:04 -07:00
use std ::collections ::{ BTreeMap , BTreeSet , HashMap } ;
2019-08-20 17:59:00 -07:00
2022-10-18 17:55:47 -06:00
use async_std ::sync ::{ Arc , RwLock } ;
2022-10-18 04:46:21 -06:00
use async_std ::channel ;
2019-09-15 15:14:19 -07:00
use rand ::Rng ;
2019-09-08 23:54:15 -07:00
use crc ::{ crc32 , Hasher32 } ;
2019-08-20 17:59:00 -07:00
use libpso ::packet ::login ::* ;
2020-11-18 18:56:04 -07:00
use libpso ::packet ::ship ::{ MenuDetail , SmallLeftDialog } ;
2019-08-20 17:59:00 -07:00
use libpso ::{ PacketParseError , PSOPacket } ;
use libpso ::crypto ::bb ::PSOBBCipher ;
2020-02-06 23:03:51 -08:00
use crate ::entity ::item ;
2020-01-25 13:01:34 -08:00
use libpso ::character ::character ;
2019-08-20 17:59:00 -07:00
2019-10-09 22:45:14 -07:00
use crate ::common ::cipherkeys ::{ ELSEWHERE_PRIVATE_KEY , ELSEWHERE_PARRAY } ;
use crate ::common ::serverstate ::{ SendServerPacket , RecvServerPacket , ServerState , OnConnect , ClientId } ;
2020-08-19 23:18:04 -06:00
use crate ::common ::interserver ::{ ServerId , InterserverActor , LoginMessage , ShipMessage , Ship } ;
2022-10-18 04:46:21 -06:00
use crate ::common ::leveltable ::LEVEL_TABLE ;
2019-11-04 21:11:28 -08:00
use libpso ::{ utf8_to_array , utf8_to_utf16_array } ;
2019-08-20 17:59:00 -07:00
2022-10-20 17:41:03 -06:00
use crate ::entity ::gateway ::{ EntityGateway , GatewayError } ;
2020-11-18 18:56:04 -07:00
use crate ::entity ::account ::{ UserAccountId , UserAccountEntity , NewUserSettingsEntity , USERFLAG_NEWCHAR , USERFLAG_DRESSINGROOM } ;
2021-12-26 23:31:12 -07:00
use crate ::entity ::item ::{ NewItemEntity , ItemDetail , ItemNote , InventoryItemEntity , InventoryEntity , BankEntity , BankName , EquippedEntity , Meseta } ;
2020-03-16 20:34:50 -07:00
use crate ::entity ::item ::weapon ::Weapon ;
2020-03-16 20:57:19 -07:00
use crate ::entity ::item ::armor ::Armor ;
2020-03-18 18:21:34 -07:00
use crate ::entity ::item ::tech ::Technique ;
2020-03-21 17:47:28 -07:00
use crate ::entity ::item ::tool ::Tool ;
2020-10-26 00:02:48 -06:00
use crate ::entity ::item ::mag ::Mag ;
2020-03-30 19:28:49 -07:00
use crate ::entity ::character ::{ CharacterEntity , NewCharacterEntity , CharacterClass , TechLevel } ;
2019-10-05 17:37:49 -07:00
2021-06-18 20:38:29 -06:00
use crate ::login ::login ::{ get_login_status } ;
2020-11-01 07:49:04 -07:00
use crate ::common ::interserver ::AuthToken ;
2019-08-20 17:59:00 -07:00
pub const CHARACTER_PORT : u16 = 12001 ;
2020-11-21 23:45:27 -07:00
pub const SHIP_MENU_ID : u32 = 1 ;
2019-08-20 17:59:00 -07:00
2020-11-01 09:04:37 -07:00
#[ derive(thiserror::Error, Debug) ]
#[ error( " " ) ]
2019-08-20 17:59:00 -07:00
pub enum CharacterError {
2019-10-17 23:41:01 -07:00
InvalidMenuSelection ( u32 , u32 ) ,
2019-09-15 15:04:12 -07:00
ClientNotFound ( ClientId ) ,
2020-10-24 17:45:59 -06:00
CouldNotLoadSettings ,
CouldNotLoadCharacters ,
CouldNotLoadGuildcard ,
2020-11-16 23:05:28 -07:00
GatewayError ( #[ from ] GatewayError ) ,
2019-08-20 17:59:00 -07:00
}
#[ derive(Debug) ]
2019-08-24 14:45:58 -07:00
pub enum RecvCharacterPacket {
2019-08-20 17:59:00 -07:00
Login ( Login ) ,
RequestSettings ( RequestSettings ) ,
2019-09-03 20:30:35 -04:00
CharSelect ( CharSelect ) ,
Checksum ( Checksum ) ,
2019-09-08 23:54:15 -07:00
GuildcardDataRequest ( GuildcardDataRequest ) ,
GuildcardDataChunkRequest ( GuildcardDataChunkRequest ) ,
2019-09-13 19:21:33 -07:00
ParamDataRequest ( ParamDataRequest ) ,
ParamDataChunkRequest ( ParamDataChunkRequest ) ,
2019-09-23 22:27:43 -07:00
CharacterPreview ( CharacterPreview ) ,
2019-10-17 23:41:01 -07:00
SetFlag ( SetFlag ) ,
MenuSelect ( MenuSelect ) ,
2020-11-18 18:56:04 -07:00
MenuDetail ( MenuDetail ) ,
2019-08-20 17:59:00 -07:00
}
2019-08-24 14:45:58 -07:00
impl RecvServerPacket for RecvCharacterPacket {
2019-09-04 09:17:22 -07:00
fn from_bytes ( data : & [ u8 ] ) -> Result < RecvCharacterPacket , PacketParseError > {
2019-08-29 23:43:48 -07:00
match u16 ::from_le_bytes ( [ data [ 2 ] , data [ 3 ] ] ) {
2019-08-24 14:45:58 -07:00
0x93 = > Ok ( RecvCharacterPacket ::Login ( Login ::from_bytes ( data ) ? ) ) ,
0xE0 = > Ok ( RecvCharacterPacket ::RequestSettings ( RequestSettings ::from_bytes ( data ) ? ) ) ,
2019-08-28 17:46:12 -07:00
0xE3 = > Ok ( RecvCharacterPacket ::CharSelect ( CharSelect ::from_bytes ( data ) ? ) ) ,
2019-09-03 20:30:35 -04:00
0x1E8 = > Ok ( RecvCharacterPacket ::Checksum ( Checksum ::from_bytes ( data ) ? ) ) ,
2019-09-08 23:54:15 -07:00
0x3E8 = > Ok ( RecvCharacterPacket ::GuildcardDataRequest ( GuildcardDataRequest ::from_bytes ( data ) ? ) ) ,
0x3DC = > Ok ( RecvCharacterPacket ::GuildcardDataChunkRequest ( GuildcardDataChunkRequest ::from_bytes ( data ) ? ) ) ,
2019-09-13 19:21:33 -07:00
0x4EB = > Ok ( RecvCharacterPacket ::ParamDataRequest ( ParamDataRequest ::from_bytes ( data ) ? ) ) ,
0x3EB = > Ok ( RecvCharacterPacket ::ParamDataChunkRequest ( ParamDataChunkRequest ::from_bytes ( data ) ? ) ) ,
2019-09-23 22:27:43 -07:00
0xE5 = > Ok ( RecvCharacterPacket ::CharacterPreview ( CharacterPreview ::from_bytes ( data ) ? ) ) ,
0xEC = > Ok ( RecvCharacterPacket ::SetFlag ( SetFlag ::from_bytes ( data ) ? ) ) ,
2019-10-17 23:41:01 -07:00
0x10 = > Ok ( RecvCharacterPacket ::MenuSelect ( MenuSelect ::from_bytes ( data ) ? ) ) ,
2020-11-18 18:56:04 -07:00
0x09 = > Ok ( RecvCharacterPacket ::MenuDetail ( MenuDetail ::from_bytes ( data ) ? ) ) ,
2019-11-09 22:58:13 -08:00
_ = > Err ( PacketParseError ::WrongPacketForServerType ( u16 ::from_le_bytes ( [ data [ 2 ] , data [ 3 ] ] ) , data . to_vec ( ) ) )
2019-08-20 17:59:00 -07:00
}
}
}
2019-08-24 14:45:58 -07:00
#[ derive(Debug) ]
pub enum SendCharacterPacket {
2019-08-25 04:58:55 -07:00
LoginResponse ( LoginResponse ) ,
2019-08-24 14:45:58 -07:00
LoginWelcome ( LoginWelcome ) ,
2021-06-18 17:46:22 -06:00
SendKeyAndTeamSettings ( Box < SendKeyAndTeamSettings > ) ,
2019-08-28 22:48:25 -07:00
CharAck ( CharAck ) ,
2019-09-03 20:30:35 -04:00
ChecksumAck ( ChecksumAck ) ,
2019-09-08 23:54:15 -07:00
CharacterPreview ( CharacterPreview ) ,
GuildcardDataHeader ( GuildcardDataHeader ) ,
2020-11-09 16:04:42 -07:00
GuildcardDataChunk ( Box < GuildcardDataChunk > ) ,
2019-09-13 19:21:33 -07:00
ParamDataHeader ( ParamDataHeader ) ,
2021-06-18 17:46:22 -06:00
ParamDataChunk ( Box < ParamDataChunk > ) ,
2019-09-23 22:27:43 -07:00
Timestamp ( Timestamp ) ,
2019-10-17 23:41:01 -07:00
ShipList ( ShipList ) ,
RedirectClient ( RedirectClient ) ,
2020-11-18 18:56:04 -07:00
SmallLeftDialog ( SmallLeftDialog ) ,
2019-08-24 14:45:58 -07:00
}
impl SendServerPacket for SendCharacterPacket {
fn as_bytes ( & self ) -> Vec < u8 > {
match self {
2019-08-25 04:58:55 -07:00
SendCharacterPacket ::LoginResponse ( pkt ) = > pkt . as_bytes ( ) ,
2019-08-24 14:45:58 -07:00
SendCharacterPacket ::LoginWelcome ( pkt ) = > pkt . as_bytes ( ) ,
2019-08-25 04:58:55 -07:00
SendCharacterPacket ::SendKeyAndTeamSettings ( pkt ) = > pkt . as_bytes ( ) ,
2019-08-28 22:48:25 -07:00
SendCharacterPacket ::CharAck ( pkt ) = > pkt . as_bytes ( ) ,
2019-09-03 20:30:35 -04:00
SendCharacterPacket ::ChecksumAck ( pkt ) = > pkt . as_bytes ( ) ,
2019-09-08 23:54:15 -07:00
SendCharacterPacket ::CharacterPreview ( pkt ) = > pkt . as_bytes ( ) ,
SendCharacterPacket ::GuildcardDataHeader ( pkt ) = > pkt . as_bytes ( ) ,
SendCharacterPacket ::GuildcardDataChunk ( pkt ) = > pkt . as_bytes ( ) ,
2019-09-13 19:21:33 -07:00
SendCharacterPacket ::ParamDataHeader ( pkt ) = > pkt . as_bytes ( ) ,
SendCharacterPacket ::ParamDataChunk ( pkt ) = > pkt . as_bytes ( ) ,
2019-09-23 22:27:43 -07:00
SendCharacterPacket ::Timestamp ( pkt ) = > pkt . as_bytes ( ) ,
SendCharacterPacket ::ShipList ( pkt ) = > pkt . as_bytes ( ) ,
2019-10-17 23:41:01 -07:00
SendCharacterPacket ::RedirectClient ( pkt ) = > pkt . as_bytes ( ) ,
2020-11-18 18:56:04 -07:00
SendCharacterPacket ::SmallLeftDialog ( pkt ) = > pkt . as_bytes ( ) ,
2019-08-24 14:45:58 -07:00
}
}
}
2019-09-13 19:21:33 -07:00
fn generate_param_data ( path : & str ) -> ( ParamDataHeader , Vec < u8 > ) {
let paths = std ::fs ::read_dir ( path ) . expect ( " could not find param/ directory " ) ;
let mut files = Vec ::new ( ) ;
let mut buffer = Vec ::new ( ) ;
for p in paths {
let param = p . unwrap ( ) . path ( ) ;
let mut file = std ::fs ::File ::open ( & param ) . unwrap ( ) ;
let mut filebuf = Vec ::new ( ) ;
let len = file . read_to_end ( & mut filebuf ) . unwrap ( ) ;
let mut crc = crc32 ::Digest ::new ( crc32 ::IEEE ) ;
crc . write ( & filebuf [ .. ] ) ;
files . push ( ParamFile {
size : len as u32 ,
checksum : crc . sum32 ( ) ,
offset : buffer . len ( ) as u32 ,
filename : utf8_to_array ! ( param . file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) , 0x40 ) ,
} ) ;
buffer . append ( & mut filebuf ) ;
}
( ParamDataHeader {
2021-06-18 20:38:29 -06:00
files
2019-09-13 19:21:33 -07:00
} , buffer )
}
2020-01-12 22:07:52 -04:00
#[ derive(Clone) ]
2019-09-15 15:04:12 -07:00
struct ClientState {
2019-09-13 19:21:33 -07:00
param_index : usize ,
2020-03-29 16:11:14 -07:00
user : Option < UserAccountEntity > ,
2020-03-29 12:43:20 -07:00
characters : Option < [ Option < CharacterEntity > ; 4 ] > ,
2019-09-08 23:54:15 -07:00
guildcard_data_buffer : Option < Vec < u8 > > ,
2019-11-04 20:28:50 -08:00
session : Session ,
2019-09-15 15:04:12 -07:00
}
impl ClientState {
fn new ( ) -> ClientState {
ClientState {
param_index : 0 ,
user : None ,
characters : None ,
guildcard_data_buffer : None ,
2019-11-04 20:28:50 -08:00
session : Session ::new ( ) ,
2019-09-15 15:04:12 -07:00
}
}
}
2019-09-08 23:54:15 -07:00
2020-11-21 23:45:27 -07:00
#[ derive(Debug, Clone) ]
2020-11-18 18:56:04 -07:00
struct ConnectedClient {
ship_id : Option < ServerId > ,
expires : Option < chrono ::DateTime < chrono ::Utc > > ,
}
2019-12-03 21:45:16 -08:00
2022-10-18 04:46:21 -06:00
#[ derive(Clone) ]
pub struct CharacterServerState < EG : EntityGateway + Clone > {
2019-10-05 17:37:49 -07:00
entity_gateway : EG ,
2019-09-15 15:04:12 -07:00
param_header : ParamDataHeader ,
2022-10-18 17:55:47 -06:00
param_data : Arc < Vec < u8 > > ,
clients : Arc < RwLock < HashMap < ClientId , ClientState > > > ,
ships : Arc < RwLock < BTreeMap < ServerId , Ship > > > ,
2020-11-01 07:49:04 -07:00
auth_token : AuthToken ,
2020-11-18 18:56:04 -07:00
2022-10-18 17:55:47 -06:00
connected_clients : Arc < RwLock < BTreeMap < UserAccountId , ConnectedClient > > > ,
authenticated_ships : Arc < RwLock < BTreeSet < ServerId > > > ,
ship_sender : Arc < RwLock < BTreeMap < ServerId , channel ::Sender < LoginMessage > > > > ,
2019-08-20 17:59:00 -07:00
}
2019-12-03 21:46:01 -08:00
2022-10-18 04:46:21 -06:00
async fn new_character < EG : EntityGateway + Clone > ( entity_gateway : & mut EG , user : & UserAccountEntity , preview : & CharacterPreview ) -> Result < ( ) , anyhow ::Error > {
2020-03-29 22:00:07 -07:00
let mut character = new_character_from_preview ( user , preview ) ;
match character . char_class {
CharacterClass ::FOmar | CharacterClass ::FOmarl | CharacterClass ::FOnewm | CharacterClass ::FOnewearl = > character . techs . set_tech ( Technique ::Foie , TechLevel ( 1 ) ) ,
2020-01-25 13:29:01 -08:00
_ = > { }
}
2020-11-16 23:05:28 -07:00
let character = entity_gateway . create_character ( character ) . await ? ;
2021-12-26 23:31:12 -07:00
entity_gateway . set_character_meseta ( & character . id , Meseta ( 300 ) ) . await ? ;
2020-01-18 23:36:28 -08:00
2020-03-29 22:00:07 -07:00
let new_weapon = match character . char_class {
2020-01-25 13:01:34 -08:00
CharacterClass ::HUmar | CharacterClass ::HUnewearl | CharacterClass ::HUcast | CharacterClass ::HUcaseal = > item ::weapon ::WeaponType ::Saber ,
CharacterClass ::RAmar | CharacterClass ::RAmarl | CharacterClass ::RAcast | CharacterClass ::RAcaseal = > item ::weapon ::WeaponType ::Handgun ,
2020-03-21 21:46:52 -07:00
CharacterClass ::FOmar | CharacterClass ::FOmarl | CharacterClass ::FOnewm | CharacterClass ::FOnewearl = > item ::weapon ::WeaponType ::Cane ,
2020-01-18 23:36:28 -08:00
} ;
2020-11-05 16:36:39 -07:00
let weapon = entity_gateway . create_item (
2020-03-30 19:28:49 -07:00
NewItemEntity {
2020-03-29 22:00:07 -07:00
item : ItemDetail ::Weapon (
Weapon {
weapon : new_weapon ,
grind : 0 ,
special : None ,
attrs : [ None ; 3 ] ,
tekked : true ,
2021-11-12 10:42:33 -07:00
} ) } ) . await ? ;
entity_gateway . add_item_note ( & weapon . id , ItemNote ::CharacterCreation {
character_id : character . id ,
} ) . await ? ;
2020-03-29 22:00:07 -07:00
2020-11-05 16:36:39 -07:00
let armor = entity_gateway . create_item (
2020-03-30 19:28:49 -07:00
NewItemEntity {
2020-03-29 22:00:07 -07:00
item : ItemDetail ::Armor (
Armor {
armor : item ::armor ::ArmorType ::Frame ,
dfp : 0 ,
evp : 0 ,
2020-08-20 20:19:46 -06:00
slots : 0 ,
2021-11-12 10:42:33 -07:00
} ) } ) . await ? ;
entity_gateway . add_item_note ( & armor . id , ItemNote ::CharacterCreation {
character_id : character . id ,
} ) . await ? ;
2020-03-29 22:00:07 -07:00
2020-11-14 15:30:37 -04:00
let mut mag = {
if character . char_class . is_android ( ) {
Mag ::baby_mag ( character . appearance . skin )
} else {
Mag ::baby_mag ( character . appearance . costume )
}
} ;
2020-09-02 22:31:33 -06:00
mag . change_owner ( character . char_class , character . section_id ) ;
2020-11-05 16:36:39 -07:00
let mag = entity_gateway . create_item (
2020-03-30 19:28:49 -07:00
NewItemEntity {
2020-09-02 22:31:33 -06:00
item : ItemDetail ::Mag ( mag ) ,
2021-11-12 10:42:33 -07:00
} ) . await ? ;
entity_gateway . add_item_note ( & mag . id , ItemNote ::CharacterCreation {
character_id : character . id ,
} ) . await ? ;
2022-04-19 23:20:16 -06:00
let mut monomates = Vec ::new ( ) ;
for _ in 0 .. 4 usize {
let monomate = entity_gateway . create_item (
NewItemEntity {
item : ItemDetail ::Tool (
Tool {
tool : item ::tool ::ToolType ::Monomate ,
} ) } ) . await ? ;
entity_gateway . add_item_note ( & monomate . id , ItemNote ::CharacterCreation {
character_id : character . id
} ) . await ? ;
monomates . push ( monomate ) ;
}
let mut monofluids = Vec ::new ( ) ;
for _ in 0 .. 4 usize {
let monofluid = entity_gateway . create_item (
NewItemEntity {
item : ItemDetail ::Tool (
Tool {
tool : item ::tool ::ToolType ::Monofluid ,
} ) } ) . await ? ;
entity_gateway . add_item_note ( & monofluid . id , ItemNote ::CharacterCreation {
character_id : character . id
} ) . await ? ;
monofluids . push ( monofluid ) ;
}
2020-11-05 16:36:39 -07:00
let inventory = InventoryEntity {
items : vec ! [ InventoryItemEntity ::Individual ( weapon . clone ( ) ) , InventoryItemEntity ::Individual ( armor . clone ( ) ) , InventoryItemEntity ::Individual ( mag . clone ( ) ) ,
InventoryItemEntity ::Stacked ( monomates ) , InventoryItemEntity ::Stacked ( monofluids ) ] ,
} ;
2020-11-16 23:05:28 -07:00
entity_gateway . set_character_inventory ( & character . id , & inventory ) . await ? ;
2022-05-14 13:02:23 -06:00
entity_gateway . set_character_bank ( & character . id , & BankEntity ::default ( ) , & BankName ( " " . into ( ) ) ) . await ? ;
2021-06-18 17:46:22 -06:00
let equipped = EquippedEntity {
weapon : Some ( weapon . id ) ,
armor : Some ( armor . id ) ,
mag : Some ( mag . id ) ,
.. Default ::default ( )
} ;
2020-11-16 23:05:28 -07:00
entity_gateway . set_character_equips ( & character . id , & equipped ) . await ? ;
Ok ( ( ) )
2019-12-03 21:46:01 -08:00
}
2022-10-18 04:46:21 -06:00
impl < EG : EntityGateway + Clone > CharacterServerState < EG > {
2020-11-01 07:49:04 -07:00
pub fn new ( entity_gateway : EG , auth_token : AuthToken ) -> CharacterServerState < EG > {
2019-12-01 13:37:17 -08:00
let ( param_header , param_data ) = generate_param_data ( " data/param/ " ) ;
2019-09-13 19:21:33 -07:00
2019-08-20 17:59:00 -07:00
CharacterServerState {
2021-06-18 20:38:29 -06:00
entity_gateway ,
param_header ,
2022-10-18 17:55:47 -06:00
param_data : Arc ::new ( param_data ) ,
clients : Default ::default ( ) ,
ships : Default ::default ( ) ,
2022-10-18 04:46:21 -06:00
//level_table: CharacterLevelTable::default(),
2021-06-18 20:38:29 -06:00
auth_token ,
2022-10-18 17:55:47 -06:00
authenticated_ships : Default ::default ( ) ,
ship_sender : Default ::default ( ) ,
connected_clients : Default ::default ( ) ,
2019-08-20 17:59:00 -07:00
}
}
2020-11-01 09:04:37 -07:00
async fn validate_login ( & mut self , id : ClientId , pkt : & Login ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2022-04-19 23:17:20 -06:00
match get_login_status ( & mut self . entity_gateway , pkt ) . await {
2020-11-18 18:56:04 -07:00
Ok ( user ) = > {
2022-10-18 17:55:47 -06:00
if let Some ( connected_client ) = self . connected_clients . read ( ) . await . get ( & user . id ) {
2020-11-18 18:56:04 -07:00
if let Some ( expires ) = connected_client . expires {
2020-11-25 22:05:55 -07:00
if expires > chrono ::Utc ::now ( ) {
2020-11-18 18:56:04 -07:00
return Ok ( vec! [ SendCharacterPacket ::LoginResponse ( LoginResponse ::by_status ( AccountStatus ::AlreadyOnline , Session ::new ( ) ) ) ] ) ;
}
}
2020-11-25 22:05:55 -07:00
else {
return Ok ( vec! [ SendCharacterPacket ::LoginResponse ( LoginResponse ::by_status ( AccountStatus ::AlreadyOnline , Session ::new ( ) ) ) ] ) ;
}
2020-11-18 18:56:04 -07:00
}
2020-10-27 22:31:54 -06:00
2019-11-04 20:28:50 -08:00
let mut response = LoginResponse ::by_status ( AccountStatus ::Ok , Session ::new ( ) ) ;
2020-03-22 22:40:40 -03:00
response . guildcard = user . guildcard ;
2022-10-18 17:55:47 -06:00
response . team_id = user . team_id . map_or ( 0 , | ti | ti ) ;
2020-11-18 18:56:04 -07:00
2022-10-18 17:55:47 -06:00
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2020-11-18 18:56:04 -07:00
2022-10-18 17:55:47 -06:00
self . connected_clients . write ( ) . await . insert ( user . id , ConnectedClient {
2020-11-18 18:56:04 -07:00
ship_id : None ,
2020-11-25 22:05:55 -07:00
expires : None , //Some(chrono::Utc::now() + chrono::Duration::minutes(1)),
2020-11-18 18:56:04 -07:00
} ) ;
2019-09-15 15:04:12 -07:00
client . user = Some ( user ) ;
2019-11-04 20:28:50 -08:00
client . session = pkt . session ;
2020-11-18 18:56:04 -07:00
Ok ( vec! [ SendCharacterPacket ::LoginResponse ( response ) ] )
2019-08-20 17:59:00 -07:00
} ,
Err ( err ) = > {
2020-11-18 18:56:04 -07:00
Ok ( vec! [ SendCharacterPacket ::LoginResponse ( LoginResponse ::by_status ( err , Session ::new ( ) ) ) ] )
2019-08-20 17:59:00 -07:00
}
2020-11-18 18:56:04 -07:00
}
2019-08-20 17:59:00 -07:00
}
2022-10-18 17:55:47 -06:00
async fn send_ship_list ( & mut self , _id : ClientId , _pkt : & Login ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2019-09-23 22:27:43 -07:00
Ok ( vec! [ SendCharacterPacket ::Timestamp ( Timestamp ::new ( chrono ::Utc ::now ( ) ) ) ,
2022-10-18 17:55:47 -06:00
SendCharacterPacket ::ShipList ( ShipList ::new ( self . ships . read ( ) . await . iter ( ) . map ( | ( i , s ) | {
2019-11-04 22:07:04 -08:00
ShipListEntry {
menu : SHIP_MENU_ID ,
2020-08-19 23:18:04 -06:00
item : i . 0 as u32 ,
2019-11-04 22:07:04 -08:00
flags : 0 ,
name : utf8_to_utf16_array ! ( s . name , 0x11 )
2019-12-03 21:45:16 -08:00
}
2019-11-04 22:07:04 -08:00
} ) . collect ( ) ) )
] )
2019-09-23 22:27:43 -07:00
}
2020-11-01 09:04:37 -07:00
async fn get_settings ( & mut self , id : ClientId ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2019-09-15 15:04:12 -07:00
let user = client . user . as_ref ( ) . unwrap ( ) ;
2021-06-18 17:46:22 -06:00
let settings = match self . entity_gateway . get_user_settings_by_user ( user ) . await {
2020-10-24 17:45:59 -06:00
Ok ( settings ) = > settings ,
Err ( _ ) = > {
2020-03-30 19:28:49 -07:00
let user_settings = NewUserSettingsEntity ::new ( user . id ) ;
2020-10-24 17:45:59 -06:00
self . entity_gateway . create_user_settings ( user_settings ) . await . map_err ( | _ | CharacterError ::CouldNotLoadSettings ) ?
2020-03-29 22:00:07 -07:00
}
2019-08-25 04:59:13 -07:00
} ;
2022-01-05 22:57:15 +00:00
let pkt = SendKeyAndTeamSettings ::new ( settings . settings . keyboard_config ,
settings . settings . gamepad_config , 0 , 0 ) ;
2021-06-18 17:46:22 -06:00
let pkt = SendCharacterPacket ::SendKeyAndTeamSettings ( Box ::new ( pkt ) ) ;
2019-08-25 04:59:13 -07:00
2019-09-15 15:04:12 -07:00
Ok ( vec! [ pkt ] )
2019-08-20 17:59:00 -07:00
}
2019-08-28 17:46:12 -07:00
2020-11-01 09:04:37 -07:00
async fn char_select ( & mut self , id : ClientId , select : & CharSelect ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2019-09-15 15:04:12 -07:00
if client . characters . is_none ( ) {
2020-10-24 17:45:59 -06:00
client . characters = Some ( self . entity_gateway . get_characters_by_user ( client . user . as_ref ( ) . unwrap ( ) ) . await . map_err ( | _ | CharacterError ::CouldNotLoadCharacters ) ? ) ;
2019-09-04 09:17:22 -07:00
}
2019-09-23 22:27:43 -07:00
if select . reason = = 0 {
let chars = client . characters . as_ref ( ) . unwrap ( ) ;
Ok ( if let Some ( char ) = & chars [ select . slot as usize ] {
2022-10-18 04:46:21 -06:00
let ( level , _stats ) = LEVEL_TABLE . get_stats_from_exp ( char . char_class , char . exp ) ;
2019-09-23 22:27:43 -07:00
vec! [ SendCharacterPacket ::CharacterPreview ( CharacterPreview {
slot : select . slot ,
2020-01-25 13:01:34 -08:00
character : SelectScreenCharacterBuilder ::new ( )
2021-06-18 17:46:22 -06:00
. character ( char )
2020-01-25 13:01:34 -08:00
. level ( level )
. build ( )
2019-09-23 22:27:43 -07:00
} ) ]
}
else {
vec! [ SendCharacterPacket ::CharAck ( CharAck {
slot : select . slot ,
code : 2 ,
} ) ]
} )
2019-09-04 09:17:22 -07:00
}
else {
2019-09-23 22:27:43 -07:00
let user = client . user . as_ref ( ) . unwrap ( ) ;
2019-11-04 20:28:50 -08:00
client . session . action = SessionAction ::SelectCharacter ;
client . session . character_slot = select . slot as u8 ;
2020-03-22 22:40:40 -03:00
Ok ( vec! [ SendCharacterPacket ::LoginResponse ( LoginResponse ::by_char_select ( user . guildcard ,
2019-09-23 22:27:43 -07:00
user . team_id . unwrap_or ( 1 ) ,
2019-11-04 20:28:50 -08:00
client . session ) ) ,
2019-09-23 22:27:43 -07:00
SendCharacterPacket ::CharAck ( CharAck {
slot : select . slot ,
code : 1 ,
} )
] )
}
2019-08-28 17:46:12 -07:00
}
2019-09-03 20:30:35 -04:00
fn validate_checksum ( & mut self ) -> Vec < SendCharacterPacket > {
vec! [ SendCharacterPacket ::ChecksumAck ( ChecksumAck {
ack : 1 ,
} ) ]
}
2019-09-08 23:54:15 -07:00
2020-11-01 09:04:37 -07:00
async fn guildcard_data_header ( & mut self , id : ClientId ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2020-10-24 17:45:59 -06:00
let guildcard_data = self . entity_gateway . get_guild_card_data_by_user ( client . user . as_ref ( ) . unwrap ( ) ) . await . map_err ( | _ | CharacterError ::CouldNotLoadGuildcard ) ? ;
2019-09-08 23:54:15 -07:00
let bytes = guildcard_data . guildcard . as_bytes ( ) ;
let mut crc = crc32 ::Digest ::new ( crc32 ::IEEE ) ;
crc . write ( & bytes [ .. ] ) ;
2019-09-15 15:04:12 -07:00
client . guildcard_data_buffer = Some ( bytes . to_vec ( ) ) ;
2019-09-08 23:54:15 -07:00
2019-09-15 15:04:12 -07:00
Ok ( vec! [ SendCharacterPacket ::GuildcardDataHeader ( GuildcardDataHeader ::new ( bytes . len ( ) , crc . sum32 ( ) ) ) ] )
2019-09-08 23:54:15 -07:00
}
2022-10-18 17:55:47 -06:00
async fn guildcard_data_chunk ( & mut self , id : ClientId , chunk : u32 , again : u32 ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2019-09-15 15:04:12 -07:00
Ok ( if again ! = 0 {
2019-09-08 23:54:15 -07:00
let start = chunk as usize * GUILD_CARD_CHUNK_SIZE ;
2022-10-18 17:55:47 -06:00
let len = std ::cmp ::min ( GUILD_CARD_CHUNK_SIZE , client . guildcard_data_buffer . as_ref ( ) . unwrap ( ) . len ( ) - start ) ;
2019-09-08 23:54:15 -07:00
let end = start + len ;
2022-10-18 17:55:47 -06:00
let mut buf = [ 0 u8 ; GUILD_CARD_CHUNK_SIZE ] ;
buf [ .. len ] . copy_from_slice ( & client . guildcard_data_buffer . as_ref ( ) . unwrap ( ) [ start .. end ] ) ;
2019-09-08 23:54:15 -07:00
2020-11-09 16:04:42 -07:00
vec! [ SendCharacterPacket ::GuildcardDataChunk ( Box ::new ( GuildcardDataChunk ::new ( chunk , buf , len ) ) ) ]
2019-09-08 23:54:15 -07:00
} else {
Vec ::new ( )
2019-09-15 15:04:12 -07:00
} )
2019-09-08 23:54:15 -07:00
}
2020-11-01 09:04:37 -07:00
async fn set_flag ( & mut self , id : ClientId , setflag : & SetFlag ) -> Result < std ::option ::IntoIter < SendCharacterPacket > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2019-12-01 13:41:30 -08:00
let mut user = client . user . as_mut ( ) . unwrap ( ) ;
user . flags = setflag . flags ;
2021-06-18 17:46:22 -06:00
self . entity_gateway . save_user ( user ) . await . unwrap ( ) ;
2019-12-01 13:41:30 -08:00
Ok ( None . into_iter ( ) )
}
2022-10-18 17:55:47 -06:00
async fn param_data_chunk_request ( & mut self , id : ClientId , _request : & ParamDataChunkRequest ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2019-12-01 13:41:30 -08:00
let chunk = client . param_index ;
client . param_index + = 1 ;
let start = chunk * 0x6800 ;
let end = std ::cmp ::min ( ( chunk + 1 ) * 0x6800 , self . param_data . len ( ) ) ;
let mut data = [ 0 u8 ; 0x6800 ] ;
data [ .. end - start ] . copy_from_slice ( & self . param_data [ start .. end ] ) ;
Ok ( vec! [ SendCharacterPacket ::ParamDataChunk (
2021-06-18 17:46:22 -06:00
Box ::new ( ParamDataChunk {
2019-12-01 13:41:30 -08:00
chunk : chunk as u32 ,
2021-06-18 20:38:29 -06:00
data ,
2021-06-18 17:46:22 -06:00
} )
2019-12-01 13:41:30 -08:00
) ] )
}
// TODO: move USERFLAGS over to SessionAction
2020-11-01 09:04:37 -07:00
async fn character_preview ( & mut self , id : ClientId , preview : & CharacterPreview ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
let mut client = self . clients . write ( ) . await ;
let client = client . get_mut ( & id ) . ok_or_else ( | | CharacterError ::ClientNotFound ( id ) ) ? ;
2019-12-01 13:41:30 -08:00
let mut user = client . user . as_mut ( ) . unwrap ( ) ;
if user . flags = = USERFLAG_NEWCHAR {
2021-06-18 17:46:22 -06:00
new_character ( & mut self . entity_gateway , user , preview ) . await ?
2019-12-01 13:41:30 -08:00
}
if user . flags = = USERFLAG_DRESSINGROOM {
// TODO: dressing room stuff
}
client . session . action = SessionAction ::SelectCharacter ;
client . session . character_slot = preview . slot as u8 ;
user . flags = 0 ;
2021-06-18 17:46:22 -06:00
self . entity_gateway . save_user ( user ) . await . unwrap ( ) ;
2020-03-22 22:40:40 -03:00
Ok ( vec! [ SendCharacterPacket ::LoginResponse ( LoginResponse ::by_char_select ( user . guildcard ,
2019-12-01 13:41:30 -08:00
user . team_id . unwrap_or ( 1 ) ,
client . session ) ) ,
SendCharacterPacket ::CharAck ( CharAck {
slot : preview . slot ,
code : 0
} )
] )
}
2022-10-18 17:55:47 -06:00
async fn select_ship ( & mut self , id : ClientId , menuselect : & MenuSelect ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
2019-10-17 23:41:01 -07:00
if menuselect . menu ! = SHIP_MENU_ID {
2021-06-18 17:46:22 -06:00
return Err ( CharacterError ::InvalidMenuSelection ( menuselect . menu , menuselect . item ) . into ( ) ) ;
2019-10-17 23:41:01 -07:00
}
2022-10-18 17:55:47 -06:00
if let Some ( client ) = self . clients . read ( ) . await . get ( & id ) {
2020-11-25 22:05:55 -07:00
if let Some ( user ) = & client . user {
2022-10-18 17:55:47 -06:00
if let Some ( cc ) = self . connected_clients . write ( ) . await . get_mut ( & user . id ) {
2020-11-25 22:05:55 -07:00
cc . ship_id = Some ( ServerId ( menuselect . item as usize ) ) ;
}
}
}
2022-10-18 17:55:47 -06:00
let ship = self . ships . read ( ) . await ;
let ship = ship . get ( & ServerId ( menuselect . item as usize ) )
. ok_or_else ( | | CharacterError ::InvalidMenuSelection ( menuselect . menu , menuselect . item ) ) ? ;
2020-08-19 23:18:04 -06:00
Ok ( vec! [ SendCharacterPacket ::RedirectClient ( RedirectClient ::new ( u32 ::from_le_bytes ( ship . ip . octets ( ) ) , ship . port ) ) ] )
2019-10-17 23:41:01 -07:00
}
2020-11-18 18:56:04 -07:00
2022-10-18 17:55:47 -06:00
async fn ship_detail ( & mut self , menudetail : & MenuDetail ) -> Result < Vec < SendCharacterPacket > , anyhow ::Error > {
let players = self . connected_clients
. read ( )
. await
. iter ( )
2020-11-18 18:56:04 -07:00
. filter ( | ( _ , client ) | {
client . ship_id = = Some ( ServerId ( menudetail . item as usize ) )
} )
. count ( ) ;
let ship_details = format! ( " players: {} \n rooms: {} " , players , 0 ) ;
Ok ( vec! [ SendCharacterPacket ::SmallLeftDialog ( SmallLeftDialog ::new ( ship_details ) ) ] )
}
2019-08-20 17:59:00 -07:00
}
2020-06-02 18:51:18 -06:00
#[ async_trait::async_trait ]
2022-10-18 04:46:21 -06:00
impl < EG : EntityGateway + Clone > ServerState for CharacterServerState < EG > {
2019-08-24 14:45:58 -07:00
type SendPacket = SendCharacterPacket ;
type RecvPacket = RecvCharacterPacket ;
2022-10-18 04:46:21 -06:00
type Cipher = PSOBBCipher ;
2020-11-01 09:04:37 -07:00
type PacketError = anyhow ::Error ;
2019-08-20 17:59:00 -07:00
2022-10-18 04:46:21 -06:00
async fn on_connect ( & mut self , id : ClientId ) -> Result < Vec < OnConnect < Self ::SendPacket , Self ::Cipher > > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
self . clients . write ( ) . await . insert ( id , ClientState ::new ( ) ) ;
2019-09-15 15:04:12 -07:00
2019-08-20 17:59:00 -07:00
let mut rng = rand ::thread_rng ( ) ;
let mut server_key = [ 0 u8 ; 48 ] ;
let mut client_key = [ 0 u8 ; 48 ] ;
rng . fill ( & mut server_key [ .. ] ) ;
rng . fill ( & mut client_key [ .. ] ) ;
2020-10-30 21:20:03 -06:00
Ok ( vec! [ OnConnect ::Packet ( SendCharacterPacket ::LoginWelcome ( LoginWelcome ::new ( server_key , client_key ) ) ) ,
2022-10-18 04:46:21 -06:00
OnConnect ::Cipher ( PSOBBCipher ::new ( ELSEWHERE_PARRAY , ELSEWHERE_PRIVATE_KEY , client_key ) ,
PSOBBCipher ::new ( ELSEWHERE_PARRAY , ELSEWHERE_PRIVATE_KEY , server_key ) )
//OnConnect::Cipher((Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key)),
// Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key))))
2020-10-30 21:20:03 -06:00
] )
2019-08-20 17:59:00 -07:00
}
2019-09-08 23:54:15 -07:00
2022-10-18 04:46:21 -06:00
async fn handle ( & mut self , id : ClientId , pkt : RecvCharacterPacket ) -> Result < Vec < ( ClientId , SendCharacterPacket ) > , anyhow ::Error > {
2019-09-15 15:04:12 -07:00
Ok ( match pkt {
2019-08-25 04:58:55 -07:00
RecvCharacterPacket ::Login ( login ) = > {
2019-11-04 20:28:50 -08:00
if login . session . action = = SessionAction ::SelectCharacter {
2022-10-18 17:55:47 -06:00
self . send_ship_list ( id , & login ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-23 22:27:43 -07:00
}
else {
2022-10-18 04:46:21 -06:00
self . validate_login ( id , & login ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-23 22:27:43 -07:00
}
2019-08-20 17:59:00 -07:00
} ,
2019-08-25 04:58:55 -07:00
RecvCharacterPacket ::RequestSettings ( _req ) = > {
2022-10-18 04:46:21 -06:00
self . get_settings ( id ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-08-28 17:46:12 -07:00
} ,
RecvCharacterPacket ::CharSelect ( sel ) = > {
2022-10-18 04:46:21 -06:00
self . char_select ( id , & sel ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-08 23:54:15 -07:00
} ,
RecvCharacterPacket ::Checksum ( _checksum ) = > {
2022-10-18 04:46:21 -06:00
self . validate_checksum ( ) . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-08 23:54:15 -07:00
} ,
RecvCharacterPacket ::GuildcardDataRequest ( _request ) = > {
2022-10-18 04:46:21 -06:00
self . guildcard_data_header ( id ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-08 23:54:15 -07:00
} ,
RecvCharacterPacket ::GuildcardDataChunkRequest ( request ) = > {
2022-10-18 17:55:47 -06:00
self . guildcard_data_chunk ( id , request . chunk , request . again ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-13 19:21:33 -07:00
} ,
RecvCharacterPacket ::ParamDataRequest ( _request ) = > {
2022-10-18 04:46:21 -06:00
vec! [ SendCharacterPacket ::ParamDataHeader ( self . param_header . clone ( ) ) ] . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-13 19:21:33 -07:00
} ,
2019-12-01 13:41:30 -08:00
RecvCharacterPacket ::SetFlag ( flag ) = > {
2022-10-18 04:46:21 -06:00
self . set_flag ( id , & flag ) . await ? . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-23 22:27:43 -07:00
} ,
2019-12-01 13:41:30 -08:00
RecvCharacterPacket ::ParamDataChunkRequest ( request ) = > {
2022-10-18 17:55:47 -06:00
self . param_data_chunk_request ( id , & request ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-09-23 22:27:43 -07:00
} ,
RecvCharacterPacket ::CharacterPreview ( preview ) = > {
2022-10-18 04:46:21 -06:00
self . character_preview ( id , & preview ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2019-10-17 23:41:01 -07:00
} ,
RecvCharacterPacket ::MenuSelect ( menuselect ) = > {
2022-10-18 17:55:47 -06:00
self . select_ship ( id , & menuselect ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( )
2020-11-18 18:56:04 -07:00
} ,
RecvCharacterPacket ::MenuDetail ( menudetail ) = > {
match menudetail . menu {
2022-10-18 17:55:47 -06:00
SHIP_MENU_ID = > self . ship_detail ( & menudetail ) . await ? . into_iter ( ) . map ( move | pkt | ( id , pkt ) ) . collect ( ) ,
2022-10-18 04:46:21 -06:00
_ = > Vec ::new ( )
2020-11-18 18:56:04 -07:00
}
2019-09-03 20:30:35 -04:00
}
2019-09-15 15:04:12 -07:00
} )
2019-08-20 17:59:00 -07:00
}
2020-01-08 22:02:51 -08:00
2020-11-01 09:04:37 -07:00
async fn on_disconnect ( & mut self , id : ClientId ) -> Result < Vec < ( ClientId , SendCharacterPacket ) > , anyhow ::Error > {
2022-10-18 17:55:47 -06:00
if let Some ( client ) = self . clients . write ( ) . await . remove ( & id ) {
2020-11-25 22:05:55 -07:00
if let Some ( user ) = client . user {
2022-10-18 17:55:47 -06:00
self . connected_clients . write ( ) . await . remove ( & user . id ) ;
2020-10-27 22:31:54 -06:00
}
}
2020-10-30 21:20:03 -06:00
Ok ( Vec ::new ( ) )
2020-01-08 22:02:51 -08:00
}
2019-08-20 17:59:00 -07:00
}
2020-08-19 23:18:04 -06:00
#[ async_trait::async_trait ]
2022-10-18 04:46:21 -06:00
impl < EG : EntityGateway + Clone > InterserverActor for CharacterServerState < EG > {
2020-08-19 23:18:04 -06:00
type SendMessage = LoginMessage ;
type RecvMessage = ShipMessage ;
type Error = ( ) ;
2020-10-26 00:02:48 -06:00
async fn on_connect ( & mut self , _id : ServerId ) -> Vec < ( ServerId , Self ::SendMessage ) > {
2020-08-19 23:18:04 -06:00
Vec ::new ( )
}
2022-10-18 04:46:21 -06:00
async fn on_action ( & mut self , id : ServerId , msg : Self ::RecvMessage ) -> Result < Vec < ( ServerId , Self ::SendMessage ) > , Self ::Error > {
2022-10-18 17:55:47 -06:00
dbg! ( & id , & msg ) ;
2020-08-19 23:18:04 -06:00
match msg {
2020-11-01 07:49:04 -07:00
ShipMessage ::Authenticate ( auth_token ) = > {
if self . auth_token = = auth_token {
2022-10-18 17:55:47 -06:00
self . authenticated_ships . write ( ) . await . insert ( id ) ;
2020-11-01 07:49:04 -07:00
}
2020-11-18 18:56:04 -07:00
Ok ( Vec ::new ( ) )
2020-11-01 07:49:04 -07:00
} ,
2020-08-19 23:18:04 -06:00
ShipMessage ::NewShip ( new_ship ) = > {
2022-10-18 17:55:47 -06:00
dbg! ( " adding ship " , & id , & new_ship ) ;
if self . authenticated_ships . read ( ) . await . contains ( & id ) {
self . ships . write ( ) . await . insert ( id , new_ship ) ;
2020-11-01 07:49:04 -07:00
}
2022-10-18 17:55:47 -06:00
dbg! ( " ship list " , & self . authenticated_ships ) ;
2020-11-21 23:45:27 -07:00
2022-10-18 17:55:47 -06:00
let ships = self . ships . read ( ) . await . iter ( ) . map ( | ( _ , s ) | s ) . cloned ( ) . collect ::< Vec < _ > > ( ) ;
2020-11-21 23:45:27 -07:00
Ok ( self . ships
2022-10-18 17:55:47 -06:00
. read ( )
. await
2020-11-21 23:45:27 -07:00
. iter ( )
. map ( | ( id , _ ) | {
( * id , LoginMessage ::ShipList { ships : ships . clone ( ) } )
} )
. collect ( ) )
2020-11-18 18:56:04 -07:00
} ,
ShipMessage ::AddUser ( new_user ) = > {
2022-10-18 17:55:47 -06:00
if self . authenticated_ships . read ( ) . await . contains ( & id ) {
self . connected_clients . write ( ) . await . insert ( new_user , ConnectedClient {
2020-11-18 18:56:04 -07:00
ship_id : Some ( id ) ,
expires : None ,
} ) ;
}
Ok ( Vec ::new ( ) )
} ,
ShipMessage ::RemoveUser ( new_user ) = > {
2022-10-18 17:55:47 -06:00
if self . authenticated_ships . read ( ) . await . contains ( & id ) {
self . connected_clients . write ( ) . await . remove ( & new_user ) ;
2020-11-18 18:56:04 -07:00
}
Ok ( Vec ::new ( ) )
} ,
ShipMessage ::RequestShipList = > {
2022-10-18 17:55:47 -06:00
dbg! ( " request ship list " , & self . authenticated_ships ) ;
if self . authenticated_ships . read ( ) . await . contains ( & id ) {
2020-11-18 18:56:04 -07:00
Ok ( vec! [ ( id , LoginMessage ::ShipList {
ships : self . ships
2022-10-18 17:55:47 -06:00
. read ( )
. await
2020-11-18 18:56:04 -07:00
. iter ( )
. map ( | ( _ , ship ) | {
ship
} )
. cloned ( )
. collect ( )
} ) ] )
}
else {
Ok ( Vec ::new ( ) )
}
} ,
ShipMessage ::SendMail { .. } = > {
Ok ( Vec ::new ( ) )
2020-08-19 23:18:04 -06:00
} ,
}
}
async fn on_disconnect ( & mut self , id : ServerId ) -> Vec < ( ServerId , Self ::SendMessage ) > {
2022-10-18 17:55:47 -06:00
self . ships . write ( ) . await . remove ( & id ) ;
self . ship_sender . write ( ) . await . remove ( & id ) ;
self . connected_clients
. write ( )
. await
. retain ( | _ , client | {
2020-11-18 18:56:04 -07:00
client . ship_id ! = Some ( id )
2022-10-18 17:55:47 -06:00
} ) ;
2020-08-19 23:18:04 -06:00
Vec ::new ( )
}
2022-10-18 04:46:21 -06:00
2022-10-18 17:55:47 -06:00
async fn set_sender ( & mut self , server_id : ServerId , sender : channel ::Sender < LoginMessage > ) {
self . ship_sender . write ( ) . await . insert ( server_id , sender ) ;
2022-10-18 04:46:21 -06:00
}
2020-08-19 23:18:04 -06:00
}
2020-01-25 13:01:34 -08:00
2020-03-30 19:28:49 -07:00
fn new_character_from_preview ( user : & UserAccountEntity , preview : & CharacterPreview ) -> NewCharacterEntity {
2022-02-19 20:29:46 +00:00
let mut character = NewCharacterEntity ::new ( user . id , 1 ) ; // it should not be possible for the client to specify the kbm config preset from the char create screen
2020-01-25 13:01:34 -08:00
character . slot = preview . slot ;
2020-01-25 18:02:17 -08:00
character . name = String ::from_utf16_lossy ( & preview . character . name ) . trim_matches ( char ::from ( 0 ) ) . into ( ) ;
2020-01-25 13:01:34 -08:00
character . section_id = preview . character . section_id . into ( ) ;
character . char_class = preview . character . ch_class . into ( ) ;
character . appearance . costume = preview . character . costume ;
character . appearance . skin = preview . character . skin ;
character . appearance . face = preview . character . face ;
character . appearance . head = preview . character . head ;
character . appearance . hair = preview . character . hair ;
character . appearance . hair_r = preview . character . hair_r ;
character . appearance . hair_g = preview . character . hair_g ;
character . appearance . hair_b = preview . character . hair_b ;
character . appearance . prop_x = preview . character . prop_x ;
character . appearance . prop_y = preview . character . prop_y ;
2020-03-29 22:00:07 -07:00
character
2020-01-25 13:01:34 -08:00
}
struct SelectScreenCharacterBuilder < ' a > {
2020-03-29 12:43:20 -07:00
character : Option < & ' a CharacterEntity > ,
2020-01-25 13:01:34 -08:00
level : Option < u32 > ,
}
impl < ' a > SelectScreenCharacterBuilder < ' a > {
fn new ( ) -> SelectScreenCharacterBuilder < ' a > {
SelectScreenCharacterBuilder {
character : None ,
level : None ,
}
}
2020-03-29 12:43:20 -07:00
fn character ( self , character : & ' a CharacterEntity ) -> SelectScreenCharacterBuilder < ' a > {
2020-01-25 13:01:34 -08:00
SelectScreenCharacterBuilder {
character : Some ( character ) ,
.. self
}
}
fn level ( self , level : u32 ) -> SelectScreenCharacterBuilder < ' a > {
SelectScreenCharacterBuilder {
level : Some ( level ) ,
.. self
}
}
fn build ( self ) -> character ::SelectScreenCharacter {
let character = self . character . unwrap ( ) ;
let level = self . level . unwrap ( ) ;
character ::SelectScreenCharacter {
//exp: character.exp,
level : level - 1 ,
//guildcard: character.guildcard,
//_unknown: character._unknown3,
//name_color: character.name_color,
//model: character.model,
//_unused: [0; 15],
//name_color_checksum: character.name_color_checksum,
section_id : character . section_id . into ( ) ,
ch_class : character . char_class . into ( ) ,
//v2flags: character.v2flags,
//version: character.version,
//v1flags: character.v1flags,
costume : character . appearance . costume ,
skin : character . appearance . skin ,
face : character . appearance . face ,
head : character . appearance . head ,
hair : character . appearance . hair ,
hair_r : character . appearance . hair_r ,
hair_g : character . appearance . hair_g ,
hair_b : character . appearance . hair_b ,
prop_x : character . appearance . prop_x ,
prop_y : character . appearance . prop_y ,
name : utf8_to_utf16_array ! ( character . name , 16 ) ,
2022-07-28 20:31:55 -06:00
play_time : character . playtime ,
2020-01-25 13:01:34 -08:00
.. character ::SelectScreenCharacter ::default ( )
}
}
}
2019-08-25 04:59:13 -07:00
#[ cfg(test) ]
mod test {
use super ::* ;
2020-03-29 22:00:07 -07:00
use crate ::entity ::account ::* ;
2020-01-12 22:07:52 -04:00
use libpso ::character ::{ settings , character } ;
2020-10-26 00:02:48 -06:00
use crate ::entity ::gateway ::{ InMemoryGateway , GatewayError } ;
2019-08-25 04:59:13 -07:00
2020-06-02 19:02:06 -06:00
#[ async_std::test ]
async fn test_option_send ( ) {
#[ derive(Clone) ]
2019-08-25 04:59:13 -07:00
struct TestData {
}
2020-06-02 19:02:06 -06:00
#[ async_trait::async_trait ]
2019-10-05 17:37:49 -07:00
impl EntityGateway for TestData {
2022-10-20 14:47:08 -06:00
type Transaction = ( ) ;
2022-04-30 18:16:11 -06:00
async fn get_user_settings_by_user ( & mut self , user : & UserAccountEntity ) -> Result < UserSettingsEntity , GatewayError > {
2020-10-26 00:02:48 -06:00
Ok ( UserSettingsEntity {
2020-03-30 19:28:49 -07:00
id : UserSettingsId ( 0 ) ,
user_id : user . id ,
2019-08-28 20:39:11 -07:00
settings : settings ::UserSettings ::default ( )
2019-08-25 04:59:13 -07:00
} )
}
}
2020-11-01 07:49:04 -07:00
let mut server = CharacterServerState ::new ( TestData { } , AuthToken ( " " . into ( ) ) ) ;
2019-09-15 15:04:12 -07:00
let mut clientstate = ClientState ::new ( ) ;
2020-03-29 16:11:14 -07:00
clientstate . user = Some ( UserAccountEntity {
2020-03-30 19:28:49 -07:00
id : UserAccountId ( 1 ) ,
2019-08-25 04:59:13 -07:00
username : " testuser " . to_owned ( ) ,
password : bcrypt ::hash ( " mypassword " , 5 ) . unwrap ( ) ,
2020-03-22 22:40:40 -03:00
guildcard : 0 ,
2020-10-03 20:12:11 -06:00
banned_until : None ,
muted_until : None ,
created_at : chrono ::Utc ::now ( ) ,
2019-08-25 04:59:13 -07:00
team_id : None ,
2019-09-23 22:27:43 -07:00
flags : 0 ,
2020-10-26 00:02:48 -06:00
activated : true ,
2020-10-27 22:31:54 -06:00
at_login : false ,
at_character : false ,
at_ship : false ,
2019-08-25 04:59:13 -07:00
} ) ;
2022-10-18 17:55:47 -06:00
server . clients . write ( ) . await . insert ( ClientId ( 5 ) , clientstate ) ;
2019-08-25 04:59:13 -07:00
2022-10-18 04:46:21 -06:00
let send = server . handle ( ClientId ( 5 ) , RecvCharacterPacket ::RequestSettings ( RequestSettings { } ) ) . await . unwrap ( ) ;
2019-08-25 04:59:13 -07:00
assert! ( send . len ( ) = = 1 ) ;
2019-09-14 11:43:02 -07:00
assert! ( send [ 0 ] . 0 = = ClientId ( 5 ) ) ;
2019-09-04 09:17:22 -07:00
let bytes = send [ 0 ] . 1. as_bytes ( ) ;
2019-08-25 04:59:13 -07:00
assert! ( bytes [ 2 ] = = 0xE2 ) ;
assert! ( bytes . len ( ) = = 0xAFC ) ;
}
2019-09-03 20:30:35 -04:00
2020-06-02 19:02:06 -06:00
#[ async_std::test ]
async fn test_user_checksum ( ) {
#[ derive(Clone) ]
2019-09-04 09:20:53 -07:00
struct TestData ;
2022-10-20 14:47:08 -06:00
impl EntityGateway for TestData {
type Transaction = ( ) ;
}
2020-11-01 07:49:04 -07:00
let mut server = CharacterServerState ::new ( TestData { } , AuthToken ( " " . into ( ) ) ) ;
2022-10-18 04:46:21 -06:00
let send = server . handle ( ClientId ( 1 ) , RecvCharacterPacket ::Checksum ( Checksum { checksum : 1234 ,
padding : 0 ,
} ) ) . await . unwrap ( ) ;
2019-09-03 20:30:35 -04:00
assert! ( send . len ( ) = = 1 ) ;
2019-09-04 09:20:53 -07:00
let bytes = send [ 0 ] . 1. as_bytes ( ) ;
2019-09-03 20:30:35 -04:00
assert! ( bytes = = [ 0xC , 0 , 0xE8 , 0x02 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 ] ) ;
}
2020-01-12 22:07:52 -04:00
2020-06-02 19:02:06 -06:00
#[ async_std::test ]
async fn test_character_create ( ) {
2022-04-30 18:16:11 -06:00
let mut test_data = InMemoryGateway ::default ( ) ;
2020-01-12 22:07:52 -04:00
let mut fake_user = ClientState ::new ( ) ;
2020-03-29 16:11:14 -07:00
fake_user . user = Some ( UserAccountEntity {
2020-03-30 19:28:49 -07:00
id : UserAccountId ( 3 ) ,
2020-01-12 22:07:52 -04:00
username : " hi3 " . to_string ( ) ,
password : bcrypt ::hash ( " qwer " , 5 ) . unwrap ( ) ,
2020-03-22 22:40:40 -03:00
guildcard : 3 ,
2020-01-12 22:07:52 -04:00
team_id : None ,
2020-10-03 20:12:11 -06:00
banned_until : None ,
muted_until : None ,
created_at : chrono ::Utc ::now ( ) ,
2020-01-12 22:07:52 -04:00
flags : 0 ,
2020-10-26 00:02:48 -06:00
activated : true ,
2020-10-27 22:31:54 -06:00
at_login : false ,
at_character : false ,
at_ship : false ,
2020-01-12 22:07:52 -04:00
} ) ;
2020-11-01 07:49:04 -07:00
let mut server = CharacterServerState ::new ( test_data . clone ( ) , AuthToken ( " " . into ( ) ) ) ;
2022-10-18 17:55:47 -06:00
server . clients . write ( ) . await . insert ( ClientId ( 1 ) , fake_user . clone ( ) ) ;
2022-10-18 04:46:21 -06:00
let mut send = server . handle ( ClientId ( 1 ) , RecvCharacterPacket ::SetFlag ( SetFlag { flags : 1 } ) ) . await . unwrap ( ) ;
2020-06-02 19:02:06 -06:00
assert! ( test_data . get_user_by_id ( UserAccountId ( 3 ) ) . await . unwrap ( ) . flags = = 1 ) ;
2022-10-18 04:46:21 -06:00
send = server . handle ( ClientId ( 1 ) , RecvCharacterPacket ::CharacterPreview ( CharacterPreview { slot : 1 , character : character ::SelectScreenCharacter {
2020-01-12 22:07:52 -04:00
exp : 0 ,
level : 0 ,
guildcard : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ] ,
_unknown : [ 0 , 0 ] ,
name_color : 4294967295 ,
model : 0 ,
_unused : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
name_color_checksum : 0 ,
section_id : 4 ,
ch_class : 2 ,
v2flags : 0 ,
version : 3 ,
v1flags : 49 ,
costume : 0 ,
skin : 4 ,
face : 0 ,
head : 0 ,
hair : 0 ,
hair_r : 0 ,
hair_g : 0 ,
hair_b : 0 ,
prop_x : 0.33333334 ,
prop_y : 0.0 ,
name : [ 9 , 69 , 116 , 101 , 115 , 116 , 32 , 110 , 97 , 109 , 101 , 0 , 0 , 0 , 0 , 0 ] , // "\tEtest name"
play_time : 0 ,
2022-10-18 04:46:21 -06:00
} } ) ) . await . unwrap ( ) ;
2020-01-12 22:07:52 -04:00
assert! ( send . len ( ) = = 2 ) ;
2020-01-25 18:02:17 -08:00
2020-10-26 00:02:48 -06:00
let chars = test_data . get_characters_by_user ( & fake_user . user . unwrap ( ) ) . await . unwrap ( ) ;
2020-01-25 18:02:17 -08:00
assert! ( chars [ 1 ] . as_ref ( ) . unwrap ( ) . name = = " \t Etest name " ) ;
2020-01-12 22:07:52 -04:00
assert! ( chars [ 0 ] . is_none ( ) ) ;
}
2019-09-04 09:20:53 -07:00
}