Implemented teleportation (using old public data)

This commit is contained in:
Nobody 2022-03-30 03:31:49 +05:00
parent e4ef8a3c36
commit e3241e5749
16 changed files with 512 additions and 222 deletions

View File

@ -1,3 +1,4 @@
use num_traits::Signed;
// Database Manager // Database Manager
use std::collections::HashMap; use std::collections::HashMap;
@ -98,25 +99,27 @@ trait Insertable<A, E>: ActiveModelTrait<Entity = E>
E::Model: IntoActiveModel<A>, E::Model: IntoActiveModel<A>,
E: EntityTrait, E: EntityTrait,
{ {
fn put(self, db: &DatabaseConnection, guid: i64) -> Result<E::Model, DbErr> fn put(self, db: &DatabaseConnection) -> Result<E::Model, DbErr>
{ {
use std::str::FromStr; use std::str::FromStr;
E::insert_many(vec![self]).exec(db).wait()?;
let column = match E::Column::from_str("guid") { let column = match E::Column::from_str("guid") {
Ok(column) => column, Ok(column) => column,
Err(_) => panic!("GUID column not found!"), Err(_) => panic!("GUID column not found!"),
}; };
let guid = self.get(column).unwrap();
E::insert(self).exec(db).wait()?;
let item = E::find().filter( let item = E::find().filter(
Condition::all() Condition::all()
.add(column.eq(guid)) .add(column.eq(guid.clone()))
).one(db).wait()?; ).one(db).wait()?;
match item { match item {
Some(item) => Ok(item), //Ok(item.into_active_model()), Some(item) => Ok(item), //Ok(item.into_active_model()),
None => Err(DbErr::Custom(format!("Failed to find inserted item: {}", guid))) None => Err(DbErr::Custom(format!("Failed to find inserted item: {:?}", guid)))
} }
} }
} }
@ -128,6 +131,40 @@ impl<A,E> Insertable<A,E> for A
E: EntityTrait, E: EntityTrait,
{} {}
/*
This is another hack to update all the fields of the record.
By default, Sea ORM only updates fields that are changed in ActiveModel.
As it is much more convenient to pass Model instead of ActiveModel around, we need this hack.
*/
trait FullyUpdateable<A, E>: ActiveModelTrait<Entity = E>
where
A: ActiveModelTrait<Entity = E>,
E::Model: IntoActiveModel<A>,
E: EntityTrait,
{
fn full_update(mut self, db: &DatabaseConnection) -> Result<E::Model, DbErr>
where <E as sea_orm::EntityTrait>::Model: sea_orm::IntoActiveModel<Self>
{
for col in <<E as EntityTrait>::Column>::iter() {
let val = self.get(col);
self.set(col, val.unwrap());
}
let item: E::Model = E::update(self).exec(db).wait()?;
Ok(item)
}
}
impl<A,E> FullyUpdateable<A,E> for A
where
A: ActiveModelTrait<Entity = E>,
E::Model: IntoActiveModel<A>,
E: EntityTrait,
{}
/* /*
Database manager itself Database manager itself
*/ */
@ -649,6 +686,20 @@ impl DatabaseManager {
return scene_info; return scene_info;
} }
pub fn update_player_scene_info(&self, scene_info: SceneInfo) {
let mut sc_info: super::scene_info::ActiveModel = scene_info.into();
/*for col in <<SceneInfoEntity as EntityTrait>::Column>::iter() {
let val = sc_info.get(col);
sc_info.set(col, val.unwrap());
}
println!("Updating scene info: {:?}", sc_info);*/
let sc_info: SceneInfo = sc_info.full_update(&self.db).unwrap();
}
pub fn get_player_teams(&self, uid: u32) -> Option<Vec<TeamInfo>> { pub fn get_player_teams(&self, uid: u32) -> Option<Vec<TeamInfo>> {
/*let t1 = TeamInfo { /*let t1 = TeamInfo {
uid: uid.clone(), uid: uid.clone(),
@ -759,7 +810,7 @@ impl DatabaseManager {
promote_level: ActiveValue::Set(0), // TODO: 1? promote_level: ActiveValue::Set(0), // TODO: 1?
}; };
let eq_info: EquipInfo = eq_info.put(&self.db, new_guid as i64).unwrap(); let eq_info: EquipInfo = eq_info.put(&self.db).unwrap();
let it_info = super::item_info::ActiveModel { let it_info = super::item_info::ActiveModel {
uid: ActiveValue::Set(uid), uid: ActiveValue::Set(uid),
@ -767,7 +818,7 @@ impl DatabaseManager {
item_id: ActiveValue::Set(item_id), item_id: ActiveValue::Set(item_id),
}; };
let it_info: ItemInfo = it_info.put(&self.db, new_guid as i64).unwrap(); let it_info: ItemInfo = it_info.put(&self.db).unwrap();
let detail = if self.jm.is_item_weapon(item_id) { let detail = if self.jm.is_item_weapon(item_id) {
let affixes: Vec<_> = self.jm.weapons[&item_id].skill_affix.iter() let affixes: Vec<_> = self.jm.weapons[&item_id].skill_affix.iter()
@ -800,7 +851,7 @@ impl DatabaseManager {
main_prop_id: ActiveValue::Set(main_stat), main_prop_id: ActiveValue::Set(main_stat),
}; };
let re_info: ReliquaryInfo = re_info.put(&self.db, new_guid as i64).unwrap(); let re_info: ReliquaryInfo = re_info.put(&self.db).unwrap();
let sub_stats_v: Vec<_> = sub_stats.clone().into_iter() let sub_stats_v: Vec<_> = sub_stats.clone().into_iter()
.map(|s| super::reliquary_prop::ActiveModel { .map(|s| super::reliquary_prop::ActiveModel {
@ -854,7 +905,7 @@ impl DatabaseManager {
item_id: ActiveValue::Set(item_id), item_id: ActiveValue::Set(item_id),
}; };
let it_info: ItemInfo = it_info.put(&self.db, new_guid as i64).unwrap(); let it_info: ItemInfo = it_info.put(&self.db).unwrap();
let detail = if self.jm.is_item_material(item_id) { let detail = if self.jm.is_item_material(item_id) {
// Material // Material
@ -865,7 +916,7 @@ impl DatabaseManager {
// TODO: MaterialDeleteConfig! // TODO: MaterialDeleteConfig!
}; };
let mt_info: MaterialInfo = mt_info.put(&self.db, new_guid as i64).unwrap(); let mt_info: MaterialInfo = mt_info.put(&self.db).unwrap();
proto::item::Detail::Material(build!(Material { proto::item::Detail::Material(build!(Material {
count: mt_info.count, count: mt_info.count,
@ -880,7 +931,7 @@ impl DatabaseManager {
count: ActiveValue::Set(count), count: ActiveValue::Set(count),
}; };
let fr_info: FurnitureInfo = fr_info.put(&self.db, new_guid as i64).unwrap(); let fr_info: FurnitureInfo = fr_info.put(&self.db).unwrap();
proto::item::Detail::Furniture(build!(Furniture { proto::item::Detail::Furniture(build!(Furniture {
count: fr_info.count, count: fr_info.count,

View File

@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "scene_info")] #[sea_orm(table_name = "scene_info")]
pub struct Model { pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key, autoincrement = false)]
pub uid: u32, pub uid: u32,
pub scene_id: u32, pub scene_id: u32,
pub scene_token: u32, pub scene_token: u32,

View File

@ -0,0 +1,277 @@
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};
use crate::luamanager::Vector;
use super::entities::Entity;
#[derive(Debug, Clone)]
struct Player {
player_id: u32,
pos: Vector,
current_scene: u32,
current_block: u32,
entities: HashMap<u32, Arc<Entity>>,
lua_manager: Arc<LuaManager>,
json_manager: Arc<JsonManager>,
db_manager: Arc<DatabaseManager>,
packets_to_send_tx: Sender<IpcMessage>,
}
impl Player {
const DESPAWN_DISTANCE: f32 = 100.0;
const SPAWN_DISTANCE: f32 = Self::DESPAWN_DISTANCE * 0.8;
const RESPAWN_TIME: i32 = 10; // In seconds
pub fn despawn_everything(&self) {
let entity_list: Vec<u32> = self.entities.iter().map(|(k, v)| *k).collect();
if entity_list.len() > 0 {
// TODO: HACK!
let player_id = self.player_id;
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
build_and_send!(self, player_id, metadata, SceneEntityDisappearNotify {
entity_list: entity_list,
disappear_type: proto::VisionType::VisionMiss as i32,
})
}
}
pub fn position_changed(&mut self) {
// 1. Go through the list of spawned entities and despawn those that are too far from us
let despawn_list: Vec<u32> = self.entities.iter()
.filter(|(k, v)| v.pos().sub(&self.pos).len() > Self::DESPAWN_DISTANCE)
.map(|(k, v)| *k)
.collect();
if despawn_list.len() > 0 {
for k in despawn_list.iter() {
self.entities.remove(&k);
}
// TODO: HACK!
let player_id = self.player_id;
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
build_and_send!(self, player_id, metadata, SceneEntityDisappearNotify {
entity_list: despawn_list,
disappear_type: proto::VisionType::VisionMiss as i32,
});
}
// 2. Go through the list of available entities and spawn those that are close to us and their respawn timeout (in case of collectibles and monsters) is over
let spawned_list: HashSet<u32> = self.entities.iter().map(|(k, v)| *k).collect();
// TODO: do this once only on block change!
let scene = self.lua_manager.get_scene_by_id(self.current_scene).unwrap();
let block = match scene.get_block_by_id(self.current_block) { // TODO: this is due to some blocks missing
Ok(block) => block,
Err(_) => return,
};
let spawn_list: Vec<Arc<Entity>> = block.entities.iter()
.filter(|(entity_id, entity)| !spawned_list.contains(entity_id)) // If entity isn't spawned already...
.filter(|(entity_id, entity)| entity.pos().sub(&self.pos).len() < Self::SPAWN_DISTANCE) // ... and is close enough
.map(|(entity_id, entity)| (*entity).clone())
.collect();
if spawn_list.len() > 0 {
// TODO: HACK!
let player_id = self.player_id;
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
let world_level = self.db_manager.get_player_world_level(self.player_id).unwrap() as u32;
build_and_send!(self, player_id, metadata, SceneEntityAppearNotify {
entity_list: spawn_list.iter().map(|e| e.convert(world_level, &self.json_manager, &self.db_manager)).collect(),
appear_type: proto::VisionType::VisionBorn as i32,
});
for entity in spawn_list.into_iter() {
self.entities.insert(entity.entity_id, entity.clone());
}
}
}
pub fn enter_scene(&self, enter_type: &proto::EnterType, token: u32) {
let world_level = self.db_manager.get_player_world_level(self.player_id).unwrap() as u32;
let player_id = self.player_id;
let mut scene_info = self.db_manager.get_player_scene_info(player_id).unwrap();
scene_info.scene_id = self.current_scene;
scene_info.scene_token = token;
scene_info.pos_x = self.pos.x;
scene_info.pos_y = self.pos.y;
scene_info.pos_z = self.pos.z;
self.db_manager.update_player_scene_info(scene_info);
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
build_and_send! (self, player_id, metadata, PlayerEnterSceneNotify {
scene_id: self.current_scene,
r#type: *enter_type as i32,
scene_begin_time: TimeManager::timestamp(),
pos: Some((&self.pos).into()),
target_uid: self.player_id,
world_level: world_level,
enter_scene_token: token,
//enter_reason: 1,
});
}
// Gatherable stuff is described in GatherExcelConfigData
}
pub struct EntityManager {
packets_to_send_tx: Sender<IpcMessage>,
players: Arc<Mutex<HashMap<u32, Player>>>,
players_moved: Sender<u32>,
lua_manager: Arc<LuaManager>,
json_manager: Arc<JsonManager>,
db_manager: Arc<DatabaseManager>,
}
impl EntityManager {
pub fn new(lua_manager: Arc<LuaManager>, json_manager: Arc<JsonManager>, db_manager: Arc<DatabaseManager>, packets_to_send_tx: Sender<IpcMessage>) -> Self {
let (tx, rx): (Sender<u32>, Receiver<u32>) = mpsc::channel();
let mut es = Self {
packets_to_send_tx: packets_to_send_tx,
players_moved: tx,
players: Arc::new(Mutex::new(HashMap::new())),
lua_manager: lua_manager,
json_manager: json_manager,
db_manager: db_manager,
};
es.run(rx);
return es;
}
fn run(&self, mut rx: Receiver<u32>) {
let players = self.players.clone();
let lua_manager = self.lua_manager.clone();
thread::spawn(move || {
loop {
let player_id = rx.recv().unwrap();
match players.lock() {
Ok(mut players) => {
let mut player = &mut players.get_mut(&player_id).unwrap();
let scene = lua_manager.get_scene_by_id(player.current_scene).unwrap();
let block = scene.get_block_by_pos(&player.pos);
match block {
Ok(block) =>
if player.current_block != block.block_id {
println!("Player {:?} moved to the block {:?}", player.player_id, block.block_id);
player.current_block = block.block_id;
},
Err(_) => {
// TODO?
player.current_block = 0;
},
};
player.position_changed();
},
Err(_) => panic!("Failed to grab player data!"),
};
}
});
}
pub fn player_moved(&self, user_id: u32, pos: Vector) {
match self.players.lock()
{
Ok(mut players) => match players.entry(user_id) {
Occupied(mut player) => {
let mut player = player.get_mut();
// HACK: if player moved too far away, then he's probably teleported just now; don't change position, we're in the process of teleportation
if player.pos.sub(&pos).len() < 10.0 {
player.pos = pos;
} else {
println!("WARN: Teleport detected, hack applied!");
}
},
Vacant(entry) => {
panic!("Moving of nonexistent player: {}", user_id);
},
},
Err(_) => panic!("Failed to grab player data!"),
};
self.players_moved.send(user_id).unwrap();
}
pub fn player_teleported(&self, user_id: u32, pos: Vector, scene_id: u32, token: u32, reason: &proto::EnterType) {
match self.players.lock()
{
Ok(mut players) => match players.entry(user_id) {
Occupied(mut player) => {
let mut player = player.get_mut();
player.pos = pos;
// TODO: check for scene_id change!
player.current_scene = scene_id;
player.enter_scene(reason, token);
},
Vacant(entry) => {
let player = Player {
player_id: user_id,
pos: pos,
current_block: 0,
current_scene: scene_id,
entities: HashMap::new(),
lua_manager: self.lua_manager.clone(),
json_manager: self.json_manager.clone(),
db_manager: self.db_manager.clone(),
packets_to_send_tx: self.packets_to_send_tx.clone(),
};
player.enter_scene(reason, token);
entry.insert(player);
},
},
Err(_) => panic!("Failed to grab player data!"),
};
self.players_moved.send(user_id).unwrap();
}
}

5
src/entitymanager/mod.rs Normal file
View File

@ -0,0 +1,5 @@
mod entity_manager;
mod entities;
pub use self::entity_manager::EntityManager;
pub use self::entities::{Entity, EntityTrait};

View File

@ -12,6 +12,7 @@ use crate::jsonmanager::material::Material;
use crate::jsonmanager::reliquary::{Reliquary, ReliquaryAffix, ReliquaryMainProp}; use crate::jsonmanager::reliquary::{Reliquary, ReliquaryAffix, ReliquaryMainProp};
use crate::jsonmanager::shop_goods::ShopGoods; use crate::jsonmanager::shop_goods::ShopGoods;
use crate::jsonmanager::shop_rotate::ShopRotate; use crate::jsonmanager::shop_rotate::ShopRotate;
use crate::jsonmanager::teleport_point::TeleportPoint;
use crate::jsonmanager::weapon::Weapon; use crate::jsonmanager::weapon::Weapon;
use super::avatar_skill_depot::AvatarSkillDepot; use super::avatar_skill_depot::AvatarSkillDepot;
@ -54,6 +55,8 @@ pub struct JsonManager {
pub reliquary_affixes: HashMap<u32, Vec<ReliquaryAffix>>, pub reliquary_affixes: HashMap<u32, Vec<ReliquaryAffix>>,
pub materials: HashMap<u32, Material>, pub materials: HashMap<u32, Material>,
pub teleport_points: HashMap<u32, HashMap<u32, TeleportPoint>>,
} }
impl std::fmt::Debug for JsonManager { // TODO: fucking hack! impl std::fmt::Debug for JsonManager { // TODO: fucking hack!
@ -66,23 +69,25 @@ impl JsonManager {
pub fn new(directory: &str) -> JsonManager { pub fn new(directory: &str) -> JsonManager {
let reader = JsonReader::new(directory); let reader = JsonReader::new(directory);
let asd: Vec<AvatarSkillDepot> = reader.read_json_list("AvatarSkillDepot"); let asd: Vec<AvatarSkillDepot> = reader.read_json_list_game("AvatarSkillDepot");
let mc: Vec<EntityCurve> = reader.read_json_list("MonsterCurve"); let mc: Vec<EntityCurve> = reader.read_json_list_game("MonsterCurve");
let monsters: Vec<Monster> = reader.read_json_list("Monster"); let monsters: Vec<Monster> = reader.read_json_list_game("Monster");
let world_levels: Vec<WorldLevel> = reader.read_json_list("WorldLevel"); let world_levels: Vec<WorldLevel> = reader.read_json_list_game("WorldLevel");
let gadget_props: Vec<GadgetProp> = reader.read_json_list("GadgetProp"); let gadget_props: Vec<GadgetProp> = reader.read_json_list_game("GadgetProp");
let gc: Vec<EntityCurve> = reader.read_json_list("GadgetCurve"); let gc: Vec<EntityCurve> = reader.read_json_list_game("GadgetCurve");
let gathers: Vec<Gather> = reader.read_json_list("Gather"); let gathers: Vec<Gather> = reader.read_json_list_game("Gather");
let shop_goods: Vec<ShopGoods> = reader.read_json_list("ShopGoods"); let shop_goods: Vec<ShopGoods> = reader.read_json_list_game("ShopGoods");
let shop_rotate: Vec<ShopRotate> = reader.read_json_list("ShopRotate"); let shop_rotate: Vec<ShopRotate> = reader.read_json_list_game("ShopRotate");
let weapons: Vec<Weapon> = reader.read_json_list("Weapon"); let weapons: Vec<Weapon> = reader.read_json_list_game("Weapon");
let reliquaries: Vec<Reliquary> = reader.read_json_list("Reliquary"); let reliquaries: Vec<Reliquary> = reader.read_json_list_game("Reliquary");
let reliquary_main_prop_depot : Vec<ReliquaryMainProp> = reader.read_json_list("ReliquaryMainProp"); let reliquary_main_prop_depot : Vec<ReliquaryMainProp> = reader.read_json_list_game("ReliquaryMainProp");
let reliquary_affixes : Vec<ReliquaryAffix> = reader.read_json_list("ReliquaryAffix"); let reliquary_affixes : Vec<ReliquaryAffix> = reader.read_json_list_game("ReliquaryAffix");
let materials: Vec<Material> = reader.read_json_list("Material"); let materials: Vec<Material> = reader.read_json_list_game("Material");
let teleport_points: Vec<TeleportPoint> = reader.read_json_list_3rdparty("TeleportPoints");
return JsonManager { return JsonManager {
reader: reader, reader: reader,
@ -106,6 +111,10 @@ impl JsonManager {
.collect(), // TODO: we're grouping by depot_id! .collect(), // TODO: we're grouping by depot_id!
materials: materials.into_iter().map(|m| (m.id, m)).collect(), materials: materials.into_iter().map(|m| (m.id, m)).collect(),
teleport_points: group_nonconsec_by(teleport_points, |tp| tp.scene_id).into_iter()
.map(|(scene_id, tp_list)| (scene_id, tp_list.into_iter().map(|tp| (tp.point_id, tp)).collect()))
.collect(),
}; };
} }
@ -152,14 +161,26 @@ impl JsonReader {
}; };
} }
fn read_json_list<T>(&self, name: &str) -> Vec<T> fn read_json_list<T>(&self, name: &str, subpath: &str) -> Vec<T>
where T: DeserializeOwned where T: DeserializeOwned
{ {
let path = format!("{}/{}ExcelConfigData.json", self.base_path, name); let path = format!("{}/{}/{}.json", self.base_path, subpath, name);
let json_file_path = Path::new(&path); let json_file_path = Path::new(&path);
let json_file_str = read_to_string(json_file_path).unwrap_or_else(|_| panic!("File {} not found", path)); let json_file_str = read_to_string(json_file_path).unwrap_or_else(|_| panic!("File {} not found", path));
let data: Vec<T> = serde_json::from_str(&json_file_str).expect(&format!("Error while reading json {}", name)); let data: Vec<T> = serde_json::from_str(&json_file_str).expect(&format!("Error while reading json {}", name));
return data; return data;
} }
fn read_json_list_game<T>(&self, name: &str) -> Vec<T>
where T: DeserializeOwned
{
self.read_json_list(&format!("{}ExcelConfigData", name), "game")
}
fn read_json_list_3rdparty<T>(&self, name: &str) -> Vec<T>
where T: DeserializeOwned
{
self.read_json_list(name, "thirdparty")
}
} }

View File

@ -13,6 +13,7 @@ mod shop_rotate;
mod weapon; mod weapon;
mod reliquary; mod reliquary;
mod material; mod material;
mod teleport_point;
pub use entity_curve::{CurveInfo,EntityCurve}; pub use entity_curve::{CurveInfo,EntityCurve};
pub use shop_goods::ShopGoods; pub use shop_goods::ShopGoods;

View File

@ -0,0 +1,22 @@
use serde::{Serialize, Deserialize};
#[derive(Deserialize, Clone)]
#[serde(rename_all="PascalCase")]
pub struct Vector {
#[serde(default)]
pub x: f32,
#[serde(default)]
pub y: f32,
#[serde(default)]
pub z: f32,
}
#[derive(Deserialize, Clone)]
#[serde(rename_all="PascalCase")]
pub struct TeleportPoint {
pub scene_id: u32,
pub point_id: u32,
#[serde(flatten)]
pub position: Vector,
pub rotation: Vector,
}

View File

@ -3,7 +3,7 @@ use std::result::Result;
use std::sync::Arc; use std::sync::Arc;
use crate::utils::IdManager; use crate::utils::IdManager;
use crate::subsystems::entity_subsystem::{Entity, EntityTrait}; use crate::entitymanager::{Entity, EntityTrait};
use lua_serde::from_file; use lua_serde::from_file;

View File

@ -12,6 +12,7 @@ mod utils;
mod dbmanager; mod dbmanager;
mod jsonmanager; mod jsonmanager;
mod luamanager; mod luamanager;
mod entitymanager;
mod subsystems; mod subsystems;
@ -21,6 +22,7 @@ use dbmanager::DatabaseManager;
use jsonmanager::JsonManager; use jsonmanager::JsonManager;
use luamanager::LuaManager; use luamanager::LuaManager;
use subsystems::EntitySubsystem; use subsystems::EntitySubsystem;
use entitymanager::EntityManager;
fn main() { fn main() {
//pretty_env_logger::init(); //pretty_env_logger::init();

View File

@ -12,8 +12,9 @@ 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::entitymanager::EntityManager;
use crate::subsystems::{InventorySubsystem, NpcSubsystem, ShopSubsystem}; use crate::subsystems::{InventorySubsystem, NpcSubsystem, ShopSubsystem};
use crate::subsystems::misc::{PauseSubsystem, SceneSubsystem, SocialSubsystem}; use crate::subsystems::misc::{PauseSubsystem, SceneSubsystem, SocialSubsystem, TeleportSubsystem};
pub struct GameServer { pub struct GameServer {
packets_to_process_rx: mpsc::Receiver<IpcMessage>, packets_to_process_rx: mpsc::Receiver<IpcMessage>,
@ -29,17 +30,19 @@ impl GameServer {
pub fn new(packets_to_process_rx: mpsc::Receiver<IpcMessage>, packets_to_send_tx: mpsc::Sender<IpcMessage>) -> GameServer { pub fn new(packets_to_process_rx: mpsc::Receiver<IpcMessage>, packets_to_send_tx: mpsc::Sender<IpcMessage>) -> GameServer {
let jm = Arc::new(JsonManager::new("./data/json")); let jm = Arc::new(JsonManager::new("./data/json"));
let db = Arc::new(DatabaseManager::new("sqlite://./database.db3", jm.clone())); let db = Arc::new(DatabaseManager::new("sqlite://./database.db3", jm.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 = Arc::new(EntityManager::new(lum.clone(),jm.clone(), db.clone(), packets_to_send_tx.clone()));
let lm = LoginManager::new(db.clone(), jm.clone(), em.clone(),packets_to_send_tx.clone());
let inv = Arc::new(InventorySubsystem::new(jm.clone(), db.clone(), packets_to_send_tx.clone())); let inv = Arc::new(InventorySubsystem::new(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 es = EntitySubsystem::new(lum.clone(), jm.clone(), db.clone(), em.clone(), packets_to_send_tx.clone());
let nt = NpcSubsystem::new(packets_to_send_tx.clone()); let nt = NpcSubsystem::new(packets_to_send_tx.clone());
let ss = ShopSubsystem::new(jm.clone(), db.clone(), inv.clone(), packets_to_send_tx.clone()); let ss = ShopSubsystem::new(jm.clone(), db.clone(), inv.clone(), packets_to_send_tx.clone());
let scs = SceneSubsystem::new(packets_to_send_tx.clone()); let scs = SceneSubsystem::new(packets_to_send_tx.clone());
let ps = PauseSubsystem::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 socs = SocialSubsystem::new(db.clone(), packets_to_send_tx.clone());
let ts = TeleportSubsystem::new(jm.clone(), db.clone(), em.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,
@ -48,7 +51,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), Box::new(nt), Box::new(ss), Box::new(scs), Box::new(ps), Box::new(socs)], processors: vec![Box::new(es), Box::new(nt), Box::new(ss), Box::new(scs), Box::new(ps), Box::new(socs), Box::new(ts)],
}; };
return gs; return gs;

View File

@ -9,28 +9,31 @@ use packet_processor_macro::*;
#[macro_use] #[macro_use]
use packet_processor::*; use packet_processor::*;
use crate::DatabaseManager; use crate::{DatabaseManager, luamanager};
use crate::JsonManager; use crate::JsonManager;
use crate::utils::{AvatarBuilder, IdManager, Remapper}; use crate::utils::{AvatarBuilder, IdManager, Remapper};
use crate::utils::TimeManager; use crate::utils::TimeManager;
use crate::dbmanager::database_manager::AvatarInfo as DbAvatarInfo; use crate::dbmanager::database_manager::AvatarInfo as DbAvatarInfo;
use crate::entitymanager::EntityManager;
#[packet_processor(PlayerLoginReq)] #[packet_processor(PlayerLoginReq)]
pub struct LoginManager { pub struct LoginManager {
packets_to_send_tx: mpsc::Sender<IpcMessage>, packets_to_send_tx: mpsc::Sender<IpcMessage>,
db: Arc<DatabaseManager>, db: Arc<DatabaseManager>,
jm: Arc<JsonManager>, jm: Arc<JsonManager>,
em: Arc<EntityManager>,
} }
impl LoginManager { impl LoginManager {
pub fn new(db: Arc<DatabaseManager>, jm: Arc<JsonManager>, packets_to_send_tx: mpsc::Sender<IpcMessage>) -> LoginManager { pub fn new(db: Arc<DatabaseManager>, jm: Arc<JsonManager>, em: Arc<EntityManager>, packets_to_send_tx: mpsc::Sender<IpcMessage>) -> LoginManager {
let mut lm = LoginManager { let mut lm = LoginManager {
packet_callbacks: HashMap::new(), packet_callbacks: HashMap::new(),
packets_to_send_tx: packets_to_send_tx, packets_to_send_tx: packets_to_send_tx,
db: db.clone(), db: db,
jm: jm.clone(), jm: jm,
em: em,
}; };
lm.register(); lm.register();
@ -112,16 +115,9 @@ impl LoginManager {
owned_flycloak_list: vec![140001], // TODO! owned_flycloak_list: vec![140001], // TODO!
}); });
build_and_send! (self, user_id, metadata, PlayerEnterSceneNotify { let pos = luamanager::Vector {x: scene_info.pos_x, y: scene_info.pos_y, z: scene_info.pos_z};
scene_id: scene_info.scene_id,
r#type: proto::EnterType::EnterSelf as i32, self.em.player_teleported(user_id, pos, scene_info.scene_id, scene_info.scene_token, &proto::EnterType::EnterSelf);
scene_begin_time: TimeManager::timestamp(),
pos: Some(proto::Vector {x: scene_info.pos_x, y: scene_info.pos_y, z: scene_info.pos_z}),
target_uid: user_id,
world_level: world_level,
enter_scene_token: scene_info.scene_token,
//enter_reason: 1,
});
} }
fn retrieve_team_info(&self, user_id: u32) -> HashMap<u32, proto::AvatarTeam> { fn retrieve_team_info(&self, user_id: u32) -> HashMap<u32, proto::AvatarTeam> {

View File

@ -15,178 +15,38 @@ use packet_processor_macro::*;
use packet_processor::*; use packet_processor::*;
use serde_json::de::Read; use serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager}; use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::entitymanager::EntityManager;
use crate::utils::{IdManager, TimeManager}; use crate::utils::{IdManager, TimeManager};
use crate::luamanager::Vector; use crate::luamanager::Vector;
use super::entities::Entity;
#[derive(Debug, Clone)]
struct Player {
player_id: u32,
pos: Vector,
current_scene: u32,
current_block: u32,
entities: HashMap<u32, Arc<Entity>>,
lua_manager: Arc<LuaManager>,
json_manager: Arc<JsonManager>,
db_manager: Arc<DatabaseManager>,
packets_to_send_tx: Sender<IpcMessage>,
}
impl Player {
const DESPAWN_DISTANCE: f32 = 100.0;
const SPAWN_DISTANCE: f32 = Self::DESPAWN_DISTANCE * 0.8;
const RESPAWN_TIME: i32 = 10; // In seconds
pub fn despawn_everything(&self) {
let entity_list: Vec<u32> = self.entities.iter().map(|(k, v)| *k).collect();
if entity_list.len() > 0 {
// TODO: HACK!
let player_id = self.player_id;
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
build_and_send!(self, player_id, metadata, SceneEntityDisappearNotify {
entity_list: entity_list,
disappear_type: proto::VisionType::VisionMiss as i32,
})
}
}
pub fn position_changed(&mut self) {
// 1. Go through the list of spawned entities and despawn those that are too far from us
let despawn_list: Vec<u32> = self.entities.iter()
.filter(|(k, v)| v.pos().sub(&self.pos).len() > Self::DESPAWN_DISTANCE)
.map(|(k, v)| *k)
.collect();
if despawn_list.len() > 0 {
for k in despawn_list.iter() {
self.entities.remove(&k);
}
// TODO: HACK!
let player_id = self.player_id;
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
build_and_send!(self, player_id, metadata, SceneEntityDisappearNotify {
entity_list: despawn_list,
disappear_type: proto::VisionType::VisionMiss as i32,
});
}
// 2. Go through the list of available entities and spawn those that are close to us and their respawn timeout (in case of collectibles and monsters) is over
let spawned_list: HashSet<u32> = self.entities.iter().map(|(k, v)| *k).collect();
// TODO: do this once only on block change!
let scene = self.lua_manager.get_scene_by_id(self.current_scene).unwrap();
let block = match scene.get_block_by_id(self.current_block) { // TODO: this is due to some blocks missing
Ok(block) => block,
Err(_) => return,
};
let spawn_list: Vec<Arc<Entity>> = block.entities.iter()
.filter(|(entity_id, entity)| !spawned_list.contains(entity_id)) // If entity isn't spawned already...
.filter(|(entity_id, entity)| entity.pos().sub(&self.pos).len() < Self::SPAWN_DISTANCE) // ... and is close enough
.map(|(entity_id, entity)| (*entity).clone())
.collect();
if spawn_list.len() > 0 {
// TODO: HACK!
let player_id = self.player_id;
let metadata = &build!(PacketHead {
sent_ms: TimeManager::timestamp(),
client_sequence_id: 0,
});
let world_level = self.db_manager.get_player_world_level(self.player_id).unwrap() as u32; // TODO: hardcoded value!
build_and_send!(self, player_id, metadata, SceneEntityAppearNotify {
entity_list: spawn_list.iter().map(|e| e.convert(world_level, &self.json_manager, &self.db_manager)).collect(),
appear_type: proto::VisionType::VisionBorn as i32,
});
for entity in spawn_list.into_iter() {
self.entities.insert(entity.entity_id, entity.clone());
}
}
}
// Gatherable stuff is described in GatherExcelConfigData
}
#[packet_processor( #[packet_processor(
CombatInvocationsNotify, CombatInvocationsNotify,
)] )]
pub struct EntitySubsystem { pub struct EntitySubsystem {
packets_to_send_tx: Sender<IpcMessage>, packets_to_send_tx: Sender<IpcMessage>,
players: Arc<Mutex<HashMap<u32, Player>>>,
players_moved: Sender<u32>,
lua_manager: Arc<LuaManager>, lua_manager: Arc<LuaManager>,
json_manager: Arc<JsonManager>, json_manager: Arc<JsonManager>,
db_manager: Arc<DatabaseManager>, db_manager: Arc<DatabaseManager>,
entity_manager: Arc<EntityManager>,
} }
impl EntitySubsystem { impl EntitySubsystem {
pub fn new(lua_manager: Arc<LuaManager>, json_manager: Arc<JsonManager>, db_manager: Arc<DatabaseManager>, packets_to_send_tx: Sender<IpcMessage>) -> EntitySubsystem { pub fn new(lua_manager: Arc<LuaManager>, json_manager: Arc<JsonManager>, db_manager: Arc<DatabaseManager>, entity_manager: Arc<EntityManager>, packets_to_send_tx: Sender<IpcMessage>) -> EntitySubsystem {
let (tx, rx): (Sender<u32>, Receiver<u32>) = mpsc::channel();
let mut es = EntitySubsystem { let mut es = EntitySubsystem {
packets_to_send_tx: packets_to_send_tx, packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(), packet_callbacks: HashMap::new(),
players_moved: tx,
players: Arc::new(Mutex::new(HashMap::new())),
lua_manager: lua_manager, lua_manager: lua_manager,
json_manager: json_manager, json_manager: json_manager,
db_manager: db_manager, db_manager: db_manager,
entity_manager: entity_manager,
}; };
es.register(); es.register();
es.run(rx);
return es; return es;
} }
fn run(&self, mut rx: Receiver<u32>) {
let players = self.players.clone();
let lua_manager = self.lua_manager.clone();
thread::spawn(move || {
loop {
let player_id = rx.recv().unwrap();
match players.lock() {
Ok(mut players) => {
let mut player = &mut players.get_mut(&player_id).unwrap();
let scene = lua_manager.get_scene_by_id(player.current_scene).unwrap();
let block = scene.get_block_by_pos(&player.pos);
match block {
Ok(block) =>
if player.current_block != block.block_id {
println!("Player {:?} moved to the block {:?}", player.player_id, block.block_id);
player.current_block = block.block_id;
},
Err(_) => {
// TODO?
player.current_block = 0;
},
};
player.position_changed();
},
Err(_) => panic!("Failed to grab player data!"),
};
}
});
}
fn process_combat_invocations(&self, user_id: u32, metadata: &proto::PacketHead, notify: &proto::CombatInvocationsNotify) { fn process_combat_invocations(&self, user_id: u32, metadata: &proto::PacketHead, notify: &proto::CombatInvocationsNotify) {
for invoke in notify.invoke_list.iter() { for invoke in notify.invoke_list.iter() {
self.handle_invoke(user_id, metadata, invoke); self.handle_invoke(user_id, metadata, invoke);
@ -236,33 +96,7 @@ impl EntitySubsystem {
return; return;
}; };
match self.players.lock() self.entity_manager.player_moved(user_id, pos);
{
Ok(mut players) => match players.entry(user_id) {
Occupied(mut player) => {
player.into_mut().pos = pos;
},
Vacant(entry) => {
// TODO: must panic!() here!
let player = Player {
player_id: user_id,
pos: pos,
current_block: 0,
current_scene: 3,
entities: HashMap::new(),
lua_manager: self.lua_manager.clone(),
json_manager: self.json_manager.clone(),
db_manager: self.db_manager.clone(),
packets_to_send_tx: self.packets_to_send_tx.clone(),
};
entry.insert(player);
},
},
Err(_) => panic!("Failed to grab player data!"),
};
self.players_moved.send(user_id).unwrap();
} }
} }

View File

@ -1,5 +1,3 @@
mod entity_subsystem; mod entity_subsystem;
mod entities;
pub use self::entity_subsystem::EntitySubsystem; pub use self::entity_subsystem::EntitySubsystem;
pub use self::entities::{Entity, EntityTrait};

View File

@ -3,9 +3,11 @@ mod shop;
mod scene; mod scene;
mod pause; mod pause;
mod social; mod social;
mod teleport;
pub use npc::NpcSubsystem; pub use npc::NpcSubsystem;
pub use shop::ShopSubsystem; pub use shop::ShopSubsystem;
pub use scene::SceneSubsystem; pub use scene::SceneSubsystem;
pub use pause::PauseSubsystem; pub use pause::PauseSubsystem;
pub use social::SocialSubsystem; pub use social::SocialSubsystem;
pub use teleport::TeleportSubsystem;

View File

@ -0,0 +1,78 @@
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::entitymanager::EntityManager;
use crate::luamanager::Vector;
use crate::utils::{IdManager, TimeManager};
#[packet_processor(
SceneTransToPointReq,
)]
pub struct TeleportSubsystem {
packets_to_send_tx: Sender<IpcMessage>,
jm: Arc<JsonManager>,
em: Arc<EntityManager>,
db: Arc<DatabaseManager>
}
impl TeleportSubsystem {
pub fn new(jm: Arc<JsonManager>, db: Arc<DatabaseManager>, em: Arc<EntityManager>, packets_to_send_tx: Sender<IpcMessage>) -> Self {
let mut nt = Self {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
jm: jm,
em: em,
db: db,
};
nt.register();
return nt;
}
fn process_scene_trans_to_point(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::SceneTransToPointReq, rsp: &mut proto::SceneTransToPointRsp) {
let s_id = req.scene_id;
let p_id = req.point_id;
rsp.scene_id = s_id;
rsp.point_id = p_id;
let pos = match self.jm.teleport_points.get(&s_id) {
None => None,
Some(scene) => match scene.get(&p_id) {
None => None,
Some(point) => Some(point.position.clone()),
},
};
let pos = match pos {
Some(pos) => Vector {x: pos.x, y: pos.y, z: pos.z},
None => {
println!("Warning: unknown TP point {}-{}, moving player to origin!", s_id, p_id);
Vector {x: 0.0, y: 500.0, z: 0.0}
}
};
// TODO: scene_token can probably be random?
let scene_info = match self.db.get_player_scene_info(user_id) {
Some(scene_info) => scene_info,
None => panic!("Scene info for user {} not found!", user_id),
};
self.em.player_teleported(user_id, pos, s_id, scene_info.scene_token, &proto::EnterType::EnterGoto);
}
}