newtype fun
use newtypes for template ids, pros: 1) enforces id validation 2) ease of use (helper method for getting template struct right away)
This commit is contained in:
parent
69634fda64
commit
99123a15ef
30 changed files with 228 additions and 136 deletions
|
@ -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,
|
||||
|
|
|
@ -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<Self> {
|
||||
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! {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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<i32>,
|
||||
pub jump_tos: Vec<u32>,
|
||||
pub procedure_banks: Vec<String>,
|
||||
pub procedure_event: String,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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::<u32>()?;
|
||||
let avatar_id = args[1].parse::<u32>()?;
|
||||
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()
|
||||
})
|
||||
|
|
|
@ -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::<u32>()?;
|
||||
let weapon_id = args[1].parse::<u32>()?;
|
||||
|
||||
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"));
|
||||
|
|
|
@ -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::<u32>()?;
|
||||
let avatar_id = args[1].parse::<u32>()?;
|
||||
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::<u32>()?;
|
||||
let procedure_id = args[1].parse::<i32>()?;
|
||||
|
||||
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:?}"
|
||||
))
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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<WeaponDressScRsp> {
|
||||
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<WeaponUnDressScRsp> {
|
||||
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;
|
||||
|
|
|
@ -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<EnterWorldScRsp> {
|
||||
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<StartTrialFightingMissionScRsp> {
|
||||
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)?,
|
||||
);
|
||||
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
|
@ -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<String> {
|
||||
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,
|
||||
|
|
|
@ -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<Self, HollowGameError> {
|
||||
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,
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String>,
|
||||
pub frontend_avatar_id: i32,
|
||||
pub beginner_procedure_id: i32,
|
||||
pub beginner_procedure_id: Option<ProcedureConfigID>,
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,52 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use data::tables::UnlockConfigID;
|
||||
use proto::{LockModelBin, UnlockData};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LockModel {
|
||||
unlock_list: BTreeSet<i32>,
|
||||
unlock_list: BTreeSet<UnlockConfigID>,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ProcedureConfigID> {
|
||||
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<ProcedureState, ProcedureError>;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ProcedureConfigID>,
|
||||
procedures: Vec<Procedure>,
|
||||
}
|
||||
|
||||
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<ProcedureConfigID> {
|
||||
self.cur_procedure_id
|
||||
}
|
||||
|
||||
pub fn is_end(&self) -> bool {
|
||||
self.cur_procedure_id == -1
|
||||
self.cur_procedure_id.is_none()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue