2025-03-30 21:42:46 -04:00
use kawari ::RECEIVE_BUFFER_SIZE ;
2025-03-30 10:34:42 -04:00
use kawari ::common ::GameData ;
2025-03-22 16:47:21 -04:00
use kawari ::config ::get_config ;
2025-05-02 00:47:11 -04:00
use kawari ::ipc ::kawari ::CustomIpcData ;
use kawari ::ipc ::kawari ::CustomIpcSegment ;
use kawari ::ipc ::kawari ::CustomIpcType ;
use kawari ::ipc ::lobby ::ServiceAccount ;
use kawari ::ipc ::lobby ::{ ClientLobbyIpcData , ServerLobbyIpcSegment } ;
2025-03-17 17:17:19 -04:00
use kawari ::lobby ::LobbyConnection ;
2025-03-21 21:26:32 -04:00
use kawari ::lobby ::send_custom_world_packet ;
2025-03-18 19:49:52 -04:00
use kawari ::packet ::ConnectionType ;
2025-05-02 00:52:26 -04:00
use kawari ::packet ::oodle ::OodleNetwork ;
2025-05-02 00:03:36 -04:00
use kawari ::packet ::{ PacketState , SegmentData , send_keep_alive } ;
2025-03-15 20:36:39 -04:00
use tokio ::io ::AsyncReadExt ;
use tokio ::net ::TcpListener ;
2025-03-08 13:51:50 -05:00
#[ tokio::main ]
async fn main ( ) {
tracing_subscriber ::fmt ::init ( ) ;
2025-03-22 16:47:21 -04:00
let config = get_config ( ) ;
2025-03-08 13:51:50 -05:00
2025-03-22 16:47:21 -04:00
let addr = config . lobby . get_socketaddr ( ) ;
let listener = TcpListener ::bind ( addr ) . await . unwrap ( ) ;
2025-03-29 20:05:20 -04:00
tracing ::info! ( " Server started on {addr} " ) ;
2025-03-08 13:51:50 -05:00
2025-03-30 10:34:42 -04:00
let mut game_data = GameData ::new ( ) ;
2025-05-09 18:35:44 -04:00
let world_name = game_data
. get_world_name ( config . world . world_id )
. expect ( " Unknown world name " ) ;
2025-03-22 17:00:21 -04:00
2025-03-08 13:51:50 -05:00
loop {
let ( socket , _ ) = listener . accept ( ) . await . unwrap ( ) ;
2025-03-16 17:43:29 -04:00
let state = PacketState {
2025-03-09 11:07:01 -04:00
client_key : None ,
2025-03-17 17:22:09 -04:00
clientbound_oodle : OodleNetwork ::new ( ) ,
serverbound_oodle : OodleNetwork ::new ( ) ,
2025-03-09 11:07:01 -04:00
} ;
2025-03-08 16:08:25 -05:00
2025-03-17 16:58:48 -04:00
let mut connection = LobbyConnection {
socket ,
state ,
session_id : None ,
2025-03-21 19:56:16 -04:00
stored_character_creation_name : String ::new ( ) ,
2025-03-22 17:32:00 -04:00
world_name : world_name . clone ( ) ,
2025-04-05 21:36:56 -04:00
service_accounts : Vec ::new ( ) ,
selected_service_account : None ,
2025-03-17 16:58:48 -04:00
} ;
2025-03-15 20:36:39 -04:00
2025-03-08 13:51:50 -05:00
tokio ::spawn ( async move {
2025-03-30 21:42:46 -04:00
let mut buf = vec! [ 0 ; RECEIVE_BUFFER_SIZE ] ;
2025-03-08 13:51:50 -05:00
loop {
2025-03-15 20:36:39 -04:00
let n = connection
. socket
. read ( & mut buf )
. await
. expect ( " Failed to read data! " ) ;
2025-03-08 13:51:50 -05:00
2025-03-08 14:38:31 -05:00
if n ! = 0 {
2025-06-26 19:09:13 -04:00
let ( segments , _ ) = connection . parse_packet ( & buf [ .. n ] ) ;
2025-03-08 23:24:09 -05:00
for segment in & segments {
2025-05-02 00:03:36 -04:00
match & segment . data {
SegmentData ::SecuritySetup { phrase , key } = > {
2025-03-22 17:32:00 -04:00
connection . initialize_encryption ( phrase , key ) . await
2025-03-08 23:24:09 -05:00
}
2025-05-02 00:03:36 -04:00
SegmentData ::Ipc { data } = > match & data . data {
2025-05-01 22:36:30 -04:00
ClientLobbyIpcData ::LoginEx {
2025-04-05 21:36:56 -04:00
sequence ,
2025-03-08 23:24:09 -05:00
session_id ,
version_info ,
} = > {
tracing ::info! (
" Client {session_id} ({version_info}) logging in! "
) ;
2025-04-05 21:36:56 -04:00
let config = get_config ( ) ;
2025-03-09 11:01:06 -04:00
2025-06-18 19:38:00 -04:00
let Ok ( login_reply ) = reqwest ::get ( format! (
2025-04-05 21:36:56 -04:00
" http://{}/_private/service_accounts?sid={} " ,
2025-06-19 16:01:16 -04:00
config . login . server_name , session_id
2025-04-05 21:36:56 -04:00
) )
. await
2025-06-18 19:38:00 -04:00
else {
tracing ::warn! (
" Failed to contact login server, is it running? "
) ;
2025-07-02 21:59:25 -04:00
// "The lobby server connection has encountered an error."
connection . send_error ( * sequence , 2002 , 13001 ) . await ;
2025-06-18 19:38:00 -04:00
break ;
} ;
let Ok ( body ) = login_reply . text ( ) . await else {
tracing ::warn! (
" Failed to contact login server, is it running? "
) ;
2025-07-02 21:59:25 -04:00
// "The lobby server connection has encountered an error."
connection . send_error ( * sequence , 2002 , 13001 ) . await ;
2025-06-18 19:38:00 -04:00
break ;
} ;
2025-03-16 15:20:55 -04:00
2025-04-05 21:36:56 -04:00
let service_accounts : Option < Vec < ServiceAccount > > =
serde_json ::from_str ( & body ) . ok ( ) ;
if let Some ( service_accounts ) = service_accounts {
2025-05-08 21:01:15 -04:00
if service_accounts . is_empty ( ) {
2025-06-18 20:28:03 -04:00
tracing ::warn! (
" This account has no service accounts attached, how did this happen? "
) ;
2025-06-18 20:08:35 -04:00
2025-07-02 21:59:25 -04:00
/* "<the game> has not yet been registered on this platform or your service account's subscription has expired. Please close the application and complete the registration process. If you would like to add a platform to your service account or renew your subscription, please visit the <website>). To register another platform, you must purchase a license for the applicable platform or complete the registration process using the registration code included with your purchase." */
connection . send_error ( * sequence , 2002 , 13209 ) . await ;
2025-05-08 21:01:15 -04:00
} else {
connection . service_accounts = service_accounts ;
connection . session_id = Some ( session_id . clone ( ) ) ;
connection . send_account_list ( ) . await ;
}
2025-04-05 21:36:56 -04:00
} else {
2025-06-18 20:28:03 -04:00
tracing ::warn! (
" Failed to parse service accounts from the login server! "
) ;
2025-06-18 20:08:35 -04:00
2025-07-02 21:59:25 -04:00
// "The lobby server has encountered a problem."
connection . send_error ( * sequence , 2002 , 13006 ) . await ;
2025-04-05 21:36:56 -04:00
}
2025-03-08 23:24:09 -05:00
}
2025-05-01 22:36:30 -04:00
ClientLobbyIpcData ::ServiceLogin { sequence } = > {
2025-04-05 21:36:56 -04:00
// TODO: support selecting a service account
connection . selected_service_account =
Some ( connection . service_accounts [ 0 ] . id ) ;
2025-03-22 17:32:00 -04:00
connection . send_lobby_info ( * sequence ) . await
2025-03-08 23:24:09 -05:00
}
2025-05-01 22:45:49 -04:00
ClientLobbyIpcData ::CharaMake ( character_action ) = > {
2025-03-22 17:32:00 -04:00
connection . handle_character_action ( character_action ) . await
2025-03-13 22:22:02 -04:00
}
2025-06-28 15:10:57 -04:00
ClientLobbyIpcData ::ShandaLogin { .. } = > {
2025-04-22 18:15:13 -04:00
connection . send_account_list ( ) . await ;
}
2025-05-01 22:36:30 -04:00
ClientLobbyIpcData ::GameLogin {
2025-03-09 11:01:06 -04:00
sequence ,
2025-03-21 19:56:16 -04:00
content_id ,
2025-03-09 11:01:06 -04:00
} = > {
2025-03-21 19:56:16 -04:00
tracing ::info! ( " Client is joining the world with {content_id} " ) ;
let our_actor_id ;
// find the actor id for this content id
// NOTE: This is NOT the ideal solution. I theorize the lobby server has it's own records with this information.
{
let ipc_segment = CustomIpcSegment {
unk1 : 0 ,
unk2 : 0 ,
op_code : CustomIpcType ::GetActorId ,
2025-05-02 00:17:15 -04:00
option : 0 ,
2025-03-21 19:56:16 -04:00
timestamp : 0 ,
data : CustomIpcData ::GetActorId {
content_id : * content_id ,
} ,
} ;
2025-03-21 21:26:32 -04:00
let response_segment =
send_custom_world_packet ( ipc_segment ) . await . unwrap ( ) ;
2025-03-21 19:56:16 -04:00
match & response_segment . data {
CustomIpcData ::ActorIdFound { actor_id } = > {
our_actor_id = * actor_id ;
}
2025-03-21 21:26:32 -04:00
_ = > panic! ( " Unexpected custom IPC packet type here! " ) ,
2025-03-21 19:56:16 -04:00
}
}
2025-03-09 11:01:06 -04:00
2025-03-21 19:56:16 -04:00
connection
. send_enter_world ( * sequence , * content_id , our_actor_id )
. await ;
2025-03-09 11:01:06 -04:00
}
2025-06-26 21:06:54 -04:00
_ = > { }
2025-03-08 23:24:09 -05:00
} ,
2025-05-02 00:03:36 -04:00
SegmentData ::KeepAliveRequest { id , timestamp } = > {
2025-03-16 17:43:29 -04:00
send_keep_alive ::< ServerLobbyIpcSegment > (
2025-03-15 20:36:39 -04:00
& mut connection . socket ,
& mut connection . state ,
2025-03-18 19:49:52 -04:00
ConnectionType ::Lobby ,
2025-03-15 20:36:39 -04:00
* id ,
* timestamp ,
)
. await
2025-03-08 23:24:09 -05:00
}
_ = > {
panic! ( " The server is recieving a response packet! " )
}
}
}
2025-03-08 14:38:31 -05:00
}
2025-03-08 13:51:50 -05:00
}
} ) ;
}
}