From 99123a15efc52c7ec601edff5d93962f1cf44681 Mon Sep 17 00:00:00 2001 From: xeon Date: Thu, 25 Jul 2024 01:24:48 +0300 Subject: [PATCH] newtype fun use newtypes for template ids, pros: 1) enforces id validation 2) ease of use (helper method for getting template struct right away) --- nap_data/src/tables/avatar_base_template.rs | 4 +- nap_data/src/tables/mod.rs | 40 +++++++++++++++++- .../src/tables/post_girl_config_template.rs | 4 +- .../src/tables/procedure_config_template.rs | 6 ++- .../src/tables/section_config_template.rs | 4 +- .../src/tables/training_quest_template.rs | 4 +- nap_data/src/tables/unlock_config_template.rs | 4 +- nap_data/src/tables/weapon_template.rs | 4 +- nap_gameserver/src/commands/avatar.rs | 11 +++-- nap_gameserver/src/commands/item.rs | 7 ++-- nap_gameserver/src/commands/player.rs | 23 +++++----- nap_gameserver/src/handlers/client_systems.rs | 4 +- nap_gameserver/src/handlers/item.rs | 10 ++++- nap_gameserver/src/handlers/world.rs | 17 +++++--- nap_gameserver/src/logic/game/fresh.rs | 9 +++- nap_gameserver/src/logic/game/frontend.rs | 22 +++------- nap_gameserver/src/logic/game/hollow.rs | 15 +++---- nap_gameserver/src/logic/item/item_model.rs | 3 +- nap_gameserver/src/logic/item/weapon.rs | 18 ++++---- .../src/logic/player/basic_data_model.rs | 15 +++++-- nap_gameserver/src/logic/player/lock_model.rs | 27 +++++++++--- .../src/logic/player/main_city_model.rs | 9 ++-- nap_gameserver/src/logic/player/player.rs | 8 +++- nap_gameserver/src/logic/procedure/battle.rs | 8 ++-- nap_gameserver/src/logic/procedure/mod.rs | 14 ++++--- .../src/logic/procedure/plot_play.rs | 8 ++-- .../src/logic/procedure/procedure_mgr.rs | 42 +++++++++++-------- .../src/logic/procedure/select_role.rs | 8 ++-- nap_gameserver/src/logic/role/avatar.rs | 11 ++--- nap_gameserver/src/logic/role/role_model.rs | 5 ++- 30 files changed, 228 insertions(+), 136 deletions(-) diff --git a/nap_data/src/tables/avatar_base_template.rs b/nap_data/src/tables/avatar_base_template.rs index ea01361..85ec3c2 100644 --- a/nap_data/src/tables/avatar_base_template.rs +++ b/nap_data/src/tables/avatar_base_template.rs @@ -1,10 +1,12 @@ use serde::Deserialize; +template_id!(AvatarBase u32 id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct AvatarBaseTemplate { #[serde(rename = "ID")] - pub id: u32, + pub id: AvatarBaseID, pub code_name: String, pub name: String, pub full_name: String, diff --git a/nap_data/src/tables/mod.rs b/nap_data/src/tables/mod.rs index 9ad808c..70400b9 100644 --- a/nap_data/src/tables/mod.rs +++ b/nap_data/src/tables/mod.rs @@ -3,11 +3,49 @@ use std::sync::OnceLock; use super::DataLoadError; +macro_rules! template_id { + ($type_name:ident $underlying_type:ident $id_field:ident) => { + ::paste::paste! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ::serde::Deserialize, ::serde::Serialize)] + pub struct [<$type_name ID>]($underlying_type); + + impl [<$type_name ID>] { + pub fn new(id: $underlying_type) -> Option { + if crate::tables::[<$type_name:snake _template_tb>]::iter().any(|tmpl| tmpl.$id_field.value() == id) { + Some(Self(id)) + } + else { + None + } + } + + pub fn new_unchecked(id: $underlying_type) -> Self { + Self(id) + } + + pub fn value(&self) -> $underlying_type { + self.0 + } + + pub fn template(&self) -> &[<$type_name Template>] { + crate::tables::[<$type_name:snake _template_tb>]::iter().find(|tmpl| tmpl.$id_field == *self).unwrap() + } + } + + impl ::std::fmt::Display for [<$type_name ID>] { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } + } + } + }; +} + macro_rules! template_tables { ($($template_type:ident;)*) => { $(paste! { mod [<$template_type:snake>]; - pub use [<$template_type:snake>]::$template_type; + pub use [<$template_type:snake>]::*; })* $(paste! { diff --git a/nap_data/src/tables/post_girl_config_template.rs b/nap_data/src/tables/post_girl_config_template.rs index 6ac70f6..eff2157 100644 --- a/nap_data/src/tables/post_girl_config_template.rs +++ b/nap_data/src/tables/post_girl_config_template.rs @@ -1,9 +1,11 @@ use serde::Deserialize; +template_id!(PostGirlConfig u32 id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct PostGirlConfigTemplate { #[serde(rename = "ID")] - pub id: u32, + pub id: PostGirlConfigID, pub name: String, } diff --git a/nap_data/src/tables/procedure_config_template.rs b/nap_data/src/tables/procedure_config_template.rs index 850d44c..768746a 100644 --- a/nap_data/src/tables/procedure_config_template.rs +++ b/nap_data/src/tables/procedure_config_template.rs @@ -1,14 +1,16 @@ use serde::Deserialize; +template_id!(ProcedureConfig u32 procedure_id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct ProcedureConfigTemplate { #[serde(rename = "ProcedureID")] - pub procedure_id: i32, + pub procedure_id: ProcedureConfigID, pub procedure_type: u32, #[serde(rename = "ContentID")] pub content_id: String, - pub jump_tos: Vec, + pub jump_tos: Vec, pub procedure_banks: Vec, pub procedure_event: String, } diff --git a/nap_data/src/tables/section_config_template.rs b/nap_data/src/tables/section_config_template.rs index d277c8f..97cdede 100644 --- a/nap_data/src/tables/section_config_template.rs +++ b/nap_data/src/tables/section_config_template.rs @@ -1,9 +1,11 @@ use serde::Deserialize; +template_id!(SectionConfig u32 section_id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct SectionConfigTemplate { - pub section_id: u32, + pub section_id: SectionConfigID, pub photo_name: String, pub name: String, pub primary_entry_name: String, diff --git a/nap_data/src/tables/training_quest_template.rs b/nap_data/src/tables/training_quest_template.rs index 028f363..7c73ef8 100644 --- a/nap_data/src/tables/training_quest_template.rs +++ b/nap_data/src/tables/training_quest_template.rs @@ -1,9 +1,11 @@ use serde::Deserialize; +template_id!(TrainingQuest u32 id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct TrainingQuestTemplate { - pub id: u32, + pub id: TrainingQuestID, pub training_type: u32, pub battle_event_id: u32, } diff --git a/nap_data/src/tables/unlock_config_template.rs b/nap_data/src/tables/unlock_config_template.rs index 083d434..05f5381 100644 --- a/nap_data/src/tables/unlock_config_template.rs +++ b/nap_data/src/tables/unlock_config_template.rs @@ -1,9 +1,11 @@ use serde::Deserialize; +template_id!(UnlockConfig i32 id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct UnlockConfigTemplate { #[serde(rename = "ID")] - pub id: i32, + pub id: UnlockConfigID, pub name: String, } diff --git a/nap_data/src/tables/weapon_template.rs b/nap_data/src/tables/weapon_template.rs index 46e540a..1a87d11 100644 --- a/nap_data/src/tables/weapon_template.rs +++ b/nap_data/src/tables/weapon_template.rs @@ -1,10 +1,12 @@ use serde::Deserialize; +template_id!(Weapon u32 item_id); + #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] pub struct WeaponTemplate { #[serde(rename = "ItemID")] - pub item_id: u32, + pub item_id: WeaponID, pub code_name: String, #[serde(rename = "Type")] pub weapon_type: u32, diff --git a/nap_gameserver/src/commands/avatar.rs b/nap_gameserver/src/commands/avatar.rs index c4af5ca..c461f10 100644 --- a/nap_gameserver/src/commands/avatar.rs +++ b/nap_gameserver/src/commands/avatar.rs @@ -1,4 +1,4 @@ -use data::tables; +use data::tables::AvatarBaseID; use proto::{AddAvatarPerformType, AddAvatarScNotify, PlayerSyncScNotify}; use crate::ServerState; @@ -17,15 +17,14 @@ pub async fn add( let uid = args[0].parse::()?; let avatar_id = args[1].parse::()?; + let Some(avatar_id) = AvatarBaseID::new(avatar_id) else { + return Ok(format!("avatar with id {avatar_id} doesn't exist")); + }; let Some(player_lock) = state.player_mgr.get_player(uid).await else { return Ok(String::from("player not found")); }; - if !tables::avatar_base_template_tb::iter().any(|tmpl| tmpl.id == avatar_id) { - return Ok(format!("avatar with id {avatar_id} doesn't exist")); - } - let (session_id, avatar_sync) = { let mut player = player_lock.lock().await; @@ -36,7 +35,7 @@ pub async fn add( if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() { session .notify(AddAvatarScNotify { - avatar_id, + avatar_id: avatar_id.value(), perform_type: AddAvatarPerformType::Gacha.into(), ..Default::default() }) diff --git a/nap_gameserver/src/commands/item.rs b/nap_gameserver/src/commands/item.rs index 13216d5..7cc55d0 100644 --- a/nap_gameserver/src/commands/item.rs +++ b/nap_gameserver/src/commands/item.rs @@ -1,4 +1,4 @@ -use data::tables; +use data::tables::WeaponID; use proto::PlayerSyncScNotify; use crate::ServerState; @@ -17,10 +17,9 @@ pub async fn add_weapon( let uid = args[0].parse::()?; let weapon_id = args[1].parse::()?; - - if !tables::weapon_template_tb::iter().any(|tmpl| tmpl.item_id == weapon_id) { + let Some(weapon_id) = WeaponID::new(weapon_id) else { return Ok(format!("weapon with id {weapon_id} doesn't exist")); - } + }; let Some(player_lock) = state.player_mgr.get_player(uid).await else { return Ok(String::from("player not found")); diff --git a/nap_gameserver/src/commands/player.rs b/nap_gameserver/src/commands/player.rs index bb2c89a..f269eda 100644 --- a/nap_gameserver/src/commands/player.rs +++ b/nap_gameserver/src/commands/player.rs @@ -1,4 +1,4 @@ -use data::tables; +use data::tables::{AvatarBaseID, ProcedureConfigID}; use proto::PlayerSyncScNotify; use crate::ServerState; @@ -17,18 +17,17 @@ pub async fn avatar( let uid = args[0].parse::()?; let avatar_id = args[1].parse::()?; + let Some(avatar_id) = AvatarBaseID::new(avatar_id) else { + return Ok(format!("avatar with id {avatar_id} doesn't exist")); + }; let Some(player_lock) = state.player_mgr.get_player(uid).await else { return Ok(String::from("player not found")); }; - if !tables::avatar_base_template_tb::iter().any(|tmpl| tmpl.id == avatar_id) { - return Ok(format!("avatar with id {avatar_id} doesn't exist")); - } - let should_save = { let mut player = player_lock.lock().await; - player.basic_data_model.frontend_avatar_id = avatar_id as i32; + player.basic_data_model.frontend_avatar_id = avatar_id.value() as i32; player.current_session_id().is_none() }; @@ -103,12 +102,10 @@ pub async fn procedure( let uid = args[0].parse::()?; let procedure_id = args[1].parse::()?; - if procedure_id != -1 - && !tables::procedure_config_template_tb::iter() - .any(|tmpl| tmpl.procedure_id == procedure_id) - { - return Ok(format!("procedure_id {procedure_id} doesn't exist")); - } + let procedure_id = match procedure_id { + 1.. => ProcedureConfigID::new(procedure_id as u32), + _ => None, + }; let Some(player_lock) = state.player_mgr.get_player(uid).await else { return Ok(String::from("player not found")); @@ -126,6 +123,6 @@ pub async fn procedure( } Ok(format!( - "successfully changed procedure_id to {procedure_id}" + "successfully changed procedure_id to {procedure_id:?}" )) } diff --git a/nap_gameserver/src/handlers/client_systems.rs b/nap_gameserver/src/handlers/client_systems.rs index 900ea63..ce9cc3d 100644 --- a/nap_gameserver/src/handlers/client_systems.rs +++ b/nap_gameserver/src/handlers/client_systems.rs @@ -26,11 +26,11 @@ pub async fn on_get_client_systems_info( info: Some(ClientSystemsInfo { post_girl_data: Some(PostGirlData { selected_post_girl_id_list: tables::post_girl_config_template_tb::iter() - .map(|template| template.id) + .map(|template| template.id.value()) .collect(), post_girl_list: tables::post_girl_config_template_tb::iter() .map(|template| PostGirlItem { - template_id: template.id, + template_id: template.id.value(), unlock_time: 1000, }) .collect(), diff --git a/nap_gameserver/src/handlers/item.rs b/nap_gameserver/src/handlers/item.rs index 9dbd0a1..bf5a07a 100644 --- a/nap_gameserver/src/handlers/item.rs +++ b/nap_gameserver/src/handlers/item.rs @@ -1,3 +1,5 @@ +use data::tables::AvatarBaseID; + use super::*; pub async fn on_get_item_data( @@ -20,7 +22,10 @@ pub async fn on_weapon_dress( player: &mut Player, req: WeaponDressCsReq, ) -> NetResult { - player.dress_weapon(req.avatar_id, req.weapon_uid.into())?; + player.dress_weapon( + AvatarBaseID::new(req.avatar_id).ok_or(Retcode::RetFail)?, + req.weapon_uid.into(), + )?; session .notify(PlayerSyncScNotify { @@ -40,11 +45,12 @@ pub async fn on_weapon_un_dress( player: &mut Player, req: WeaponUnDressCsReq, ) -> NetResult { + let avatar_id = AvatarBaseID::new(req.avatar_id).ok_or(Retcode::RetFail)?; let avatar = player .role_model .avatar_list .iter_mut() - .find(|a| a.template_id == req.avatar_id) + .find(|a| a.template_id == avatar_id) .ok_or(Retcode::RetFail)?; avatar.weapon_uid = None; diff --git a/nap_gameserver/src/handlers/world.rs b/nap_gameserver/src/handlers/world.rs index 5822de4..9fe32f8 100644 --- a/nap_gameserver/src/handlers/world.rs +++ b/nap_gameserver/src/handlers/world.rs @@ -1,3 +1,5 @@ +use data::tables::{ProcedureConfigID, TrainingQuestID}; + use super::core::NetError; use crate::{ @@ -14,10 +16,8 @@ pub async fn on_enter_world( ) -> NetResult { session.set_state(NetSessionState::EndBasicsReq); - if player.basic_data_model.beginner_procedure_id != -1 { - player.game_instance = GameInstance::Fresh(FreshGame::new( - player.basic_data_model.beginner_procedure_id, - )) + if let Some(procedure_id) = player.basic_data_model.beginner_procedure_id { + player.game_instance = GameInstance::Fresh(FreshGame::new(procedure_id)) } else { player.init_frontend_game()?; } @@ -41,9 +41,12 @@ pub async fn on_advance_beginner_procedure( return Err(NetError::from(Retcode::RetFail)); }; + let procedure_id = + ProcedureConfigID::new(req.procedure_id as u32).ok_or(Retcode::RetFail)?; + fresh_game .procedure_mgr - .try_complete_procedure(req.procedure_id) + .try_complete_procedure(procedure_id) .map_err(LogicError::from)?; player.basic_data_model.beginner_procedure_id = fresh_game.procedure_mgr.procedure_id(); @@ -160,8 +163,10 @@ pub async fn on_start_trial_fighting_mission( player: &mut Player, req: StartTrialFightingMissionCsReq, ) -> NetResult { + let quest_id = TrainingQuestID::new(req.quest_id).ok_or(Retcode::RetFail)?; + player.game_instance = GameInstance::Hollow( - HollowGame::create_training_game(req.quest_id, ELocalPlayType::TrainingRoomFight) + HollowGame::create_training_game(quest_id, ELocalPlayType::TrainingRoomFight) .map_err(LogicError::from)?, ); diff --git a/nap_gameserver/src/logic/game/fresh.rs b/nap_gameserver/src/logic/game/fresh.rs index 6e45310..ea8c8ca 100644 --- a/nap_gameserver/src/logic/game/fresh.rs +++ b/nap_gameserver/src/logic/game/fresh.rs @@ -1,3 +1,4 @@ +use data::tables::ProcedureConfigID; use proto::{DungeonInfo, FreshSceneInfo, SceneInfo}; use crate::logic::{procedure::ProcedureManager, ESceneType}; @@ -9,7 +10,7 @@ pub struct FreshGame { } impl FreshGame { - pub fn new(start_procedure_id: i32) -> Self { + pub fn new(start_procedure_id: ProcedureConfigID) -> Self { Self { procedure_mgr: ProcedureManager::new(start_procedure_id), } @@ -25,7 +26,11 @@ impl NapGameMode for FreshGame { Some(SceneInfo { scene_type: self.scene_type() as u32, fresh_scene_info: Some(FreshSceneInfo { - beginner_procedure_id: (self.procedure_mgr.procedure_id() - 1) as u32, + beginner_procedure_id: self + .procedure_mgr + .procedure_id() + .map(|i| i.value() - 1) + .unwrap_or(0), }), ..Default::default() }) diff --git a/nap_gameserver/src/logic/game/frontend.rs b/nap_gameserver/src/logic/game/frontend.rs index c18edf4..1cddaf5 100644 --- a/nap_gameserver/src/logic/game/frontend.rs +++ b/nap_gameserver/src/logic/game/frontend.rs @@ -1,4 +1,4 @@ -use data::tables; +use data::tables::SectionConfigID; use proto::*; use thiserror::Error; @@ -7,7 +7,7 @@ use crate::logic::{math::Vector3f, time::MainCityTime, ESceneType}; use super::NapGameMode; pub struct FrontendGame { - section_id: u32, + section_id: SectionConfigID, frontend_avatar_id: i32, camera_x: u32, camera_y: u32, @@ -18,14 +18,11 @@ pub struct FrontendGame { } #[derive(Error, Debug)] -pub enum FrontendGameError { - #[error("section id is invalid ({0})")] - InvalidSection(u32), -} +pub enum FrontendGameError {} impl FrontendGame { pub fn new( - section_id: u32, + section_id: SectionConfigID, avatar_id: i32, main_city_time: MainCityTime, avatar_pos: Vector3f, @@ -37,8 +34,7 @@ impl FrontendGame { frontend_avatar_id: avatar_id, camera_x: 0xFFFFFFFF, camera_y: 0xFFFFFFFF, - born_pos: Self::get_default_stage_entry_name(section_id) - .ok_or(FrontendGameError::InvalidSection(section_id))?, + born_pos: section_id.template().primary_entry_name.clone(), avatar_pos, avatar_rot, }; @@ -46,12 +42,6 @@ impl FrontendGame { tracing::info!("creating new frontend game (section={section_id}, avatar={avatar_id})"); Ok(instance) } - - fn get_default_stage_entry_name(section_id: u32) -> Option { - tables::section_config_template_tb::iter() - .find(|tmpl| tmpl.section_id == section_id) - .map(|tmpl| tmpl.primary_entry_name.clone()) - } } impl NapGameMode for FrontendGame { @@ -59,7 +49,7 @@ impl NapGameMode for FrontendGame { Some(SceneInfo { scene_type: self.scene_type() as u32, hall_scene_info: Some(HallSceneInfo { - section_id: self.section_id, + section_id: self.section_id.value(), frontend_avatar_id: self.frontend_avatar_id as u32, camera_x: self.camera_x, camera_y: self.camera_y, diff --git a/nap_gameserver/src/logic/game/hollow.rs b/nap_gameserver/src/logic/game/hollow.rs index 4c7af02..e9de395 100644 --- a/nap_gameserver/src/logic/game/hollow.rs +++ b/nap_gameserver/src/logic/game/hollow.rs @@ -1,5 +1,5 @@ use common::util; -use data::tables; +use data::tables::TrainingQuestID; use proto::{DungeonInfo, DungeonItemData, FightSceneInfo, SceneInfo, WeatherPoolInfo}; use thiserror::Error; @@ -8,10 +8,7 @@ use crate::logic::{ELocalPlayType, ESceneType, TimePeriodType, WeatherType}; use super::NapGameMode; #[derive(Error, Debug)] -pub enum HollowGameError { - #[error("quest id is invalid: {0}")] - InvalidQuestId(u32), -} +pub enum HollowGameError {} pub struct HollowGame { pub quest_id: u32, @@ -24,15 +21,13 @@ pub struct HollowGame { impl HollowGame { pub fn create_training_game( - training_quest_id: u32, + training_quest_id: TrainingQuestID, play_type: ELocalPlayType, ) -> Result { - let template = tables::training_quest_template_tb::iter() - .find(|tmpl| tmpl.id == training_quest_id) - .ok_or(HollowGameError::InvalidQuestId(training_quest_id))?; + let template = training_quest_id.template(); Ok(Self { - quest_id: template.id, + quest_id: template.id.value(), battle_event_id: template.battle_event_id, time_period: TimePeriodType::Morning, weather: WeatherType::SunShine, diff --git a/nap_gameserver/src/logic/item/item_model.rs b/nap_gameserver/src/logic/item/item_model.rs index eb35ce6..a507a0e 100644 --- a/nap_gameserver/src/logic/item/item_model.rs +++ b/nap_gameserver/src/logic/item/item_model.rs @@ -1,4 +1,5 @@ use super::{ItemUID, ResourceItem, Weapon}; +use data::tables::WeaponID; use proto::{ItemModelBin, ItemSync}; pub struct ItemModel { @@ -43,7 +44,7 @@ impl ItemModel { } } - pub fn add_weapon(&mut self, template_id: u32) -> ItemUID { + pub fn add_weapon(&mut self, template_id: WeaponID) -> ItemUID { let uid = self.next_uid(); self.weapons.push(Weapon::new(template_id, uid)); diff --git a/nap_gameserver/src/logic/item/weapon.rs b/nap_gameserver/src/logic/item/weapon.rs index b7e139c..7281fa0 100644 --- a/nap_gameserver/src/logic/item/weapon.rs +++ b/nap_gameserver/src/logic/item/weapon.rs @@ -1,11 +1,11 @@ use super::ItemUID; -use data::tables::{self, WeaponTemplate}; +use data::tables::WeaponID; use proto::{WeaponBin, WeaponInfo}; pub struct Weapon { pub uid: ItemUID, - pub template_id: u32, + pub template_id: WeaponID, pub star: u32, pub level: u32, pub exp: u32, @@ -13,8 +13,8 @@ pub struct Weapon { } impl Weapon { - pub fn new(template_id: u32, uid: ItemUID) -> Self { - let template = Self::get_template(template_id).unwrap(); + pub fn new(template_id: WeaponID, uid: ItemUID) -> Self { + let template = template_id.template(); Self { template_id, @@ -28,7 +28,7 @@ impl Weapon { pub fn from_bin(bin: WeaponBin) -> Self { Self { - template_id: bin.template_id, + template_id: WeaponID::new_unchecked(bin.template_id), uid: bin.uid.into(), star: bin.star, level: bin.level, @@ -39,7 +39,7 @@ impl Weapon { pub fn to_bin(&self) -> WeaponBin { WeaponBin { - template_id: self.template_id, + template_id: self.template_id.value(), uid: self.uid.value(), star: self.star, level: self.level, @@ -50,7 +50,7 @@ impl Weapon { pub fn to_client(&self) -> WeaponInfo { WeaponInfo { - template_id: self.template_id, + template_id: self.template_id.value(), uid: self.uid.value(), star: self.star, level: self.level, @@ -59,8 +59,4 @@ impl Weapon { ..Default::default() } } - - fn get_template(template_id: u32) -> Option<&'static WeaponTemplate> { - tables::weapon_template_tb::iter().find(|tmpl| tmpl.item_id == template_id) - } } diff --git a/nap_gameserver/src/logic/player/basic_data_model.rs b/nap_gameserver/src/logic/player/basic_data_model.rs index 3bb10c0..44d6482 100644 --- a/nap_gameserver/src/logic/player/basic_data_model.rs +++ b/nap_gameserver/src/logic/player/basic_data_model.rs @@ -1,3 +1,4 @@ +use data::tables::ProcedureConfigID; use proto::{BasicDataModelBin, PlayerBasicInfo}; pub struct BasicDataModel { @@ -6,7 +7,7 @@ pub struct BasicDataModel { pub profile_icon: u32, pub nick_name: Option, pub frontend_avatar_id: i32, - pub beginner_procedure_id: i32, + pub beginner_procedure_id: Option, } impl Default for BasicDataModel { @@ -17,7 +18,7 @@ impl Default for BasicDataModel { profile_icon: 3200000, nick_name: None, frontend_avatar_id: 0, - beginner_procedure_id: 1, + beginner_procedure_id: Some(ProcedureConfigID::new_unchecked(1)), } } } @@ -41,7 +42,10 @@ impl BasicDataModel { exp: bin.exp, profile_icon: bin.profile_icon, frontend_avatar_id: bin.frontend_avatar_id, - beginner_procedure_id: bin.beginner_procedure_id, + beginner_procedure_id: match bin.beginner_procedure_id { + 1.. => ProcedureConfigID::new(bin.beginner_procedure_id as u32), + _ => None, + }, nick_name: match bin.nick_name.is_empty() { true => None, false => Some(bin.nick_name), @@ -56,7 +60,10 @@ impl BasicDataModel { profile_icon: self.profile_icon, frontend_avatar_id: self.frontend_avatar_id, nick_name: self.nick_name.clone().unwrap_or_default(), - beginner_procedure_id: self.beginner_procedure_id, + beginner_procedure_id: self + .beginner_procedure_id + .map(|i| i.value() as i32) + .unwrap_or(-1), } } } diff --git a/nap_gameserver/src/logic/player/lock_model.rs b/nap_gameserver/src/logic/player/lock_model.rs index 63ba690..a43d74d 100644 --- a/nap_gameserver/src/logic/player/lock_model.rs +++ b/nap_gameserver/src/logic/player/lock_model.rs @@ -1,37 +1,52 @@ use std::collections::BTreeSet; +use data::tables::UnlockConfigID; use proto::{LockModelBin, UnlockData}; #[derive(Default)] pub struct LockModel { - unlock_list: BTreeSet, + unlock_list: BTreeSet, } impl LockModel { pub fn from_bin(bin: LockModelBin) -> Self { Self { - unlock_list: bin.unlock_list.into_iter().collect(), + unlock_list: bin + .unlock_list + .into_iter() + .map(UnlockConfigID::new_unchecked) + .collect(), } } pub fn to_bin(&self) -> LockModelBin { LockModelBin { - unlock_list: self.unlock_list.clone().into_iter().collect(), + unlock_list: self + .unlock_list + .clone() + .into_iter() + .map(|i| i.value()) + .collect(), } } pub fn to_client(&self) -> UnlockData { UnlockData { - unlock_id_list: self.unlock_list.clone().into_iter().collect(), + unlock_id_list: self + .unlock_list + .clone() + .into_iter() + .map(|i| i.value()) + .collect(), ..Default::default() } } - pub fn add_unlock(&mut self, id: i32) { + pub fn add_unlock(&mut self, id: UnlockConfigID) { self.unlock_list.insert(id); } - pub fn is_unlock(&self, id: i32) -> bool { + pub fn is_unlock(&self, id: UnlockConfigID) -> bool { self.unlock_list.contains(&id) } } diff --git a/nap_gameserver/src/logic/player/main_city_model.rs b/nap_gameserver/src/logic/player/main_city_model.rs index eda8df5..4629d84 100644 --- a/nap_gameserver/src/logic/player/main_city_model.rs +++ b/nap_gameserver/src/logic/player/main_city_model.rs @@ -1,3 +1,4 @@ +use data::tables::SectionConfigID; use proto::{MainCityModelBin, TransformBin}; use super::{math::Vector3f, time::MainCityTime}; @@ -6,7 +7,7 @@ pub struct MainCityModel { pub position: Vector3f, pub rotation: Vector3f, pub main_city_time: MainCityTime, - pub section_id: u32, + pub section_id: SectionConfigID, } impl MainCityModel { @@ -22,7 +23,7 @@ impl MainCityModel { rotation: self.position.to_vec(), }), time: Some(self.main_city_time.to_bin()), - section_id: self.section_id, + section_id: self.section_id.value(), } } @@ -33,7 +34,7 @@ impl MainCityModel { position: Vector3f::from_vec(transform.position), rotation: Vector3f::from_vec(transform.rotation), main_city_time: bin.time.map(MainCityTime::from_bin).unwrap_or_default(), - section_id: bin.section_id, + section_id: SectionConfigID::new_unchecked(bin.section_id), } } } @@ -44,7 +45,7 @@ impl Default for MainCityModel { position: Vector3f::default(), rotation: Vector3f::default(), main_city_time: MainCityTime::default(), - section_id: 1, + section_id: SectionConfigID::new_unchecked(1), } } } diff --git a/nap_gameserver/src/logic/player/player.rs b/nap_gameserver/src/logic/player/player.rs index cdd1519..c437ef6 100644 --- a/nap_gameserver/src/logic/player/player.rs +++ b/nap_gameserver/src/logic/player/player.rs @@ -1,4 +1,4 @@ -use data::tables; +use data::tables::{self, AvatarBaseID}; use proto::{ItemStatic, PlayerDataBin, Retcode}; use super::game::{FrontendGame, GameInstance, LogicError}; @@ -90,7 +90,11 @@ impl Player { Ok(()) } - pub fn dress_weapon(&mut self, avatar_id: u32, weapon_uid: ItemUID) -> Result<(), Retcode> { + pub fn dress_weapon( + &mut self, + avatar_id: AvatarBaseID, + weapon_uid: ItemUID, + ) -> Result<(), Retcode> { self.item_model .weapons .iter() diff --git a/nap_gameserver/src/logic/procedure/battle.rs b/nap_gameserver/src/logic/procedure/battle.rs index 379f087..ef1e532 100644 --- a/nap_gameserver/src/logic/procedure/battle.rs +++ b/nap_gameserver/src/logic/procedure/battle.rs @@ -1,12 +1,14 @@ +use data::tables::ProcedureConfigID; + use super::{ProcedureAction, ProcedureBase, ProcedureError, ProcedureState, ProcedureType}; pub struct ProcedureBattle { - id: i32, + id: ProcedureConfigID, state: ProcedureState, } impl ProcedureBattle { - pub fn new(id: i32) -> Self { + pub fn new(id: ProcedureConfigID) -> Self { Self { id, state: ProcedureState::Init, @@ -15,7 +17,7 @@ impl ProcedureBattle { } impl ProcedureBase for ProcedureBattle { - fn id(&self) -> i32 { + fn id(&self) -> ProcedureConfigID { self.id } diff --git a/nap_gameserver/src/logic/procedure/mod.rs b/nap_gameserver/src/logic/procedure/mod.rs index a74eb11..6bb6693 100644 --- a/nap_gameserver/src/logic/procedure/mod.rs +++ b/nap_gameserver/src/logic/procedure/mod.rs @@ -8,7 +8,7 @@ pub use plot_play::ProcedurePlotPlay; pub use procedure_mgr::ProcedureManager; pub use select_role::ProcedureSelectRole; -use data::tables::{self, ProcedureConfigTemplate}; +use data::tables::{self, ProcedureConfigID, ProcedureConfigTemplate}; use num_enum::TryFromPrimitive; use thiserror::Error; @@ -45,21 +45,25 @@ pub enum ProcedureError { #[error("can't advance procedure because it's not finished")] NotFinished, #[error("trying to complete procedure: {0}, current procedure: {1}")] - InvalidProcedureId(i32, i32), + InvalidProcedureId(ProcedureConfigID, ProcedureConfigID), #[error("current procedure is NULL!")] ProcedureIsNull, } pub trait ProcedureBase { - fn id(&self) -> i32; + fn id(&self) -> ProcedureConfigID; fn procedure_type(&self) -> ProcedureType; - fn get_next_id(&self) -> Option<&i32> { + fn get_next_id(&self) -> Option { let config = tables::procedure_config_template_tb::iter() .find(|tmpl| tmpl.procedure_id == self.id()) .unwrap(); - config.jump_tos.iter().next() + config + .jump_tos + .iter() + .next() + .map(|id| ProcedureConfigID::new_unchecked(*id)) } fn on_action(&mut self, action: ProcedureAction) -> Result; diff --git a/nap_gameserver/src/logic/procedure/plot_play.rs b/nap_gameserver/src/logic/procedure/plot_play.rs index c9bd403..251cd83 100644 --- a/nap_gameserver/src/logic/procedure/plot_play.rs +++ b/nap_gameserver/src/logic/procedure/plot_play.rs @@ -1,12 +1,14 @@ +use data::tables::ProcedureConfigID; + use super::{ProcedureAction, ProcedureBase, ProcedureError, ProcedureState, ProcedureType}; pub struct ProcedurePlotPlay { - id: i32, + id: ProcedureConfigID, state: ProcedureState, } impl ProcedurePlotPlay { - pub fn new(id: i32) -> Self { + pub fn new(id: ProcedureConfigID) -> Self { Self { id, state: ProcedureState::Init, @@ -15,7 +17,7 @@ impl ProcedurePlotPlay { } impl ProcedureBase for ProcedurePlotPlay { - fn id(&self) -> i32 { + fn id(&self) -> ProcedureConfigID { self.id } diff --git a/nap_gameserver/src/logic/procedure/procedure_mgr.rs b/nap_gameserver/src/logic/procedure/procedure_mgr.rs index 70c8680..9c31662 100644 --- a/nap_gameserver/src/logic/procedure/procedure_mgr.rs +++ b/nap_gameserver/src/logic/procedure/procedure_mgr.rs @@ -1,30 +1,34 @@ -use data::tables; +use data::tables::{self, ProcedureConfigID}; use super::{Procedure, ProcedureAction, ProcedureError}; pub struct ProcedureManager { - cur_procedure_id: i32, + cur_procedure_id: Option, procedures: Vec, } impl ProcedureManager { - pub fn new(start_procedure_id: i32) -> Self { + pub fn new(start_procedure_id: ProcedureConfigID) -> Self { Self { - cur_procedure_id: start_procedure_id, + cur_procedure_id: Some(start_procedure_id), procedures: tables::procedure_config_template_tb::iter() - .filter(|tmpl| tmpl.procedure_id >= start_procedure_id) + .filter(|tmpl| tmpl.procedure_id.value() >= start_procedure_id.value()) .map(Procedure::new) .collect(), } } - pub fn try_complete_procedure(&mut self, procedure_id: i32) -> Result<(), ProcedureError> { - (self.cur_procedure_id == procedure_id) - .then_some(()) - .ok_or(ProcedureError::InvalidProcedureId( - procedure_id, - self.cur_procedure_id, - ))?; + pub fn try_complete_procedure( + &mut self, + procedure_id: ProcedureConfigID, + ) -> Result<(), ProcedureError> { + let Some(cur_procedure_id) = self.cur_procedure_id else { + return Err(ProcedureError::ProcedureIsNull); + }; + + (cur_procedure_id == procedure_id).then_some(()).ok_or( + ProcedureError::InvalidProcedureId(procedure_id, cur_procedure_id), + )?; let procedure = self .procedures @@ -33,7 +37,7 @@ impl ProcedureManager { .ok_or(ProcedureError::ProcedureIsNull)?; if procedure.base().is_finished() { - self.cur_procedure_id = procedure.base().get_next_id().cloned().unwrap_or(-1); + self.cur_procedure_id = procedure.base().get_next_id(); Ok(()) } else { Err(ProcedureError::NotFinished) @@ -41,26 +45,30 @@ impl ProcedureManager { } pub fn on_action(&mut self, action: ProcedureAction) -> Result<(), ProcedureError> { + let Some(cur_procedure_id) = self.cur_procedure_id else { + return Err(ProcedureError::ProcedureIsNull); + }; + let procedure = self .procedures .iter_mut() - .find(|proc| proc.base().id() == self.cur_procedure_id) + .find(|proc| proc.base().id() == cur_procedure_id) .ok_or(ProcedureError::ProcedureIsNull)?; let state = procedure.base_mut().on_action(action)?; tracing::info!( "procedure action {action:?} performed, state: {state:?}, procedure id: {}", - self.cur_procedure_id + cur_procedure_id ); Ok(()) } - pub fn procedure_id(&self) -> i32 { + pub fn procedure_id(&self) -> Option { self.cur_procedure_id } pub fn is_end(&self) -> bool { - self.cur_procedure_id == -1 + self.cur_procedure_id.is_none() } } diff --git a/nap_gameserver/src/logic/procedure/select_role.rs b/nap_gameserver/src/logic/procedure/select_role.rs index 4cb2669..f7fe1d1 100644 --- a/nap_gameserver/src/logic/procedure/select_role.rs +++ b/nap_gameserver/src/logic/procedure/select_role.rs @@ -1,12 +1,14 @@ +use data::tables::ProcedureConfigID; + use super::{ProcedureAction, ProcedureBase, ProcedureError, ProcedureState, ProcedureType}; pub struct ProcedureSelectRole { - id: i32, + id: ProcedureConfigID, state: ProcedureState, } impl ProcedureSelectRole { - pub fn new(id: i32) -> Self { + pub fn new(id: ProcedureConfigID) -> Self { Self { id, state: ProcedureState::Init, @@ -15,7 +17,7 @@ impl ProcedureSelectRole { } impl ProcedureBase for ProcedureSelectRole { - fn id(&self) -> i32 { + fn id(&self) -> ProcedureConfigID { self.id } diff --git a/nap_gameserver/src/logic/role/avatar.rs b/nap_gameserver/src/logic/role/avatar.rs index 715f5c4..c4ac1a7 100644 --- a/nap_gameserver/src/logic/role/avatar.rs +++ b/nap_gameserver/src/logic/role/avatar.rs @@ -1,3 +1,4 @@ +use data::tables::AvatarBaseID; use proto::{AvatarBin, AvatarInfo, AvatarSkillInfo}; use crate::logic::item::ItemUID; @@ -6,7 +7,7 @@ use super::AvatarSkill; pub const AVATAR_TALENT_COUNT: usize = 6; pub struct Avatar { - pub template_id: u32, + pub template_id: AvatarBaseID, pub level: u32, pub exp: u32, pub star: u32, @@ -18,7 +19,7 @@ pub struct Avatar { } impl Avatar { - pub fn new(template_id: u32) -> Self { + pub fn new(template_id: AvatarBaseID) -> Self { Self { template_id, level: 60, @@ -39,7 +40,7 @@ impl Avatar { pub fn from_bin(bin: AvatarBin) -> Self { Self { - template_id: bin.template_id, + template_id: AvatarBaseID::new_unchecked(bin.template_id), level: bin.level, exp: bin.exp, star: bin.star, @@ -60,7 +61,7 @@ impl Avatar { pub fn to_bin(&self) -> AvatarBin { AvatarBin { - template_id: self.template_id, + template_id: self.template_id.value(), exp: self.exp, level: self.level, star: self.star, @@ -74,7 +75,7 @@ impl Avatar { pub fn to_client(&self) -> AvatarInfo { AvatarInfo { - template_id: self.template_id, + template_id: self.template_id.value(), level: self.level, skill_list: self .skill_list diff --git a/nap_gameserver/src/logic/role/role_model.rs b/nap_gameserver/src/logic/role/role_model.rs index ade7182..7f93dfe 100644 --- a/nap_gameserver/src/logic/role/role_model.rs +++ b/nap_gameserver/src/logic/role/role_model.rs @@ -1,3 +1,4 @@ +use data::tables::AvatarBaseID; use proto::{AvatarSync, RoleModelBin}; use crate::logic::role::Avatar; @@ -11,7 +12,7 @@ impl Default for RoleModel { Self { avatar_list: Self::DEFAULT_AVATARS .iter() - .map(|tmpl_id| Avatar::new(*tmpl_id)) + .map(|tmpl_id| Avatar::new(AvatarBaseID::new_unchecked(*tmpl_id))) .collect(), } } @@ -20,7 +21,7 @@ impl Default for RoleModel { impl RoleModel { const DEFAULT_AVATARS: [u32; 2] = [1011, 1081]; - pub fn add_avatar(&mut self, template_id: u32) { + pub fn add_avatar(&mut self, template_id: AvatarBaseID) { if !self .avatar_list .iter()