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
use std::collections::HashMap;
@ -98,25 +99,27 @@ trait Insertable<A, E>: ActiveModelTrait<Entity = E>
E::Model: IntoActiveModel<A>,
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;
E::insert_many(vec![self]).exec(db).wait()?;
let column = match E::Column::from_str("guid") {
Ok(column) => column,
Err(_) => panic!("GUID column not found!"),
};
let guid = self.get(column).unwrap();
E::insert(self).exec(db).wait()?;
let item = E::find().filter(
Condition::all()
.add(column.eq(guid))
.add(column.eq(guid.clone()))
).one(db).wait()?;
match item {
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,
{}
/*
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
*/
@ -649,6 +686,20 @@ impl DatabaseManager {
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>> {
/*let t1 = TeamInfo {
uid: uid.clone(),
@ -759,7 +810,7 @@ impl DatabaseManager {
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 {
uid: ActiveValue::Set(uid),
@ -767,7 +818,7 @@ impl DatabaseManager {
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 affixes: Vec<_> = self.jm.weapons[&item_id].skill_affix.iter()
@ -800,7 +851,7 @@ impl DatabaseManager {
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()
.map(|s| super::reliquary_prop::ActiveModel {
@ -854,7 +905,7 @@ impl DatabaseManager {
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) {
// Material
@ -865,7 +916,7 @@ impl DatabaseManager {
// 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 {
count: mt_info.count,
@ -880,7 +931,7 @@ impl DatabaseManager {
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 {
count: fr_info.count,

View File

@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "scene_info")]
pub struct Model {
#[sea_orm(primary_key)]
#[sea_orm(primary_key, autoincrement = false)]
pub uid: u32,
pub scene_id: 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::shop_goods::ShopGoods;
use crate::jsonmanager::shop_rotate::ShopRotate;
use crate::jsonmanager::teleport_point::TeleportPoint;
use crate::jsonmanager::weapon::Weapon;
use super::avatar_skill_depot::AvatarSkillDepot;
@ -54,6 +55,8 @@ pub struct JsonManager {
pub reliquary_affixes: HashMap<u32, Vec<ReliquaryAffix>>,
pub materials: HashMap<u32, Material>,
pub teleport_points: HashMap<u32, HashMap<u32, TeleportPoint>>,
}
impl std::fmt::Debug for JsonManager { // TODO: fucking hack!
@ -66,23 +69,25 @@ impl JsonManager {
pub fn new(directory: &str) -> JsonManager {
let reader = JsonReader::new(directory);
let asd: Vec<AvatarSkillDepot> = reader.read_json_list("AvatarSkillDepot");
let mc: Vec<EntityCurve> = reader.read_json_list("MonsterCurve");
let monsters: Vec<Monster> = reader.read_json_list("Monster");
let world_levels: Vec<WorldLevel> = reader.read_json_list("WorldLevel");
let gadget_props: Vec<GadgetProp> = reader.read_json_list("GadgetProp");
let gc: Vec<EntityCurve> = reader.read_json_list("GadgetCurve");
let gathers: Vec<Gather> = reader.read_json_list("Gather");
let shop_goods: Vec<ShopGoods> = reader.read_json_list("ShopGoods");
let shop_rotate: Vec<ShopRotate> = reader.read_json_list("ShopRotate");
let weapons: Vec<Weapon> = reader.read_json_list("Weapon");
let asd: Vec<AvatarSkillDepot> = reader.read_json_list_game("AvatarSkillDepot");
let mc: Vec<EntityCurve> = reader.read_json_list_game("MonsterCurve");
let monsters: Vec<Monster> = reader.read_json_list_game("Monster");
let world_levels: Vec<WorldLevel> = reader.read_json_list_game("WorldLevel");
let gadget_props: Vec<GadgetProp> = reader.read_json_list_game("GadgetProp");
let gc: Vec<EntityCurve> = reader.read_json_list_game("GadgetCurve");
let gathers: Vec<Gather> = reader.read_json_list_game("Gather");
let shop_goods: Vec<ShopGoods> = reader.read_json_list_game("ShopGoods");
let shop_rotate: Vec<ShopRotate> = reader.read_json_list_game("ShopRotate");
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_affixes : Vec<ReliquaryAffix> = reader.read_json_list("ReliquaryAffix");
let reliquary_main_prop_depot : Vec<ReliquaryMainProp> = reader.read_json_list_game("ReliquaryMainProp");
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 {
reader: reader,
@ -106,6 +111,10 @@ impl JsonManager {
.collect(), // TODO: we're grouping by depot_id!
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
{
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_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));
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 reliquary;
mod material;
mod teleport_point;
pub use entity_curve::{CurveInfo,EntityCurve};
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 crate::utils::IdManager;
use crate::subsystems::entity_subsystem::{Entity, EntityTrait};
use crate::entitymanager::{Entity, EntityTrait};
use lua_serde::from_file;

View File

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

View File

@ -12,8 +12,9 @@ use crate::JsonManager;
use crate::LuaManager;
use crate::server::LoginManager;
use std::sync::Arc;
use crate::entitymanager::EntityManager;
use crate::subsystems::{InventorySubsystem, NpcSubsystem, ShopSubsystem};
use crate::subsystems::misc::{PauseSubsystem, SceneSubsystem, SocialSubsystem};
use crate::subsystems::misc::{PauseSubsystem, SceneSubsystem, SocialSubsystem, TeleportSubsystem};
pub struct GameServer {
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 {
let jm = Arc::new(JsonManager::new("./data/json"));
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 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 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 ss = ShopSubsystem::new(jm.clone(), db.clone(), inv.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 ts = TeleportSubsystem::new(jm.clone(), db.clone(), em.clone(), packets_to_send_tx.clone());
let gs = GameServer {
packets_to_process_rx: packets_to_process_rx,
@ -48,7 +51,7 @@ impl GameServer {
login_manager: lm,
database_manager: db.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;

View File

@ -9,28 +9,31 @@ use packet_processor_macro::*;
#[macro_use]
use packet_processor::*;
use crate::DatabaseManager;
use crate::{DatabaseManager, luamanager};
use crate::JsonManager;
use crate::utils::{AvatarBuilder, IdManager, Remapper};
use crate::utils::TimeManager;
use crate::dbmanager::database_manager::AvatarInfo as DbAvatarInfo;
use crate::entitymanager::EntityManager;
#[packet_processor(PlayerLoginReq)]
pub struct LoginManager {
packets_to_send_tx: mpsc::Sender<IpcMessage>,
db: Arc<DatabaseManager>,
jm: Arc<JsonManager>,
em: Arc<EntityManager>,
}
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 {
packet_callbacks: HashMap::new(),
packets_to_send_tx: packets_to_send_tx,
db: db.clone(),
jm: jm.clone(),
db: db,
jm: jm,
em: em,
};
lm.register();
@ -112,16 +115,9 @@ impl LoginManager {
owned_flycloak_list: vec![140001], // TODO!
});
build_and_send! (self, user_id, metadata, PlayerEnterSceneNotify {
scene_id: scene_info.scene_id,
r#type: proto::EnterType::EnterSelf as i32,
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,
});
let pos = luamanager::Vector {x: scene_info.pos_x, y: scene_info.pos_y, z: scene_info.pos_z};
self.em.player_teleported(user_id, pos, scene_info.scene_id, scene_info.scene_token, &proto::EnterType::EnterSelf);
}
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 serde_json::de::Read;
use crate::{DatabaseManager, JsonManager, LuaManager};
use crate::entitymanager::EntityManager;
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; // 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(
CombatInvocationsNotify,
)]
pub struct EntitySubsystem {
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>,
entity_manager: Arc<EntityManager>,
}
impl EntitySubsystem {
pub fn new(lua_manager: Arc<LuaManager>, json_manager: Arc<JsonManager>, db_manager: Arc<DatabaseManager>, packets_to_send_tx: Sender<IpcMessage>) -> EntitySubsystem {
let (tx, rx): (Sender<u32>, Receiver<u32>) = mpsc::channel();
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 mut es = EntitySubsystem {
packets_to_send_tx: packets_to_send_tx,
packet_callbacks: HashMap::new(),
players_moved: tx,
players: Arc::new(Mutex::new(HashMap::new())),
lua_manager: lua_manager,
json_manager: json_manager,
db_manager: db_manager,
entity_manager: entity_manager,
};
es.register();
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!"),
};
}
});
}
fn process_combat_invocations(&self, user_id: u32, metadata: &proto::PacketHead, notify: &proto::CombatInvocationsNotify) {
for invoke in notify.invoke_list.iter() {
self.handle_invoke(user_id, metadata, invoke);
@ -236,33 +96,7 @@ impl EntitySubsystem {
return;
};
match self.players.lock()
{
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();
self.entity_manager.player_moved(user_id, pos);
}
}

View File

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

View File

@ -3,9 +3,11 @@ mod shop;
mod scene;
mod pause;
mod social;
mod teleport;
pub use npc::NpcSubsystem;
pub use shop::ShopSubsystem;
pub use scene::SceneSubsystem;
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);
}
}