Add a bunch of misc subsystems

This commit is contained in:
Nobody 2022-02-21 00:22:16 +05:00
parent 9cac1c8d6c
commit 22b52b373e
8 changed files with 388 additions and 2 deletions

View File

@ -12,6 +12,8 @@ use crate::JsonManager;
use crate::LuaManager; use crate::LuaManager;
use crate::server::LoginManager; use crate::server::LoginManager;
use std::sync::Arc; use std::sync::Arc;
use crate::subsystems::{NpcSubsystem, ShopSubsystem};
use crate::subsystems::misc::{PauseSubsystem, SceneSubsystem, SocialSubsystem};
pub struct GameServer { pub struct GameServer {
packets_to_process_rx: mpsc::Receiver<IpcMessage>, packets_to_process_rx: mpsc::Receiver<IpcMessage>,
@ -29,7 +31,13 @@ impl GameServer {
let jm = Arc::new(JsonManager::new("./data/json")); let jm = Arc::new(JsonManager::new("./data/json"));
let lm = LoginManager::new(db.clone(), jm.clone(), packets_to_send_tx.clone()); let lm = LoginManager::new(db.clone(), jm.clone(), packets_to_send_tx.clone());
let lum = Arc::new(LuaManager::new("./data/lua")); let lum = Arc::new(LuaManager::new("./data/lua"));
let em = EntitySubsystem::new(lum.clone(), jm.clone(), db.clone(), packets_to_send_tx.clone()); let em = EntitySubsystem::new(lum.clone(), jm.clone(), db.clone(), packets_to_send_tx.clone());
let nt = NpcSubsystem::new(packets_to_send_tx.clone());
let ss = ShopSubsystem::new(jm.clone(), db.clone(), packets_to_send_tx.clone());
let scs = SceneSubsystem::new(packets_to_send_tx.clone());
let ps = PauseSubsystem::new(packets_to_send_tx.clone());
let socs = SocialSubsystem::new(db.clone(), packets_to_send_tx.clone());
let gs = GameServer { let gs = GameServer {
packets_to_process_rx: packets_to_process_rx, packets_to_process_rx: packets_to_process_rx,
@ -38,7 +46,7 @@ impl GameServer {
login_manager: lm, login_manager: lm,
database_manager: db.clone(), database_manager: db.clone(),
json_manager: jm.clone(), json_manager: jm.clone(),
processors: vec![Box::new(em)], processors: vec![Box::new(em), Box::new(nt), Box::new(ss), Box::new(scs), Box::new(ps), Box::new(socs)],
}; };
return gs; return gs;

View File

@ -0,0 +1,11 @@
mod npc;
mod shop;
mod scene;
mod pause;
mod social;
pub use npc::NpcSubsystem;
pub use shop::ShopSubsystem;
pub use scene::SceneSubsystem;
pub use pause::PauseSubsystem;
pub use social::SocialSubsystem;

View File

@ -0,0 +1,47 @@
use std::sync::{mpsc::{self, Sender, Receiver}, Arc, Mutex};
use std::thread;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use crate::server::IpcMessage;
use prost::Message;
use proto;
use proto::{PacketId, CombatTypeArgument, ForwardType, ProtEntityType};
use packet_processor_macro::*;
#[macro_use]
use packet_processor::*;
use serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::utils::{IdManager, TimeManager};
#[packet_processor(
NpcTalkReq,
)]
pub struct NpcSubsystem {
packets_to_send_tx: Sender<IpcMessage>,
}
impl NpcSubsystem {
pub fn new(packets_to_send_tx: Sender<IpcMessage>) -> Self {
let mut nt = Self {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
};
nt.register();
return nt;
}
fn process_npc_talk(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::NpcTalkReq, rsp: &mut proto::NpcTalkRsp) {
// TODO: Real server should analyze data sent by the client and produce extra packets (about quest, rewards, etc)
// As of now we just confirming to the client that he's correct
// TODO: We also don't consider "npc_entity_id" field here.
// It's omitted most of the time (in fact, I've never seen it in the traffic), but maybe it's important...
rsp.cur_talk_id = req.talk_id;
rsp.entity_id = req.entity_id;
}
}

View File

@ -0,0 +1,42 @@
use std::sync::{mpsc::{self, Sender, Receiver}, Arc, Mutex};
use std::thread;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use crate::server::IpcMessage;
use prost::Message;
use proto;
use proto::{PacketId, CombatTypeArgument, ForwardType, ProtEntityType};
use packet_processor_macro::*;
#[macro_use]
use packet_processor::*;
use serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::utils::{IdManager, TimeManager};
#[packet_processor(
PlayerSetPauseReq,
)]
pub struct PauseSubsystem {
packets_to_send_tx: Sender<IpcMessage>,
}
impl PauseSubsystem {
pub fn new(packets_to_send_tx: Sender<IpcMessage>) -> Self {
let mut ps = Self {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
};
ps.register();
return ps;
}
fn process_player_set_pause(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::PlayerSetPauseReq, rsp: &mut proto::PlayerSetPauseRsp) {
// Nothing to do here, maybe check req.is_paused
}
}

View File

@ -0,0 +1,59 @@
use std::sync::{mpsc::{self, Sender, Receiver}, Arc, Mutex};
use std::thread;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use crate::server::IpcMessage;
use prost::Message;
use proto;
use proto::{PacketId, CombatTypeArgument, ForwardType, ProtEntityType};
use packet_processor_macro::*;
#[macro_use]
use packet_processor::*;
use serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::utils::{IdManager, TimeManager};
#[packet_processor(
GetSceneAreaReq,
GetScenePointReq,
)]
pub struct SceneSubsystem {
packets_to_send_tx: Sender<IpcMessage>,
}
impl SceneSubsystem {
pub fn new(packets_to_send_tx: Sender<IpcMessage>) -> Self {
let mut scs = Self {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
};
scs.register();
return scs;
}
fn process_get_scene_area(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetSceneAreaReq, rsp: &mut proto::GetSceneAreaRsp) {
rsp.scene_id = req.scene_id;
// TODO: hardcoded data!
rsp.area_id_list = (1..20).collect();
rsp.city_info_list = vec![
build!(CityInfo { city_id: 1, level: 10,}),
build!(CityInfo { city_id: 2, level: 10,}),
build!(CityInfo { city_id: 3, level: 10,}),
];
}
fn process_get_scene_point(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetScenePointReq, rsp: &mut proto::GetScenePointRsp) {
rsp.scene_id = req.scene_id;
// TODO: hardcoded data!
rsp.unlocked_point_list = (1..250).collect();
rsp.unlock_area_list = (1..11).collect();
//locked_point_list=vec![];
}
}

123
src/subsystems/misc/shop.rs Normal file
View File

@ -0,0 +1,123 @@
use std::sync::{mpsc::{self, Sender, Receiver}, Arc, Mutex};
use std::thread;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use crate::server::IpcMessage;
use prost::Message;
use proto;
use proto::{PacketId, CombatTypeArgument, ForwardType, ProtEntityType};
use packet_processor_macro::*;
#[macro_use]
use packet_processor::*;
use serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::utils::{IdManager, TimeManager};
#[packet_processor(
GetShopReq,
BuyGoodsReq,
)]
pub struct ShopSubsystem {
packets_to_send_tx: Sender<IpcMessage>,
json_manager: Arc<JsonManager>,
db_manager: Arc<DatabaseManager>,
}
impl ShopSubsystem {
pub fn new(jm: Arc<JsonManager>, db: Arc<DatabaseManager>, packets_to_send_tx: Sender<IpcMessage>) -> Self {
let mut ss = Self {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
json_manager: jm.clone(),
db_manager: db.clone(),
};
ss.register();
return ss;
}
fn process_get_shop(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetShopReq, rsp: &mut proto::GetShopRsp) {
let fuck_you_borrow_checker: Vec<crate::jsonmanager::ShopGoods> = vec![];
let shop_goods = self.json_manager.shop_goods.get(&req.shop_type).unwrap_or(&fuck_you_borrow_checker);
// TODO: each item should have it's own refresh time!
let next_refresh_time = TimeManager::timestamp() as u32 + 86400;
let player_level = self.db_manager.get_player_level(user_id).unwrap();
let goods = shop_goods.iter().filter_map(|item| {
// If player's AR is too low or too high, then we don't even show this item to him
if player_level >= item.min_show_level || player_level <= item.max_show_level.unwrap_or(99) {
let item_id = match item.item_id {
Some(item_id) => item_id,
None => match item.rotate_id {
Some(rotate_id) => {
let rotate = match self.json_manager.shop_rotate.get(&rotate_id) {
Some(rotate) => rotate,
None => panic!("Rotate {} not found!", rotate_id),
};
rotate[0].item_id // TODO: should be rotated obviously!
},
None => {
panic!("Both item_id and rotate_id are empty for item {}!", item.goods_id)
}
}
};
let item_refresh_time = self.get_shop_refresh_time(req.shop_type, item_id);
let item_refresh_time = std::cmp::min(item_refresh_time, next_refresh_time);
let begin_time = match item.begin_time { Some(t) => t.timestamp() as u32, None => 0 };
let end_time = match item.end_time { Some(t) => t.timestamp() as u32, None => 0 };
let good = build!(ShopGoods {
goods_id: item.goods_id,
goods_item: Some(build!(ItemParam { item_id: item_id, count: item.item_count, })),
begin_time: begin_time,
end_time: end_time,
next_refresh_time: item_refresh_time,
min_level: item.min_show_level,
max_level: item.max_show_level.unwrap_or(0),
buy_limit: item.buy_limit.unwrap_or(0),
cost_item_list: item.cost_items.iter().filter_map(|ci| if ci.item_id > 0 { Some(build!(ItemParam { item_id: ci.item_id, count: ci.count, })) } else { None }).collect(),
hcoin: item.cost_hcoin.unwrap_or(0),
mcoin: item.cost_mcoin.unwrap_or(0),
scoin: item.cost_scoin.unwrap_or(0),
// TODO: handle preconditions!
});
// TODO: SubTabId / secondary_sheet_id is not filled by a server?
Some(good)
} else {
None
}
}).collect();
rsp.shop = Some(build!(Shop {
shop_type: req.shop_type,
goods_list: goods,
next_refresh_time: next_refresh_time,
}));
}
fn process_buy_goods(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::BuyGoodsReq, rsp: &mut proto::BuyGoodsRsp) {
}
fn get_shop_refresh_time(&self, shop_type: u32, item_id: u32) -> u32 {
// TODO: handle daily, weekly and monthly updates
(TimeManager::timestamp() + 86400) as u32
}
}

View File

@ -0,0 +1,93 @@
use std::sync::{mpsc::{self, Sender, Receiver}, Arc, Mutex};
use std::thread;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use crate::server::IpcMessage;
use chrono::Datelike;
use prost::Message;
use proto;
use proto::{PacketId, CombatTypeArgument, ForwardType, ProtEntityType};
use packet_processor_macro::*;
#[macro_use]
use packet_processor::*;
use serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::utils::{IdManager, TimeManager};
#[packet_processor(
GetPlayerBlacklistReq,
GetPlayerFriendListReq,
GetPlayerSocialDetailReq,
)]
pub struct SocialSubsystem {
packets_to_send_tx: Sender<IpcMessage>,
db: Arc<DatabaseManager>,
}
impl SocialSubsystem {
pub fn new(db: Arc<DatabaseManager>, packets_to_send_tx: Sender<IpcMessage>) -> Self {
let mut socs = Self {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
db: db.clone(),
};
socs.register();
return socs;
}
fn process_get_player_blacklist(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerBlacklistReq, rsp: &mut proto::GetPlayerBlacklistRsp) {
// TODO!
}
fn process_get_player_friend_list(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerFriendListReq, rsp: &mut proto::GetPlayerFriendListRsp) {
// TODO!
}
fn process_get_player_social_detail(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerSocialDetailReq, rsp: &mut proto::GetPlayerSocialDetailRsp) {
let user = match self.db.get_player_info(user_id) {
Some(user) => user,
None => panic!("User {} not found!", user_id),
};
let props = self.db.get_player_props(user_id).unwrap_or_else(|| panic!("Failed to get properties for user {}!", user_id));
let user_level = props[&(proto::PropType::PropPlayerLevel as u32)] as u32;
let world_level = props[&(proto::PropType::PropPlayerWorldLevel as u32)] as u32;
let avatar_info = build!(SocialShowAvatarInfo {
avatar_id: user.avatar_id,
level: 80, // TODO
});
let details = build!(SocialDetail {
uid: user_id,
nickname: user.nick_name.clone(),
level: user_level,
//avatar_id: user.avatar_id,
signature: user.signature.clone(),
birthday: Some(proto::Birthday {month: user.birthday.month(), day: user.birthday.day()}),
world_level: world_level,
online_state: proto::FriendOnlineState::FriendOnline as i32, // TODO
is_friend: true, // TODO
is_mp_mode_available: true, // TODO
name_card_id: user.namecard_id,
finish_achievement_num: user.finish_achievement_num, // TODO
tower_floor_index: user.tower_floor_index as u32,
tower_level_index: user.tower_level_index as u32,
show_avatar_info_list: vec![avatar_info], // TODO
show_name_card_id_list: vec![user.namecard_id], // TODO: add all namecards!
profile_picture: Some(build!(ProfilePicture {
avatar_id: 10000007,
})),
});
rsp.detail_data = Some(details);
}
}

View File

@ -1,3 +1,6 @@
pub mod entity_subsystem; pub mod entity_subsystem;
pub mod misc;
pub use self::entity_subsystem::EntitySubsystem; pub use self::entity_subsystem::EntitySubsystem;
pub use self::misc::NpcSubsystem;
pub use self::misc::ShopSubsystem;