mirror of
https://github.com/RustySamovar/RustySamovar.git
synced 2024-11-21 18:38:18 +00:00
Implement almost proper monster attribute scaling
This commit is contained in:
parent
3053cb987b
commit
616035373d
@ -1,6 +1,8 @@
|
||||
// Database Manager
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::collection;
|
||||
|
||||
use sea_orm::{entity::*, error::*, query::*, DbConn, FromQueryResult, Database};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use crate::JsonManager;
|
||||
@ -59,19 +61,6 @@ use super::reliquary_prop::Entity as ReliquaryPropEntity;
|
||||
pub use super::furniture_info::Model as FurnitureInfo;
|
||||
use super::furniture_info::Entity as FurnitureInfoEntity;
|
||||
|
||||
macro_rules! collection {
|
||||
// map-like
|
||||
($($k:expr => $v:expr),* $(,)?) => {{
|
||||
use std::iter::{Iterator, IntoIterator};
|
||||
Iterator::collect(IntoIterator::into_iter([$(($k, $v),)*]))
|
||||
}};
|
||||
// set-like
|
||||
($($v:expr),* $(,)?) => {{
|
||||
use std::iter::{Iterator, IntoIterator};
|
||||
Iterator::collect(IntoIterator::into_iter([$($v,)*]))
|
||||
}};
|
||||
}
|
||||
|
||||
trait Block {
|
||||
fn wait(self) -> <Self as futures::Future>::Output
|
||||
where Self: Sized, Self: futures::Future
|
||||
@ -84,6 +73,7 @@ impl<F,T> Block for F
|
||||
where F: futures::Future<Output = T>
|
||||
{}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DatabaseManager {
|
||||
db: DbConn,
|
||||
}
|
||||
@ -146,6 +136,17 @@ impl DatabaseManager {
|
||||
|
||||
return Some(props);
|
||||
}
|
||||
|
||||
pub fn get_player_prop(&self, uid: u32, prop_id: u32) -> Option<i64> {
|
||||
match PlayerPropEntity::find().filter(
|
||||
Condition::all()
|
||||
.add(super::player_prop::Column::Uid.eq(uid))
|
||||
.add(super::player_prop::Column::PropId.eq(prop_id))
|
||||
).one(&self.db).wait() {
|
||||
Ok(prop) => Some(prop?.prop_value), // Returns None if prop is none
|
||||
Err(_) => panic!("DB ERROR!"),
|
||||
}
|
||||
}
|
||||
/*
|
||||
pub fn _get_avatar_props(&self, guid: u64) -> Option<HashMap<u32, i64>> {
|
||||
let map = collection! {
|
||||
|
16
src/jsonmanager/entity_curve.rs
Normal file
16
src/jsonmanager/entity_curve.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct CurveInfo {
|
||||
pub r#type: proto::GrowCurveType,
|
||||
pub arith: proto::ArithType,
|
||||
pub value: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct EntityCurve {
|
||||
pub level: u32,
|
||||
pub curve_infos: Vec<CurveInfo>
|
||||
}
|
15
src/jsonmanager/gadget_prop.rs
Normal file
15
src/jsonmanager/gadget_prop.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct GadgetProp {
|
||||
pub id: u32,
|
||||
pub hp: f32,
|
||||
pub hp_curve: proto::GrowCurveType,
|
||||
#[serde(default)]
|
||||
pub attack: f32,
|
||||
pub attack_curve: proto::GrowCurveType,
|
||||
#[serde(default)]
|
||||
pub defense: f32,
|
||||
pub defense_curve: proto::GrowCurveType,
|
||||
}
|
26
src/jsonmanager/gather.rs
Normal file
26
src/jsonmanager/gather.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct BlockLimit {
|
||||
pub block_id: u32,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct Gather {
|
||||
pub id: u32,
|
||||
pub area_id: Option<u32>,
|
||||
pub point_type: u32, // TODO: probs an enum?
|
||||
pub gadget_id: u32,
|
||||
pub item_id: u32,
|
||||
pub extra_item_id_vec: Vec<u32>,
|
||||
pub cd: u32,
|
||||
pub priority: u32,
|
||||
pub refresh_id: Option<u32>,
|
||||
pub block_limits: Vec<BlockLimit>,
|
||||
#[serde(default)]
|
||||
pub init_disable_interact: bool,
|
||||
pub save_type: Option<String>, // TODO: this is an enum!
|
||||
}
|
@ -4,8 +4,13 @@ use std::collections::HashMap;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
use crate::jsonmanager::gather::Gather;
|
||||
|
||||
use super::avatar_skill_depot::AvatarSkillDepot;
|
||||
use super::entity_curve::EntityCurve;
|
||||
use super::monster::Monster;
|
||||
use super::world_level::WorldLevel;
|
||||
use super::gadget_prop::GadgetProp;
|
||||
|
||||
struct JsonReader {
|
||||
base_path: String,
|
||||
@ -14,6 +19,18 @@ struct JsonReader {
|
||||
pub struct JsonManager {
|
||||
reader: JsonReader,
|
||||
pub avatar_skill_depot: HashMap<u32,AvatarSkillDepot>,
|
||||
pub monster_curves: HashMap<u32,EntityCurve>,
|
||||
pub monsters: HashMap<u32, Monster>,
|
||||
pub world_levels: HashMap<u32, WorldLevel>,
|
||||
pub gadget_props: HashMap<u32, GadgetProp>,
|
||||
pub gadget_curves: HashMap<u32,EntityCurve>,
|
||||
pub gathers: HashMap<u32, Gather>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for JsonManager { // TODO: fucking hack!
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "JsonManager is not debuggable!")
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonManager {
|
||||
@ -21,10 +38,22 @@ impl 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");
|
||||
|
||||
return JsonManager {
|
||||
reader: reader,
|
||||
avatar_skill_depot: asd.into_iter().map(|a| (a.id, a)).collect(),
|
||||
monster_curves: mc.into_iter().map(|m| (m.level, m)).collect(),
|
||||
monsters: monsters.into_iter().map(|m| (m.id, m)).collect(),
|
||||
world_levels: world_levels.into_iter().map(|wl| (wl.level, wl)).collect(),
|
||||
gadget_props: gadget_props.into_iter().map(|gp| (gp.id, gp)).collect(),
|
||||
gadget_curves: gc.into_iter().map(|g| (g.level, g)).collect(),
|
||||
gathers: gathers.into_iter().map(|g| (g.gadget_id, g)).collect(), // TODO: we index it by gadget_id and not by it's id!
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -43,7 +72,7 @@ impl JsonReader {
|
||||
|
||||
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("Error while reading json");
|
||||
let data: Vec<T> = serde_json::from_str(&json_file_str).expect(&format!("Error while reading json {}", name));
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -3,3 +3,10 @@ mod json_manager;
|
||||
pub use self::json_manager::JsonManager;
|
||||
|
||||
mod avatar_skill_depot;
|
||||
mod entity_curve;
|
||||
mod monster;
|
||||
mod world_level;
|
||||
mod gadget_prop;
|
||||
mod gather;
|
||||
|
||||
pub use entity_curve::{CurveInfo,EntityCurve};
|
92
src/jsonmanager/monster.rs
Normal file
92
src/jsonmanager/monster.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
// TODO: those two structs have fields that are usually missing all together, so it makes sense to omit
|
||||
// an entire record from the list in the generator.
|
||||
// For the sake of being compatible with Dimbreath's data I've chosen this way for now - wrapping real data with Option<>
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct HpDrop {
|
||||
pub drop_id: u32,
|
||||
pub hp_percent: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct HpDropWrap {
|
||||
#[serde(flatten)]
|
||||
pub data: Option<HpDrop>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct PropGrowCurve {
|
||||
#[serde(default = "PropGrowCurve::default_type")]
|
||||
pub r#type: proto::FightPropType,
|
||||
#[serde(default = "PropGrowCurve::default_curve")]
|
||||
pub grow_curve: proto::GrowCurveType,
|
||||
}
|
||||
// TODO: fucking hack!
|
||||
impl PropGrowCurve {
|
||||
fn default_type() -> proto::FightPropType { proto::FightPropType::FightPropNone }
|
||||
fn default_curve() -> proto::GrowCurveType { proto::GrowCurveType::GrowCurveNone }
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct PropGrowCurveWrap {
|
||||
#[serde(flatten)]
|
||||
pub data: Option<PropGrowCurve>,
|
||||
}*/
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct Monster {
|
||||
pub id: u32,
|
||||
#[serde(rename = "CampID")]
|
||||
pub camp_id: u32,
|
||||
|
||||
pub monster_name: String,
|
||||
pub r#type: String, // TODO: this is an enum!
|
||||
pub server_script: String,
|
||||
pub affix: Vec<u32>,
|
||||
pub ai: String,
|
||||
#[serde(default)]
|
||||
pub is_ai_hash_check: bool,
|
||||
pub equips: Vec<u32>,
|
||||
pub hp_drops: Vec<HpDropWrap>,
|
||||
pub kill_drop_id: Option<u32>,
|
||||
pub exclude_weathers: String,
|
||||
|
||||
#[serde(rename = "FeatureTagGroupID")]
|
||||
pub feature_tag_group_id: u32,
|
||||
#[serde(rename = "MpPropID")]
|
||||
pub mp_prop_id: u32,
|
||||
|
||||
pub hp_base: f32,
|
||||
#[serde(default)] // Missing for Slimes that attack during the tutorial fight
|
||||
pub attack_base: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub defense_base: f32,
|
||||
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub fire_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub grass_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub water_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub elec_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub wind_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub ice_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub rock_sub_hurt: f32,
|
||||
#[serde(default)] // Missing for Dvalin in the aerial fight
|
||||
pub physical_sub_hurt: f32,
|
||||
|
||||
//pub prop_grow_curves: Vec<PropGrowCurveWrap>,
|
||||
pub prop_grow_curves: Vec<PropGrowCurve>,
|
||||
}
|
8
src/jsonmanager/world_level.rs
Normal file
8
src/jsonmanager/world_level.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all="PascalCase")]
|
||||
pub struct WorldLevel {
|
||||
pub level: u32,
|
||||
pub monster_level: u32,
|
||||
}
|
@ -2,11 +2,10 @@ use std::collections::HashMap;
|
||||
use std::result::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use lua_serde::from_file;
|
||||
|
||||
#[macro_use]
|
||||
use packet_processor::*;
|
||||
use crate::utils::IdManager;
|
||||
use crate::subsystems::entity_subsystem::{Entity, EntityTrait};
|
||||
|
||||
use lua_serde::from_file;
|
||||
|
||||
use super::scene_config;
|
||||
|
||||
@ -43,22 +42,6 @@ pub struct InternalGroupData {
|
||||
// No extra data here
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub enum EntityType {
|
||||
Monster(Monster),
|
||||
Npc(Npc),
|
||||
Gadget(Gadget),
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Entity {
|
||||
pub entity_id: u32,
|
||||
pub group_id: u32,
|
||||
pub block_id: u32,
|
||||
pub entity: EntityType,
|
||||
}
|
||||
|
||||
/// Implementation of utility functions
|
||||
impl InternalSceneData {
|
||||
pub fn get_block_by_pos(&self, pos: &Vector) -> Result<&InternalBlockData, String> {
|
||||
@ -80,89 +63,6 @@ impl InternalSceneData {
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
pub fn pos(&self) -> Vector {
|
||||
match &self.entity {
|
||||
EntityType::Monster(m) => m.pos.clone(),
|
||||
EntityType::Npc(n) => n.pos.clone(),
|
||||
EntityType::Gadget(g) => g.pos.clone(),
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rot(&self) -> Vector {
|
||||
match &self.entity {
|
||||
EntityType::Monster(m) => m.rot.clone(),
|
||||
EntityType::Npc(n) => n.rot.clone(),
|
||||
EntityType::Gadget(g) => g.rot.clone(),
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn speed(&self) -> Vector {
|
||||
// TODO!
|
||||
Vector { x: 0.0, y: 0.0, z: 0.0 }
|
||||
}
|
||||
|
||||
pub fn etype(&self) -> i32 {
|
||||
(match &self.entity {
|
||||
EntityType::Monster(_) => proto::ProtEntityType::ProtEntityMonster,
|
||||
EntityType::Npc(n) => proto::ProtEntityType::ProtEntityNpc,
|
||||
EntityType::Gadget(g) => proto::ProtEntityType::ProtEntityGadget,
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
}) as i32
|
||||
}
|
||||
|
||||
pub fn convert(&self) -> proto::SceneEntityInfo {
|
||||
let mut sei = build!(SceneEntityInfo {
|
||||
entity_id: self.entity_id,
|
||||
entity_type: self.etype(),
|
||||
motion_info: Some(build!(MotionInfo {
|
||||
pos: Some((&self.pos()).into()),
|
||||
rot: Some((&self.rot()).into()),
|
||||
speed: Some((&self.speed()).into()),
|
||||
})),
|
||||
animator_para_list: vec![],
|
||||
entity_client_data: Some(build!(EntityClientData {})),
|
||||
entity_authority_info: Some(build!(EntityAuthorityInfo {
|
||||
renderer_changed_info: Some(build!(EntityRendererChangedInfo{})),
|
||||
ai_info: Some(build!(SceneEntityAiInfo {
|
||||
is_ai_open: true, // TODO!
|
||||
born_pos: Some((&self.pos()).into()),
|
||||
})),
|
||||
born_pos: Some((&self.pos()).into()),
|
||||
})),
|
||||
});
|
||||
|
||||
sei.entity = Some(match &self.entity {
|
||||
EntityType::Monster(m) => proto::scene_entity_info::Entity::Monster(build!(SceneMonsterInfo {
|
||||
monster_id: m.monster_id,
|
||||
group_id: self.group_id,
|
||||
config_id: m.config_id,
|
||||
authority_peer_id: 1, // TODO: hardcoded value!
|
||||
born_type: proto::MonsterBornType::MonsterBornDefault as i32, // TODO: hardcoded value!
|
||||
block_id: self.block_id,
|
||||
// TODO: level scaling, weapons!
|
||||
})),
|
||||
EntityType::Npc(n) => proto::scene_entity_info::Entity::Npc(build!(SceneNpcInfo {
|
||||
npc_id: n.npc_id,
|
||||
block_id: self.block_id,
|
||||
})),
|
||||
EntityType::Gadget(g) => proto::scene_entity_info::Entity::Gadget(build!(SceneGadgetInfo {
|
||||
gadget_id: g.gadget_id,
|
||||
group_id: self.group_id,
|
||||
config_id: g.config_id,
|
||||
authority_peer_id: 1, // TODO: hardcoded value!
|
||||
is_enable_interact: true,
|
||||
// TODO: collectibles!
|
||||
})),
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
});
|
||||
|
||||
sei
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LuaManager {
|
||||
scenes_data: HashMap<u32,InternalSceneData>,
|
||||
@ -254,7 +154,8 @@ impl LuaManager {
|
||||
entity_id: entity_id,
|
||||
group_id: *group_id,
|
||||
block_id: block_id,
|
||||
entity: EntityType::Npc(npc.clone()), // TODO: very fucking inefficient!
|
||||
health: 0,
|
||||
entity: Arc::new(npc.clone()), // TODO: very fucking inefficient!
|
||||
}));
|
||||
}
|
||||
|
||||
@ -266,7 +167,8 @@ impl LuaManager {
|
||||
entity_id: entity_id,
|
||||
group_id: *group_id,
|
||||
block_id: block_id,
|
||||
entity: EntityType::Monster(monster.clone()), // TODO: very fucking inefficient!
|
||||
health: 0,
|
||||
entity: Arc::new(monster.clone()), // TODO: very fucking inefficient!
|
||||
}));
|
||||
}
|
||||
|
||||
@ -278,7 +180,8 @@ impl LuaManager {
|
||||
entity_id: entity_id,
|
||||
group_id: *group_id,
|
||||
block_id: block_id,
|
||||
entity: EntityType::Gadget(gadget.clone()), // TODO: very fucking inefficient!
|
||||
health: 0,
|
||||
entity: Arc::new(gadget.clone()), // TODO: very fucking inefficient!
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,4 @@ mod lua_manager;
|
||||
mod scene_config;
|
||||
|
||||
pub use self::lua_manager::LuaManager;
|
||||
pub use self::scene_config::Vector;
|
||||
pub use self::lua_manager::Entity;
|
||||
pub use self::scene_config::{Vector, Monster, Gadget, Npc};
|
@ -29,7 +29,7 @@ impl GameServer {
|
||||
let jm = Arc::new(JsonManager::new("./data/json"));
|
||||
let lm = LoginManager::new(db.clone(), jm.clone(), packets_to_send_tx.clone());
|
||||
let lum = Arc::new(LuaManager::new("./data/lua"));
|
||||
let em = EntitySubsystem::new(lum.clone(), packets_to_send_tx.clone());
|
||||
let em = EntitySubsystem::new(lum.clone(), jm.clone(), db.clone(), packets_to_send_tx.clone());
|
||||
|
||||
let gs = GameServer {
|
||||
packets_to_process_rx: packets_to_process_rx,
|
||||
|
400
src/subsystems/entity_subsystem/entities.rs
Normal file
400
src/subsystems/entity_subsystem/entities.rs
Normal file
@ -0,0 +1,400 @@
|
||||
use actix_web::web::Json;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rand::{self, Rng};
|
||||
|
||||
#[macro_use]
|
||||
use packet_processor::*;
|
||||
use crate::{DatabaseManager, JsonManager};
|
||||
use crate::jsonmanager::{CurveInfo, EntityCurve};
|
||||
|
||||
use crate::collection;
|
||||
|
||||
use crate::luamanager::{Monster, Npc, Gadget, Vector};
|
||||
use crate::utils::Remapper;
|
||||
|
||||
pub trait EntityTrait {
|
||||
fn id(&self) -> String;
|
||||
fn pos(&self) -> Vector;
|
||||
fn rot(&self) -> Vector;
|
||||
fn speed(&self) -> Vector;
|
||||
fn etype(&self) -> proto::ProtEntityType;
|
||||
fn info(&self, block_id: u32, group_id: u32, jm: &Arc<JsonManager>) -> proto::scene_entity_info::Entity;
|
||||
fn props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<u32, i64>;
|
||||
fn fight_props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<proto::FightPropType, f32>;
|
||||
fn get_scaled_level(&self, world_level: u32, jm: &Arc<JsonManager>) -> u32;
|
||||
|
||||
fn curve_info_for_level<'a>(&self, list: &'a HashMap<u32, EntityCurve>, level: u32) -> HashMap<u32, &'a CurveInfo> {
|
||||
list[&level].curve_infos.iter()
|
||||
.map(|c| (c.r#type.clone() as u32, c))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_scaled_props(&self, world_level: u32, jm: &Arc<JsonManager>, list: &HashMap<u32, EntityCurve>,
|
||||
scaling_helper: &HashMap<proto::FightPropType, (proto::FightPropType, f32)>,
|
||||
grow_curves: &HashMap<proto::FightPropType, proto::GrowCurveType>) -> HashMap<proto::FightPropType,f32> {
|
||||
let level = self.get_scaled_level(world_level, jm);
|
||||
|
||||
let curve_info = EntityTrait::curve_info_for_level(self, list, level);
|
||||
|
||||
let mut props = HashMap::new();
|
||||
|
||||
for (k, v) in scaling_helper.iter() {
|
||||
let gct = match grow_curves.get(&v.0) {
|
||||
Some(gct) => gct.clone() as u32,
|
||||
None => {
|
||||
println!("No curve {:?} for entity {}!", v.0, self.id());
|
||||
continue;
|
||||
},
|
||||
};
|
||||
|
||||
let curve = match curve_info.get(&gct) {
|
||||
Some(curve) => curve,
|
||||
None => panic!("Unknown curve {:?} for level {}", gct, level),
|
||||
};
|
||||
|
||||
let scaled_value = match curve.arith {
|
||||
proto::ArithType::ArithMulti => {
|
||||
curve.value.unwrap() * v.1
|
||||
},
|
||||
proto::ArithType::ArithAdd => {
|
||||
println!("Don't know how to use ArithAdd!");
|
||||
v.1
|
||||
}
|
||||
_ => {
|
||||
panic!("Unknown arith type {:?} for curve {:?} (level {})", curve.arith, curve.r#type.clone() as u32, level);
|
||||
}
|
||||
};
|
||||
|
||||
props.insert(*k, scaled_value);
|
||||
props.insert(v.0, scaled_value);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for EntityTrait+Sync+Send { // TODO: fucking hack!
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{{ \npos: {:?},\n rot: {:?},\n speed: {:?}, \netype: {:?},\n}}",
|
||||
self.pos(), self.rot(), self.speed(), self.etype()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Entity {
|
||||
pub entity_id: u32,
|
||||
pub group_id: u32,
|
||||
pub block_id: u32,
|
||||
pub health: u32,
|
||||
pub entity: Arc<EntityTrait + Sync + Send>,
|
||||
}
|
||||
|
||||
impl EntityTrait for Monster {
|
||||
fn id(&self) -> String {
|
||||
format!("Monster {}", self.monster_id)
|
||||
}
|
||||
fn pos(&self) -> Vector {
|
||||
self.pos.clone()
|
||||
}
|
||||
fn rot(&self) -> Vector {
|
||||
self.rot.clone()
|
||||
}
|
||||
fn speed(&self) -> Vector { // TODO!
|
||||
Vector {x:0.0, y:0.0, z:0.0}
|
||||
}
|
||||
fn etype(&self) -> proto::ProtEntityType {
|
||||
proto::ProtEntityType::ProtEntityMonster
|
||||
}
|
||||
fn info(&self, block_id: u32, group_id: u32, jm: &Arc<JsonManager>) -> proto::scene_entity_info::Entity {
|
||||
let monster_info = &jm.monsters.get(&self.monster_id);
|
||||
|
||||
let affixes = match monster_info {
|
||||
Some(mi) => mi.affix.clone(),
|
||||
None => {
|
||||
println!("No monster info found for monster {}! No affix.", self.monster_id);
|
||||
vec![]
|
||||
},
|
||||
};
|
||||
|
||||
proto::scene_entity_info::Entity::Monster(build!(SceneMonsterInfo {
|
||||
monster_id: self.monster_id,
|
||||
group_id: group_id,
|
||||
config_id: self.config_id,
|
||||
authority_peer_id: 1, // TODO: hardcoded value!
|
||||
born_type: proto::MonsterBornType::MonsterBornDefault as i32, // TODO: hardcoded value!
|
||||
block_id: block_id,
|
||||
affix_list: affixes,
|
||||
// TODO: special_name!
|
||||
}))
|
||||
}
|
||||
fn props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<u32, i64> {
|
||||
let level = self.get_scaled_level(world_level, jm) as i64;
|
||||
|
||||
collection!{
|
||||
proto::PropType::PropLevel as u32 => level,
|
||||
}
|
||||
}
|
||||
fn fight_props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<proto::FightPropType,f32> {
|
||||
let mut props = HashMap::new();
|
||||
|
||||
let monster_info = &jm.monsters.get(&self.monster_id);
|
||||
|
||||
match monster_info {
|
||||
Some(mi) => {
|
||||
// Non-scaled props
|
||||
|
||||
let non_scaled_props: HashMap<proto::FightPropType,f32> = collection!{
|
||||
proto::FightPropType::FightPropPhysicalSubHurt => mi.physical_sub_hurt,
|
||||
proto::FightPropType::FightPropFireSubHurt => mi.fire_sub_hurt,
|
||||
proto::FightPropType::FightPropElecSubHurt => mi.elec_sub_hurt,
|
||||
proto::FightPropType::FightPropWaterSubHurt => mi.water_sub_hurt,
|
||||
proto::FightPropType::FightPropGrassSubHurt => mi.grass_sub_hurt,
|
||||
proto::FightPropType::FightPropWindSubHurt => mi.wind_sub_hurt,
|
||||
proto::FightPropType::FightPropRockSubHurt => mi.rock_sub_hurt,
|
||||
proto::FightPropType::FightPropIceSubHurt => mi.ice_sub_hurt,
|
||||
};
|
||||
|
||||
props.extend(non_scaled_props);
|
||||
|
||||
// Scaled props
|
||||
|
||||
// Transform monster's dict into usable format
|
||||
let grow_curves: HashMap<proto::FightPropType, proto::GrowCurveType> = mi.prop_grow_curves.iter()
|
||||
//.filter_map(|g| g.data.as_ref())
|
||||
.map(|g| (g.r#type, g.grow_curve.clone()))
|
||||
.collect();
|
||||
|
||||
let scaling_helper: HashMap<proto::FightPropType, (proto::FightPropType, f32)> = collection!{
|
||||
proto::FightPropType::FightPropCurAttack => (
|
||||
proto::FightPropType::FightPropBaseAttack,
|
||||
mi.attack_base,
|
||||
),
|
||||
proto::FightPropType::FightPropCurDefense => (
|
||||
proto::FightPropType::FightPropBaseDefense,
|
||||
mi.defense_base,
|
||||
),
|
||||
proto::FightPropType::FightPropMaxHp => (
|
||||
proto::FightPropType::FightPropBaseHp,
|
||||
mi.hp_base,
|
||||
),
|
||||
};
|
||||
|
||||
props.extend(
|
||||
self.get_scaled_props(world_level, jm, &jm.monster_curves, &scaling_helper, &grow_curves)
|
||||
);
|
||||
|
||||
// TODO: hack! Properly calculate HP!
|
||||
match props.get(&proto::FightPropType::FightPropMaxHp) {
|
||||
Some(value) => {
|
||||
props.insert(proto::FightPropType::FightPropCurHp, value * 0.7);
|
||||
},
|
||||
None => {
|
||||
println!("Monster {} has no HP!", self.monster_id);
|
||||
}
|
||||
}
|
||||
},
|
||||
None=> {
|
||||
println!("No monster info found for monster {}! No fight props.", self.monster_id);
|
||||
},
|
||||
};
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
fn get_scaled_level(&self, world_level: u32, jm: &Arc<JsonManager>) -> u32 {
|
||||
let base_level = jm.world_levels[&1].monster_level;
|
||||
|
||||
let max_level = jm.world_levels[&world_level].monster_level;
|
||||
|
||||
let level = max_level - base_level + self.level;
|
||||
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityTrait for Npc {
|
||||
fn id(&self) -> String {
|
||||
format!("Npc {}", self.npc_id)
|
||||
}
|
||||
fn pos(&self) -> Vector {
|
||||
self.pos.clone()
|
||||
}
|
||||
fn rot(&self) -> Vector {
|
||||
self.rot.clone()
|
||||
}
|
||||
fn speed(&self) -> Vector { // TODO!
|
||||
Vector {x:0.0, y:0.0, z:0.0}
|
||||
}
|
||||
fn etype(&self) -> proto::ProtEntityType {
|
||||
proto::ProtEntityType::ProtEntityNpc
|
||||
}
|
||||
fn info(&self, block_id: u32, group_id: u32, jm: &Arc<JsonManager>,) -> proto::scene_entity_info::Entity {
|
||||
proto::scene_entity_info::Entity::Npc(build!(SceneNpcInfo {
|
||||
npc_id: self.npc_id,
|
||||
block_id: block_id,
|
||||
}))
|
||||
}
|
||||
fn props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<u32, i64> {
|
||||
HashMap::new() // TODO
|
||||
}
|
||||
fn fight_props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<proto::FightPropType,f32> {
|
||||
HashMap::new() // TODO
|
||||
}
|
||||
fn get_scaled_level(&self, world_level: u32, jm: &Arc<JsonManager>) -> u32 {
|
||||
/*let base_level = jm.world_levels[&1].monster_level;
|
||||
|
||||
let max_level = jm.world_levels[&world_level].monster_level;
|
||||
|
||||
let level = max_level - base_level + self.level;
|
||||
|
||||
return level;*/
|
||||
return 1; // TODO!
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityTrait for Gadget {
|
||||
fn id(&self) -> String {
|
||||
format!("Gadget {}", self.gadget_id)
|
||||
}
|
||||
fn pos(&self) -> Vector {
|
||||
self.pos.clone()
|
||||
}
|
||||
fn rot(&self) -> Vector {
|
||||
self.rot.clone()
|
||||
}
|
||||
fn speed(&self) -> Vector { // TODO!
|
||||
Vector {x:0.0, y:0.0, z:0.0}
|
||||
}
|
||||
fn etype(&self) -> proto::ProtEntityType {
|
||||
proto::ProtEntityType::ProtEntityGadget
|
||||
}
|
||||
fn info(&self, block_id: u32, group_id: u32, jm: &Arc<JsonManager>,) -> proto::scene_entity_info::Entity {
|
||||
proto::scene_entity_info::Entity::Gadget(build!(SceneGadgetInfo {
|
||||
gadget_id: self.gadget_id,
|
||||
group_id: group_id,
|
||||
config_id: self.config_id,
|
||||
authority_peer_id: 1, // TODO: hardcoded value!
|
||||
is_enable_interact: true,
|
||||
content: self.get_content(jm),
|
||||
}))
|
||||
}
|
||||
fn props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<u32, i64> {
|
||||
HashMap::new() // TODO
|
||||
}
|
||||
fn fight_props(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> HashMap<proto::FightPropType,f32> {
|
||||
let mut props = HashMap::new();
|
||||
|
||||
let gadget_props = jm.gadget_props.get(&self.gadget_id);
|
||||
|
||||
match gadget_props {
|
||||
Some(gp) => {
|
||||
// Scaled props
|
||||
|
||||
// Transform monster's dict into usable format
|
||||
let grow_curves: HashMap<proto::FightPropType, proto::GrowCurveType> = collection!{
|
||||
proto::FightPropType::FightPropBaseHp => gp.hp_curve.clone(),
|
||||
proto::FightPropType::FightPropBaseAttack => gp.attack_curve.clone(),
|
||||
proto::FightPropType::FightPropBaseDefense => gp.defense_curve.clone(),
|
||||
};
|
||||
|
||||
let scaling_helper: HashMap<proto::FightPropType, (proto::FightPropType, f32)> = collection!{
|
||||
proto::FightPropType::FightPropCurAttack => (
|
||||
proto::FightPropType::FightPropBaseAttack,
|
||||
gp.attack,
|
||||
),
|
||||
proto::FightPropType::FightPropCurDefense => (
|
||||
proto::FightPropType::FightPropBaseDefense,
|
||||
gp.defense,
|
||||
),
|
||||
proto::FightPropType::FightPropMaxHp => (
|
||||
proto::FightPropType::FightPropBaseHp,
|
||||
gp.hp,
|
||||
),
|
||||
};
|
||||
|
||||
props.extend(
|
||||
self.get_scaled_props(world_level, jm, &jm.gadget_curves, &scaling_helper, &grow_curves)
|
||||
);
|
||||
|
||||
// TODO: hack! Properly calculate HP!
|
||||
match props.get(&proto::FightPropType::FightPropMaxHp) {
|
||||
Some(value) => {
|
||||
props.insert(proto::FightPropType::FightPropCurHp, value * 0.7);
|
||||
},
|
||||
None => {
|
||||
println!("Gadget {} has no HP!", self.gadget_id);
|
||||
}
|
||||
}
|
||||
},
|
||||
None=> {
|
||||
println!("No gadget info found for gadget {}! No fight props.", self.gadget_id);
|
||||
},
|
||||
};
|
||||
|
||||
return props;
|
||||
}
|
||||
fn get_scaled_level(&self, world_level: u32, jm: &Arc<JsonManager>) -> u32 {
|
||||
/*let base_level = jm.world_levels[&1].monster_level;
|
||||
|
||||
let max_level = jm.world_levels[&world_level].monster_level;
|
||||
|
||||
let level = max_level - base_level + self.level;
|
||||
|
||||
return level;*/
|
||||
return 1; // TODO!
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
pub fn pos(&self) -> Vector {
|
||||
self.entity.pos()
|
||||
}
|
||||
|
||||
pub fn convert(&self, world_level: u32, jm: &Arc<JsonManager>, db: &Arc<DatabaseManager>) -> proto::SceneEntityInfo {
|
||||
let mut sei = build!(SceneEntityInfo {
|
||||
entity_id: self.entity_id,
|
||||
entity_type: self.entity.etype() as i32,
|
||||
motion_info: Some(build!(MotionInfo {
|
||||
pos: Some((&self.entity.pos()).into()),
|
||||
rot: Some((&self.entity.rot()).into()),
|
||||
speed: Some((&self.entity.speed()).into()),
|
||||
})),
|
||||
prop_list: Remapper::remap2(&self.entity.props(world_level, jm, db)),
|
||||
fight_prop_list: Remapper::remap4(&self.entity.fight_props(world_level, jm, db)),
|
||||
animator_para_list: vec![],
|
||||
entity_client_data: Some(build!(EntityClientData {})),
|
||||
entity_authority_info: Some(build!(EntityAuthorityInfo {
|
||||
renderer_changed_info: Some(build!(EntityRendererChangedInfo{})),
|
||||
ai_info: Some(build!(SceneEntityAiInfo {
|
||||
is_ai_open: true, // TODO!
|
||||
born_pos: Some((&self.entity.pos()).into()),
|
||||
})),
|
||||
born_pos: Some((&self.entity.pos()).into()),
|
||||
})),
|
||||
});
|
||||
|
||||
sei.entity = Some(self.entity.info(self.block_id, self.group_id, &jm));
|
||||
|
||||
sei
|
||||
}
|
||||
}
|
||||
|
||||
impl Gadget {
|
||||
fn get_content(&self, jm: &Arc<JsonManager>) -> Option<proto::scene_gadget_info::Content> {
|
||||
match jm.gathers.get(&self.gadget_id) { // TODO: worktop and other options are missing!
|
||||
Some(gather) => {
|
||||
println!("GATHERABLE {} FOUND FOR GADGET {}!", gather.item_id, self.gadget_id);
|
||||
Some(proto::scene_gadget_info::Content::GatherGadget(build!(GatherGadgetInfo {
|
||||
item_id: gather.item_id,
|
||||
})))
|
||||
},
|
||||
None => {
|
||||
println!("NO CONTENT FOUND FOR GADGET {}!", self.gadget_id);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -14,11 +14,11 @@ use packet_processor_macro::*;
|
||||
#[macro_use]
|
||||
use packet_processor::*;
|
||||
use serde_json::de::Read;
|
||||
use crate::LuaManager;
|
||||
use crate::{DatabaseManager, JsonManager, LuaManager};
|
||||
use crate::utils::{IdManager, TimeManager};
|
||||
|
||||
use crate::luamanager::Vector;
|
||||
use crate::luamanager::Entity;
|
||||
use super::entities::Entity;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Player {
|
||||
@ -28,6 +28,8 @@ struct Player {
|
||||
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>,
|
||||
}
|
||||
|
||||
@ -102,9 +104,10 @@ impl Player {
|
||||
sent_ms: TimeManager::timestamp(),
|
||||
client_sequence_id: 0,
|
||||
});
|
||||
let world_level = self.db_manager.get_player_prop(self.player_id, proto::PropType::PropPlayerWorldLevel as u32).unwrap() as u32; // TODO: hardcoded value!
|
||||
|
||||
build_and_send!(self, player_id, metadata, SceneEntityAppearNotify {
|
||||
entity_list: spawn_list.iter().map(|e| e.convert()).collect(),
|
||||
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,
|
||||
});
|
||||
|
||||
@ -125,10 +128,12 @@ pub struct EntitySubsystem {
|
||||
players: Arc<Mutex<HashMap<u32, Player>>>,
|
||||
players_moved: Sender<u32>,
|
||||
lua_manager: Arc<LuaManager>,
|
||||
json_manager: Arc<JsonManager>,
|
||||
db_manager: Arc<DatabaseManager>,
|
||||
}
|
||||
|
||||
impl EntitySubsystem {
|
||||
pub fn new(lua_manager: Arc<LuaManager>, packets_to_send_tx: Sender<IpcMessage>) -> 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();
|
||||
|
||||
let mut es = EntitySubsystem {
|
||||
@ -137,6 +142,8 @@ impl EntitySubsystem {
|
||||
players_moved: tx,
|
||||
players: Arc::new(Mutex::new(HashMap::new())),
|
||||
lua_manager: lua_manager,
|
||||
json_manager: json_manager,
|
||||
db_manager: db_manager,
|
||||
};
|
||||
|
||||
es.register();
|
||||
@ -244,6 +251,8 @@ impl EntitySubsystem {
|
||||
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(),
|
||||
};
|
||||
|
5
src/subsystems/entity_subsystem/mod.rs
Normal file
5
src/subsystems/entity_subsystem/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod entity_subsystem;
|
||||
mod entities;
|
||||
|
||||
pub use self::entity_subsystem::EntitySubsystem;
|
||||
pub use self::entities::{Entity, EntityTrait};
|
@ -1,3 +1,3 @@
|
||||
mod entity_subsystem;
|
||||
pub mod entity_subsystem;
|
||||
|
||||
pub use self::entity_subsystem::EntitySubsystem;
|
@ -3,6 +3,8 @@ mod data_packet;
|
||||
mod id_manager;
|
||||
mod time_manager;
|
||||
mod avatar_builder;
|
||||
|
||||
#[macro_use]
|
||||
mod remapper;
|
||||
|
||||
pub use self::handshake_packet::HandshakePacket;
|
||||
|
@ -1,5 +1,19 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! collection {
|
||||
// map-like
|
||||
($($k:expr => $v:expr),* $(,)?) => {{
|
||||
use std::iter::{Iterator, IntoIterator};
|
||||
Iterator::collect(IntoIterator::into_iter([$(($k, $v),)*]))
|
||||
}};
|
||||
// set-like
|
||||
($($v:expr),* $(,)?) => {{
|
||||
use std::iter::{Iterator, IntoIterator};
|
||||
Iterator::collect(IntoIterator::into_iter([$($v,)*]))
|
||||
}};
|
||||
}
|
||||
|
||||
pub struct Remapper {}
|
||||
|
||||
impl Remapper {
|
||||
@ -46,4 +60,17 @@ impl Remapper {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn remap4(map: &HashMap<proto::FightPropType, f32>) -> Vec<proto::FightPropPair> {
|
||||
let mut ret = vec![];
|
||||
|
||||
for (key, value) in map {
|
||||
let mut pair = proto::FightPropPair::default();
|
||||
pair.prop_type = *key as u32;
|
||||
pair.prop_value = *value;
|
||||
ret.push(pair);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user