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
|
// 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,
|
||||||
|
@ -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,
|
||||||
|
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::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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
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 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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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> {
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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};
|
|
@ -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;
|
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