mirror of
https://github.com/RustySamovar/RustySamovar.git
synced 2024-11-28 04:31:27 +00:00
Implemented teleportation (using old public data)
This commit is contained in:
parent
e4ef8a3c36
commit
e3241e5749
@ -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,
|
||||
|
@ -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,
|
||||
|
277
src/entitymanager/entity_manager.rs
Normal file
277
src/entitymanager/entity_manager.rs
Normal 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
5
src/entitymanager/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod entity_manager;
|
||||
mod entities;
|
||||
|
||||
pub use self::entity_manager::EntityManager;
|
||||
pub use self::entities::{Entity, EntityTrait};
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
22
src/jsonmanager/teleport_point.rs
Normal file
22
src/jsonmanager/teleport_point.rs
Normal 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,
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
mod entity_subsystem;
|
||||
mod entities;
|
||||
|
||||
pub use self::entity_subsystem::EntitySubsystem;
|
||||
pub use self::entities::{Entity, EntityTrait};
|
@ -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 teleport::TeleportSubsystem;
|
78
src/subsystems/misc/teleport.rs
Normal file
78
src/subsystems/misc/teleport.rs
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user