use common::structs::MultiPathAvatar; use proto::chat_data::ExtendType; use std::path::Path; use tokio::fs; use crate::{ net::PlayerSession, util::{self, cur_timestamp_ms}, }; use super::*; const SERVER_UID: u32 = 727; const SERVER_HEAD_ICON: u32 = 201402; const SERVER_CHAT_BUBBLE_ID: u32 = 220005; const SERVER_CHAT_HISTORY: [&str; 6] = [ "'lua {path_to_lua_script}' execute lua script", "'sync' to synchronize stats between json and in-game view", "'mc {mc_id}' mc_id can be set from 8001 to 8008", "'march {march_id}' march_id can be set 1001 or 1224", "available commands:", "visit srtools.neonteam.dev to configure the PS! (you configure relics, equipment, monsters from there)", ]; pub async fn on_get_friend_login_info_cs_req( _session: &mut PlayerSession, _req: &GetFriendLoginInfoCsReq, res: &mut GetFriendLoginInfoScRsp, ) { res.kcgceppmokm = vec![SERVER_UID]; res.omfombgfhpa = vec![SERVER_UID]; } pub async fn on_get_friend_list_info_cs_req( _session: &mut PlayerSession, _req: &GetFriendListInfoCsReq, res: &mut GetFriendListInfoScRsp, ) { res.friend_list = vec![FriendSimpleInfo { remark_name: String::from("RobinSR"), player_info: Some(PlayerSimpleInfo { uid: SERVER_UID, platform: PlatformType::Pc.into(), online_status: FriendOnlineStatus::Online.into(), head_icon: SERVER_HEAD_ICON, chat_bubble_id: SERVER_CHAT_BUBBLE_ID, level: 70, nickname: String::from("Server"), signature: String::from("omg"), ..Default::default() }), is_marked: true, create_time: 0, ..Default::default() }]; } pub async fn on_get_private_chat_history_cs_req( _session: &mut PlayerSession, req: &GetPrivateChatHistoryCsReq, res: &mut GetPrivateChatHistoryScRsp, ) { let cur_time = cur_timestamp_ms(); res.chat_message_list = SERVER_CHAT_HISTORY .iter() .map(|text| ChatMessageData { create_time: cur_time, ckhpffenobe: Some(Eknabklpeel { kpobmnlklok: 1, role_id: SERVER_UID, }), bkoalkhdlob: Some(Eknabklpeel { kpobmnlklok: 1, role_id: SERVER_UID, }), message_datas: vec![MessageChatData { message_type: 1, chat_data: Some(ChatData { extend_type: Some(ExtendType::MessageText(text.to_string())), }), }], ..Default::default() }) .collect(); res.target_side = req.target_side; res.contact_side = SERVER_UID; } pub async fn on_send_msg_cs_req( session: &mut PlayerSession, body: &SendMsgCsReq, _res: &mut SendMsgScRsp, ) { let Some(json) = session.json_data.get_mut() else { tracing::error!("data is not set!"); return; }; let msg = body .message_datas .as_ref() .and_then(|x| x.chat_data.as_ref()) .and_then(|x| x.extend_type.as_ref()) .and_then(|x| match x { ExtendType::MessageText(s) => Some(s.as_str()), _ => None, }) .unwrap_or(""); if let Some((cmd, args)) = parse_command(msg) { match cmd { "sync" => { let _ = session.sync_player().await; session .send(create_send_message( 25, SERVER_UID, body.message_datas .as_ref() .map(|v| v.message_type) .unwrap_or_default(), body.chat_type, String::from("Inventory Synced"), )) .await .unwrap(); } "mc" => { let mc = MultiPathAvatar::from( args.first() .unwrap_or(&"") .parse::() .unwrap_or(json.main_character as u32), ); json.main_character = mc; json.save_persistent().await; session .send(AvatarPathChangedNotify { base_avatar_id: 8001, cur_multi_path_avatar_type: mc as i32, }) .await .unwrap(); let _ = session.sync_player().await; session .send(create_send_message( 25, SERVER_UID, body.message_datas .as_ref() .map(|v| v.message_type) .unwrap_or_default(), body.chat_type, format!("Success change mc to {mc:#?}"), )) .await .unwrap(); } "march" => { let mut march_type = MultiPathAvatar::from( args.first() .unwrap_or(&"") .parse::() .unwrap_or(json.march_type as u32), ); if march_type != MultiPathAvatar::MarchPreservation && march_type != MultiPathAvatar::MarchHunt { march_type = MultiPathAvatar::MarchHunt } json.march_type = march_type; json.save_persistent().await; session .send(AvatarPathChangedNotify { base_avatar_id: 1001, cur_multi_path_avatar_type: march_type as i32, }) .await .unwrap(); session .send(create_send_message( 25, SERVER_UID, body.message_datas .as_ref() .map(|v| v.message_type) .unwrap_or_default(), body.chat_type, format!("Success change march to {march_type:#?}"), )) .await .unwrap(); } "lua" => { let path = Path::new(args.first().unwrap_or(&"")); if !path.is_file() { session .send(create_send_message( 25, SERVER_UID, body.message_datas .as_ref() .map(|v| v.message_type) .unwrap_or_default(), body.chat_type, format!("File {path:?} does not exist!"), )) .await .unwrap(); } let data = match fs::read(&path).await { Ok(file) => file, Err(err) => { session .send(create_send_message( 25, SERVER_UID, body.message_datas .as_ref() .map(|v| v.message_type) .unwrap_or_default(), body.chat_type, format!("Failed to read file: {err:?}"), )) .await .unwrap(); return; } }; session .send(ClientDownloadDataScNotify { download_data: Some(ClientDownloadData { version: 51, time: util::cur_timestamp_ms() as i64, data, ..Default::default() }), }) .await .unwrap(); session .send(create_send_message( 25, SERVER_UID, body.message_datas .as_ref() .map(|v| v.message_type) .unwrap_or_default(), body.chat_type, format!("Executed {path:?}"), )) .await .unwrap(); } _ => {} } } } fn parse_command(command: &str) -> Option<(&str, Vec<&str>)> { let parts: Vec<&str> = command.split_whitespace().collect(); if parts.is_empty() { return Option::None; } Some((parts[0], parts[1..].to_vec())) } fn create_send_message( to: u32, from: u32, message_type: i32, chat_type: i32, msg: String, ) -> RevcMsgScNotify { RevcMsgScNotify { chat_type, dkdlooaaake: to, recv_message_data: Some(ChatMessageData { create_time: cur_timestamp_ms(), ckhpffenobe: Some(Eknabklpeel { kpobmnlklok: 1, role_id: from, }), bkoalkhdlob: Some(Eknabklpeel { kpobmnlklok: 1, role_id: from, }), message_datas: vec![MessageChatData { message_type, chat_data: Some(ChatData { extend_type: Some(chat_data::ExtendType::MessageText(msg)), }), }], ..Default::default() }), } }