use data::tables::{AvatarBaseID, MainCityBgmConfigID, SectionConfigID}; use proto::*; use thiserror::Error; use crate::logic::{ math::Vector3f, scene::{SceneUnit, SceneUnitManager}, time::MainCityTime, ESceneType, }; use super::NapGameMode; pub struct FrontendGame { section_id: SectionConfigID, frontend_avatar_id: AvatarBaseID, main_city_bgm: MainCityBgmConfigID, scene_unit_mgr: SceneUnitManager, camera_x: u32, camera_y: u32, entry_transform: String, main_city_time: MainCityTime, avatar_pos: Vector3f, avatar_rot: Vector3f, } #[derive(Error, Debug)] pub enum FrontendGameError { #[error("player's frontend avatar is None")] NoFrontendAvatar, } impl FrontendGame { const DEFAULT_BGM_ID: u32 = 1005; pub fn new( section_id: SectionConfigID, avatar_id: AvatarBaseID, main_city_time: MainCityTime, avatar_pos: Vector3f, avatar_rot: Vector3f, ) -> Result { let instance = Self { section_id, main_city_time, main_city_bgm: MainCityBgmConfigID::new_unchecked(Self::DEFAULT_BGM_ID), scene_unit_mgr: SceneUnitManager::new(section_id), frontend_avatar_id: avatar_id, camera_x: 0xFFFFFFFF, camera_y: 0xFFFFFFFF, entry_transform: section_id.template().primary_entry_name.clone(), avatar_pos, avatar_rot, }; tracing::info!("creating new frontend game (section={section_id}, avatar={avatar_id})"); Ok(instance) } pub fn set_entry_transform(&mut self, transform_name: String) { self.entry_transform = transform_name; } } impl NapGameMode for FrontendGame { fn scene_info(&self) -> Option { Some(SceneInfo { scene_type: self.scene_type() as u32, hall_scene_info: Some(HallSceneInfo { section_id: self.section_id.value(), frontend_avatar_id: self.frontend_avatar_id.value(), main_city_bgm_id: self.main_city_bgm.value(), camera_x: self.camera_x, camera_y: self.camera_y, transform: self .avatar_pos .is_zero() .then_some(self.entry_transform.clone()) .unwrap_or_default(), day_of_week: self.main_city_time.day_of_week.value(), time_of_day: self.main_city_time.time_of_day.value(), position: (!self.avatar_pos.is_zero()).then_some(Transform { position: self.avatar_pos.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() }) } fn dungeon_info(&self) -> Option { None } fn scene_type(&self) -> ESceneType { ESceneType::Hall } }