mirror of
https://github.com/RustySamovar/RustySamovar.git
synced 2024-11-21 18:38:18 +00:00
Add a bunch of misc subsystems
This commit is contained in:
parent
9cac1c8d6c
commit
22b52b373e
@ -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;
|
||||||
|
11
src/subsystems/misc/mod.rs
Normal file
11
src/subsystems/misc/mod.rs
Normal 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;
|
47
src/subsystems/misc/npc.rs
Normal file
47
src/subsystems/misc/npc.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
42
src/subsystems/misc/pause.rs
Normal file
42
src/subsystems/misc/pause.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
59
src/subsystems/misc/scene.rs
Normal file
59
src/subsystems/misc/scene.rs
Normal 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
123
src/subsystems/misc/shop.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
93
src/subsystems/misc/social.rs
Normal file
93
src/subsystems/misc/social.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
Loading…
Reference in New Issue
Block a user