SceneUnitManager: create default scene units

This commit is contained in:
xeon 2024-07-25 19:49:39 +03:00
parent d3cd213d27
commit d196ef861a
14 changed files with 237248 additions and 166 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,28 @@
use serde::Deserialize;
template_id!(MainCityObject u32 tag_id);
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct MainCityObjectTemplate {
#[serde(rename = "TagID")]
pub tag_id: MainCityObjectID,
#[serde(rename = "NPCID")]
pub npc_id: u32,
pub create_position: String,
pub create_type: u32,
#[serde(rename = "DefaultInteractIDs")]
pub default_interact_ids: Vec<u32>,
pub interact_name: String,
pub interact_shape: u32,
pub interact_scale: String,
pub focus_interact_scale: f32,
pub camera_story_key: String,
}
impl MainCityObjectTemplate {
pub fn get_section_name(&self) -> String {
let section_name = self.create_position.split('_').next().unwrap();
format!("SectionName_{section_name}")
}
}

View file

@ -82,4 +82,5 @@ template_tables! {
PostGirlConfigTemplate; PostGirlConfigTemplate;
TrainingQuestTemplate; TrainingQuestTemplate;
WeaponTemplate; WeaponTemplate;
MainCityObjectTemplate;
} }

View file

@ -12,7 +12,7 @@ pub async fn on_get_tips_info(
Ok(GetTipsInfoScRsp { Ok(GetTipsInfoScRsp {
retcode: Retcode::RetSucc.into(), retcode: Retcode::RetSucc.into(),
tips_info: Some(TipsInfo::default()), tips_info: Some(TipsInfo::default()),
ofolagfmcmo: req.ofolagfmcmo, // tips group type r#type: req.r#type, // tips group type
}) })
} }

View file

@ -95,6 +95,7 @@ req_handlers! {
world::StartTrialFightingMission; world::StartTrialFightingMission;
world::EndBattle; world::EndBattle;
world::LeaveCurDungeon; world::LeaveCurDungeon;
world::InteractWithUnit;
client_systems::ReportUiLayoutPlatform; client_systems::ReportUiLayoutPlatform;
client_systems::PlayerOperation; client_systems::PlayerOperation;
client_systems::UnlockNewbieGroup; client_systems::UnlockNewbieGroup;

View file

@ -125,7 +125,7 @@ pub async fn on_beginner_battle_rebegin(
pub async fn on_enter_section( pub async fn on_enter_section(
_session: &NetSession, _session: &NetSession,
_player: &mut Player, _player: &mut Player,
_req: EnterSectionCsReq, req: EnterSectionCsReq,
) -> NetResult<EnterSectionScRsp> { ) -> NetResult<EnterSectionScRsp> {
Ok(EnterSectionScRsp { Ok(EnterSectionScRsp {
retcode: Retcode::RetSucc.into(), retcode: Retcode::RetSucc.into(),
@ -203,3 +203,15 @@ pub async fn on_leave_cur_dungeon(
retcode: Retcode::RetSucc.into(), retcode: Retcode::RetSucc.into(),
}) })
} }
pub async fn on_interact_with_unit(
_session: &NetSession,
_player: &mut Player,
req: InteractWithUnitCsReq,
) -> NetResult<InteractWithUnitScRsp> {
tracing::info!("interact: {req:?}");
Ok(InteractWithUnitScRsp {
retcode: Retcode::RetSucc.into(),
})
}

View file

@ -2,13 +2,19 @@ use data::tables::{AvatarBaseID, SectionConfigID};
use proto::*; use proto::*;
use thiserror::Error; use thiserror::Error;
use crate::logic::{math::Vector3f, time::MainCityTime, ESceneType}; use crate::logic::{
math::Vector3f,
scene::{SceneUnit, SceneUnitManager},
time::MainCityTime,
ESceneType,
};
use super::NapGameMode; use super::NapGameMode;
pub struct FrontendGame { pub struct FrontendGame {
section_id: SectionConfigID, section_id: SectionConfigID,
frontend_avatar_id: AvatarBaseID, frontend_avatar_id: AvatarBaseID,
scene_unit_mgr: SceneUnitManager,
camera_x: u32, camera_x: u32,
camera_y: u32, camera_y: u32,
born_pos: String, born_pos: String,
@ -34,6 +40,7 @@ impl FrontendGame {
let instance = Self { let instance = Self {
section_id, section_id,
main_city_time, main_city_time,
scene_unit_mgr: SceneUnitManager::new(section_id),
frontend_avatar_id: avatar_id, frontend_avatar_id: avatar_id,
camera_x: 0xFFFFFFFF, camera_x: 0xFFFFFFFF,
camera_y: 0xFFFFFFFF, camera_y: 0xFFFFFFFF,
@ -67,6 +74,12 @@ impl NapGameMode for FrontendGame {
position: self.avatar_pos.to_vec(), position: self.avatar_pos.to_vec(),
rotation: self.avatar_rot.to_vec(), rotation: self.avatar_rot.to_vec(),
}), }),
scene_unit_list: self
.scene_unit_mgr
.unit_vec
.iter()
.map(SceneUnit::protocol_info)
.collect(),
..Default::default() ..Default::default()
}), }),
..Default::default() ..Default::default()

View file

@ -22,3 +22,33 @@ impl Vector3f {
self.x == 0.0 && self.y == 0.0 && self.z == 0.0 self.x == 0.0 && self.y == 0.0 && self.z == 0.0
} }
} }
#[derive(Default, Debug, Clone)]
pub struct InteractScale {
pub x: f64,
pub y: f64,
pub z: f64,
pub w: f64,
pub r: f64,
}
impl InteractScale {
pub fn from_str(s: &str) -> Option<Self> {
let scale = s
.split(',')
.map(|c| c.parse::<f64>().unwrap_or_default())
.collect::<Vec<_>>();
if scale.len() == 5 {
Some(Self {
x: scale[0],
y: scale[1],
z: scale[2],
w: scale[3],
r: scale[4],
})
} else {
None
}
}
}

View file

@ -5,6 +5,7 @@ pub mod math;
pub mod player; pub mod player;
pub mod procedure; pub mod procedure;
pub mod role; pub mod role;
pub mod scene;
pub mod time; pub mod time;
pub use enums::*; pub use enums::*;

View file

@ -0,0 +1,28 @@
use std::collections::HashMap;
use proto::{InteractInfo, InteractTarget};
use crate::logic::math::InteractScale;
#[derive(Debug)]
pub struct InteractComponent {
pub interact_id: u32,
pub participators: HashMap<u32, String>,
pub scale: InteractScale,
}
impl InteractComponent {
pub fn to_client(&self) -> InteractInfo {
InteractInfo {
interact_id: self.interact_id as i32,
participators: self.participators.clone(),
interact_target_list: vec![InteractTarget::Npc.into()], // TODO
scale_x: self.scale.x,
scale_y: self.scale.y,
scale_z: self.scale.z,
scale_w: self.scale.w,
scale_r: self.scale.r,
..Default::default()
}
}
}

View file

@ -0,0 +1,7 @@
mod interact;
mod unit;
mod unit_mgr;
pub use interact::InteractComponent;
pub use unit::SceneUnit;
pub use unit_mgr::SceneUnitManager;

View file

@ -0,0 +1,65 @@
use std::collections::HashMap;
use data::tables::MainCityObjectID;
use proto::SceneUnitProtocolInfo;
use crate::logic::math::InteractScale;
use super::InteractComponent;
pub struct SceneUnit {
pub tag: u32,
pub interacts: HashMap<u32, InteractComponent>,
}
impl SceneUnit {
pub fn new(template_id: MainCityObjectID) -> Self {
let template = template_id.template();
Self {
tag: template.tag_id.value(),
interacts: Self::create_default_interacts(
&template.default_interact_ids,
template.tag_id.value(),
&template.interact_name,
&template.interact_scale,
),
}
}
pub fn protocol_info(&self) -> SceneUnitProtocolInfo {
SceneUnitProtocolInfo {
is_interactable: !self.interacts.is_empty(),
tag: self.tag,
interacts_info: self
.interacts
.iter()
.map(|(id, comp)| (*id, comp.to_client()))
.collect(),
..Default::default()
}
}
fn create_default_interacts(
interact_ids: &[u32],
tag: u32,
name: &str,
scale: &str,
) -> HashMap<u32, InteractComponent> {
let scale = InteractScale::from_str(scale).unwrap_or_default();
interact_ids
.iter()
.map(|id| {
(
*id,
InteractComponent {
participators: HashMap::from([(tag, name.to_string())]),
interact_id: tag,
scale: scale.clone(),
},
)
})
.collect()
}
}

View file

@ -0,0 +1,25 @@
use data::tables::{self, SectionConfigID};
use super::SceneUnit;
pub struct SceneUnitManager {
pub unit_vec: Vec<SceneUnit>,
}
impl SceneUnitManager {
pub fn new(section_id: SectionConfigID) -> Self {
let section_template = section_id.template();
let unit_vec = tables::main_city_object_template_tb::iter()
.filter(|tmpl| tmpl.get_section_name() == section_template.section_name)
.filter(|tmpl| {
tmpl.create_type == 0
&& !tmpl.create_position.contains("Test")
&& !tmpl.default_interact_ids.is_empty()
})
.map(|tmpl| SceneUnit::new(tmpl.tag_id))
.collect();
Self { unit_vec }
}
}

File diff suppressed because it is too large Load diff