diff --git a/ConfigScript/GMGroupDemo.json b/ConfigScript/GMGroupDemo.json index 3007c47..c3e54af 100644 --- a/ConfigScript/GMGroupDemo.json +++ b/ConfigScript/GMGroupDemo.json @@ -6,6 +6,7 @@ "UnlockAllHollow", "UnlockAllHollowBuff", "UnlockAllCafeItem", + "UnlockAllAvatarSkin", "finishquest 1 0", "finishquest 3 0", "addquest 5 4030136" diff --git a/crates/game-server/src/logic/gm_util.rs b/crates/game-server/src/logic/gm_util.rs index 833ffc5..00d9ca2 100644 --- a/crates/game-server/src/logic/gm_util.rs +++ b/crates/game-server/src/logic/gm_util.rs @@ -72,9 +72,36 @@ pub async fn execute_command(context: &mut CommandContext<'_>, command: &GMComma GMCommand::UnlockAllHollow => gm_unlock_all_hollow(context).await, GMCommand::UnlockAllHollowBuff => gm_unlock_all_hollow_buff(context).await, GMCommand::UnlockAllCafeItem => gm_unlock_all_cafe_item(context).await, + GMCommand::UnlockAllAvatarSkin => gm_unlock_all_avatar_skin(context).await, } } +async fn gm_unlock_all_avatar_skin(context: &mut CommandContext<'_>) { + context + .player + .item_model + .add_or_use_materials( + &context + .state + .filecfg + .avatar_skin_base_template_tb() + .data() + .unwrap() + .iter() + .map(|tmpl| (tmpl.id() as u32, 1).into()) + .collect::>(), + ) + .await; + + context.add_notify(PlayerSyncScNotify { + item_sync: Some(ItemSync { + material_list: context.player.item_model.get_protocol_material_list(), + ..Default::default() + }), + ..Default::default() + }); +} + async fn gm_unlock_all_hollow(context: &mut CommandContext<'_>) { context .player diff --git a/crates/game-server/src/logic/player/item.rs b/crates/game-server/src/logic/player/item.rs index 591da43..08f2400 100644 --- a/crates/game-server/src/logic/player/item.rs +++ b/crates/game-server/src/logic/player/item.rs @@ -101,7 +101,18 @@ impl ItemModel { .transaction::<_, (), DbErr>(|txn| { Box::pin(async move { for model in updated_models { - model.update(txn).await?; + material::Entity::insert(model) + .on_conflict( + OnConflict::new() + .exprs([ + Expr::col(material::Column::OwnerPlayerUid), + Expr::col(material::Column::Id), + ]) + .update_column(material::Column::Num) + .to_owned(), + ) + .exec(txn) + .await?; } Ok(()) @@ -185,3 +196,9 @@ impl ItemModel { .collect() } } + +impl From<(u32, i32)> for MaterialDelta { + fn from((id, num): (u32, i32)) -> Self { + Self { id, num } + } +} diff --git a/crates/game-server/src/logic/player/role.rs b/crates/game-server/src/logic/player/role.rs index f553e2a..70fe557 100644 --- a/crates/game-server/src/logic/player/role.rs +++ b/crates/game-server/src/logic/player/role.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use trigger_database::entity::avatar; use trigger_database::prelude::*; -use trigger_logic::skill::EAvatarSkillType; +use trigger_logic::{skill::EAvatarSkillType, template_ext::TemplateExt}; use trigger_protocol::{Avatar, AvatarSkillLevel, DressedEquip}; use trigger_sv::time_util; @@ -325,6 +325,36 @@ impl RoleModel { } } + pub async fn dress_avatar_skin(&mut self, avatar_id: i32, avatar_skin_id: i32) -> bool { + if avatar_skin_id != 0 + && !self + .context + .filecfg + .skin_targets_avatar(avatar_skin_id, avatar_id) + { + return false; + } + + if let Some(avatar) = self.avatar_map.remove(&(avatar_id as u32)) { + let model = avatar::ActiveModel { + avatar_skin_id: Set(avatar_skin_id), + ..avatar.into() + }; + + self.avatar_map.insert( + avatar_id as u32, + model + .update(self.context.database) + .await + .expect("avatar::update failed"), + ); + + true + } else { + false + } + } + pub fn is_avatar_unlocked(&self, avatar_id: u32) -> bool { self.avatar_map.contains_key(&avatar_id) } diff --git a/crates/game-server/src/session/message/avatar.rs b/crates/game-server/src/session/message/avatar.rs index 2982afb..d80e7a0 100644 --- a/crates/game-server/src/session/message/avatar.rs +++ b/crates/game-server/src/session/message/avatar.rs @@ -32,7 +32,8 @@ mod avatar_module { .weapon_dress( request.avatar_id, request.weapon_uid as i32, - equip_model.is_signature_weapon(request.weapon_uid as i32, request.avatar_id as i32) + equip_model + .is_signature_weapon(request.weapon_uid as i32, request.avatar_id as i32), ) .await { @@ -194,4 +195,53 @@ mod avatar_module { ToggleWeaponShowScRsp { retcode: 1 } } + + pub async fn on_dress_avatar_skin( + context: &mut MessageContext<'_, '_>, + request: DressAvatarSkinCsReq, + ) -> DressAvatarSkinScRsp { + let item_model = &context.player.item_model; + + if item_model.has_enough_material(request.avatar_skin_id, 1) { + let role_model = &mut context.player.role_model; + + if role_model + .dress_avatar_skin(request.avatar_id as i32, request.avatar_skin_id as i32) + .await + { + let avatar_list = role_model.get_protocol_avatar_list(&[request.avatar_id]); + context.add_notify(PlayerSyncScNotify { + avatar_sync: Some(AvatarSync { avatar_list }), + ..Default::default() + }); + + return DressAvatarSkinScRsp { retcode: 0 }; + } + } + + DressAvatarSkinScRsp { retcode: 1 } + } + + pub async fn on_undress_avatar_skin( + context: &mut MessageContext<'_, '_>, + request: UndressAvatarSkinCsReq, + ) -> UndressAvatarSkinScRsp { + // Why separate packet, retards? + let role_model = &mut context.player.role_model; + + if role_model + .dress_avatar_skin(request.avatar_id as i32, 0) + .await + { + let avatar_list = role_model.get_protocol_avatar_list(&[request.avatar_id]); + context.add_notify(PlayerSyncScNotify { + avatar_sync: Some(AvatarSync { avatar_list }), + ..Default::default() + }); + + return UndressAvatarSkinScRsp { retcode: 0 }; + } + + UndressAvatarSkinScRsp { retcode: 1 } + } } diff --git a/crates/trigger-database/src/lib.rs b/crates/trigger-database/src/lib.rs index ab34cbb..f9d7486 100644 --- a/crates/trigger-database/src/lib.rs +++ b/crates/trigger-database/src/lib.rs @@ -14,6 +14,7 @@ pub mod prelude { pub use sea_orm::entity::ActiveValue::*; pub use sea_orm::entity::prelude::*; pub use sea_orm::query::Condition; + pub use sea_orm::sea_query::OnConflict; } #[derive(Debug, Deserialize)] diff --git a/crates/trigger-fileconfig/fbs/tables.fbs b/crates/trigger-fileconfig/fbs/tables.fbs index 1fdbc56..3af04d4 100644 --- a/crates/trigger-fileconfig/fbs/tables.fbs +++ b/crates/trigger-fileconfig/fbs/tables.fbs @@ -558,6 +558,33 @@ table EquipmentLevelTemplate { unk_6: int; } +table AvatarSkinBaseTemplate { + id: int; + server_only_0: int; + DLFHPHCLIBA: string; + NFIEGMLEEFE: string; + avatar_id: int; + server_only_1: int; + server_only_2: int; + server_only_3: int; + GMBBOEGOEPH: string; + HMIOIBHJGCM: [string]; + server_only_4: int; + OEMHKAENMHN: int; + FGJJELBGBBC: string; + FKBJLMBAPDI: int; + server_only_5: int; + server_only_6: int; + server_only_7: int; + server_only_8: int; + server_only_9: int; + DIGLJDFKAMN: string; + BKFKIDCLHKL: int; + FHJDONJMNKP: string; + AHHLKMJEEAE: string; + HPMCPJGPKJB: int; +} + table AvatarBaseTemplateTb { data: [AvatarBaseTemplate]; } @@ -656,4 +683,8 @@ table AvatarPassiveSkillTemplateTb { table EquipmentLevelTemplateTb { data: [EquipmentLevelTemplate]; -} \ No newline at end of file +} + +table AvatarSkinBaseTemplateTb { + data: [AvatarSkinBaseTemplate]; +} diff --git a/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs b/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs index b40ee1a..53453a5 100644 --- a/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs +++ b/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs @@ -14292,6 +14292,696 @@ impl core::fmt::Debug for EquipmentLevelTemplate<'_> { ds.finish() } } +pub enum AvatarSkinBaseTemplateOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct AvatarSkinBaseTemplate<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for AvatarSkinBaseTemplate<'a> { + type Inner = AvatarSkinBaseTemplate<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } +} + +impl<'a> AvatarSkinBaseTemplate<'a> { + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_SERVER_ONLY_0: flatbuffers::VOffsetT = 6; + pub const VT_DLFHPHCLIBA: flatbuffers::VOffsetT = 8; + pub const VT_NFIEGMLEEFE: flatbuffers::VOffsetT = 10; + pub const VT_AVATAR_ID: flatbuffers::VOffsetT = 12; + pub const VT_SERVER_ONLY_1: flatbuffers::VOffsetT = 14; + pub const VT_SERVER_ONLY_2: flatbuffers::VOffsetT = 16; + pub const VT_SERVER_ONLY_3: flatbuffers::VOffsetT = 18; + pub const VT_GMBBOEGOEPH: flatbuffers::VOffsetT = 20; + pub const VT_HMIOIBHJGCM: flatbuffers::VOffsetT = 22; + pub const VT_SERVER_ONLY_4: flatbuffers::VOffsetT = 24; + pub const VT_OEMHKAENMHN: flatbuffers::VOffsetT = 26; + pub const VT_FGJJELBGBBC: flatbuffers::VOffsetT = 28; + pub const VT_FKBJLMBAPDI: flatbuffers::VOffsetT = 30; + pub const VT_SERVER_ONLY_5: flatbuffers::VOffsetT = 32; + pub const VT_SERVER_ONLY_6: flatbuffers::VOffsetT = 34; + pub const VT_SERVER_ONLY_7: flatbuffers::VOffsetT = 36; + pub const VT_SERVER_ONLY_8: flatbuffers::VOffsetT = 38; + pub const VT_SERVER_ONLY_9: flatbuffers::VOffsetT = 40; + pub const VT_DIGLJDFKAMN: flatbuffers::VOffsetT = 42; + pub const VT_BKFKIDCLHKL: flatbuffers::VOffsetT = 44; + pub const VT_FHJDONJMNKP: flatbuffers::VOffsetT = 46; + pub const VT_AHHLKMJEEAE: flatbuffers::VOffsetT = 48; + pub const VT_HPMCPJGPKJB: flatbuffers::VOffsetT = 50; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + AvatarSkinBaseTemplate { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args AvatarSkinBaseTemplateArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = AvatarSkinBaseTemplateBuilder::new(_fbb); + builder.add_HPMCPJGPKJB(args.HPMCPJGPKJB); + if let Some(x) = args.AHHLKMJEEAE { + builder.add_AHHLKMJEEAE(x); + } + if let Some(x) = args.FHJDONJMNKP { + builder.add_FHJDONJMNKP(x); + } + builder.add_BKFKIDCLHKL(args.BKFKIDCLHKL); + if let Some(x) = args.DIGLJDFKAMN { + builder.add_DIGLJDFKAMN(x); + } + builder.add_server_only_9(args.server_only_9); + builder.add_server_only_8(args.server_only_8); + builder.add_server_only_7(args.server_only_7); + builder.add_server_only_6(args.server_only_6); + builder.add_server_only_5(args.server_only_5); + builder.add_FKBJLMBAPDI(args.FKBJLMBAPDI); + if let Some(x) = args.FGJJELBGBBC { + builder.add_FGJJELBGBBC(x); + } + builder.add_OEMHKAENMHN(args.OEMHKAENMHN); + builder.add_server_only_4(args.server_only_4); + if let Some(x) = args.HMIOIBHJGCM { + builder.add_HMIOIBHJGCM(x); + } + if let Some(x) = args.GMBBOEGOEPH { + builder.add_GMBBOEGOEPH(x); + } + builder.add_server_only_3(args.server_only_3); + builder.add_server_only_2(args.server_only_2); + builder.add_server_only_1(args.server_only_1); + builder.add_avatar_id(args.avatar_id); + if let Some(x) = args.NFIEGMLEEFE { + builder.add_NFIEGMLEEFE(x); + } + if let Some(x) = args.DLFHPHCLIBA { + builder.add_DLFHPHCLIBA(x); + } + builder.add_server_only_0(args.server_only_0); + builder.add_id(args.id); + builder.finish() + } + + #[inline] + pub fn id(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_ID, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_0(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_0, Some(0)) + .unwrap() + } + } + #[inline] + pub fn DLFHPHCLIBA(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_DLFHPHCLIBA, + None, + ) + } + } + #[inline] + pub fn NFIEGMLEEFE(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_NFIEGMLEEFE, + None, + ) + } + } + #[inline] + pub fn avatar_id(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_AVATAR_ID, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_1(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_1, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_2(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_2, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_3(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_3, Some(0)) + .unwrap() + } + } + #[inline] + pub fn GMBBOEGOEPH(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_GMBBOEGOEPH, + None, + ) + } + } + #[inline] + pub fn HMIOIBHJGCM( + &self, + ) -> Option>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>, + >>(AvatarSkinBaseTemplate::VT_HMIOIBHJGCM, None) + } + } + #[inline] + pub fn server_only_4(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_4, Some(0)) + .unwrap() + } + } + #[inline] + pub fn OEMHKAENMHN(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_OEMHKAENMHN, Some(0)) + .unwrap() + } + } + #[inline] + pub fn FGJJELBGBBC(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_FGJJELBGBBC, + None, + ) + } + } + #[inline] + pub fn FKBJLMBAPDI(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_FKBJLMBAPDI, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_5(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_5, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_6(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_6, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_7(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_7, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_8(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_8, Some(0)) + .unwrap() + } + } + #[inline] + pub fn server_only_9(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_9, Some(0)) + .unwrap() + } + } + #[inline] + pub fn DIGLJDFKAMN(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_DIGLJDFKAMN, + None, + ) + } + } + #[inline] + pub fn BKFKIDCLHKL(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_BKFKIDCLHKL, Some(0)) + .unwrap() + } + } + #[inline] + pub fn FHJDONJMNKP(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_FHJDONJMNKP, + None, + ) + } + } + #[inline] + pub fn AHHLKMJEEAE(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>( + AvatarSkinBaseTemplate::VT_AHHLKMJEEAE, + None, + ) + } + } + #[inline] + pub fn HPMCPJGPKJB(&self) -> i32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::(AvatarSkinBaseTemplate::VT_HPMCPJGPKJB, Some(0)) + .unwrap() + } + } +} + +impl flatbuffers::Verifiable for AvatarSkinBaseTemplate<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("id", Self::VT_ID, false)? + .visit_field::("server_only_0", Self::VT_SERVER_ONLY_0, false)? + .visit_field::>( + "DLFHPHCLIBA", + Self::VT_DLFHPHCLIBA, + false, + )? + .visit_field::>( + "NFIEGMLEEFE", + Self::VT_NFIEGMLEEFE, + false, + )? + .visit_field::("avatar_id", Self::VT_AVATAR_ID, false)? + .visit_field::("server_only_1", Self::VT_SERVER_ONLY_1, false)? + .visit_field::("server_only_2", Self::VT_SERVER_ONLY_2, false)? + .visit_field::("server_only_3", Self::VT_SERVER_ONLY_3, false)? + .visit_field::>( + "GMBBOEGOEPH", + Self::VT_GMBBOEGOEPH, + false, + )? + .visit_field::>, + >>("HMIOIBHJGCM", Self::VT_HMIOIBHJGCM, false)? + .visit_field::("server_only_4", Self::VT_SERVER_ONLY_4, false)? + .visit_field::("OEMHKAENMHN", Self::VT_OEMHKAENMHN, false)? + .visit_field::>( + "FGJJELBGBBC", + Self::VT_FGJJELBGBBC, + false, + )? + .visit_field::("FKBJLMBAPDI", Self::VT_FKBJLMBAPDI, false)? + .visit_field::("server_only_5", Self::VT_SERVER_ONLY_5, false)? + .visit_field::("server_only_6", Self::VT_SERVER_ONLY_6, false)? + .visit_field::("server_only_7", Self::VT_SERVER_ONLY_7, false)? + .visit_field::("server_only_8", Self::VT_SERVER_ONLY_8, false)? + .visit_field::("server_only_9", Self::VT_SERVER_ONLY_9, false)? + .visit_field::>( + "DIGLJDFKAMN", + Self::VT_DIGLJDFKAMN, + false, + )? + .visit_field::("BKFKIDCLHKL", Self::VT_BKFKIDCLHKL, false)? + .visit_field::>( + "FHJDONJMNKP", + Self::VT_FHJDONJMNKP, + false, + )? + .visit_field::>( + "AHHLKMJEEAE", + Self::VT_AHHLKMJEEAE, + false, + )? + .visit_field::("HPMCPJGPKJB", Self::VT_HPMCPJGPKJB, false)? + .finish(); + Ok(()) + } +} +pub struct AvatarSkinBaseTemplateArgs<'a> { + pub id: i32, + pub server_only_0: i32, + pub DLFHPHCLIBA: Option>, + pub NFIEGMLEEFE: Option>, + pub avatar_id: i32, + pub server_only_1: i32, + pub server_only_2: i32, + pub server_only_3: i32, + pub GMBBOEGOEPH: Option>, + pub HMIOIBHJGCM: Option< + flatbuffers::WIPOffset>>, + >, + pub server_only_4: i32, + pub OEMHKAENMHN: i32, + pub FGJJELBGBBC: Option>, + pub FKBJLMBAPDI: i32, + pub server_only_5: i32, + pub server_only_6: i32, + pub server_only_7: i32, + pub server_only_8: i32, + pub server_only_9: i32, + pub DIGLJDFKAMN: Option>, + pub BKFKIDCLHKL: i32, + pub FHJDONJMNKP: Option>, + pub AHHLKMJEEAE: Option>, + pub HPMCPJGPKJB: i32, +} +impl<'a> Default for AvatarSkinBaseTemplateArgs<'a> { + #[inline] + fn default() -> Self { + AvatarSkinBaseTemplateArgs { + id: 0, + server_only_0: 0, + DLFHPHCLIBA: None, + NFIEGMLEEFE: None, + avatar_id: 0, + server_only_1: 0, + server_only_2: 0, + server_only_3: 0, + GMBBOEGOEPH: None, + HMIOIBHJGCM: None, + server_only_4: 0, + OEMHKAENMHN: 0, + FGJJELBGBBC: None, + FKBJLMBAPDI: 0, + server_only_5: 0, + server_only_6: 0, + server_only_7: 0, + server_only_8: 0, + server_only_9: 0, + DIGLJDFKAMN: None, + BKFKIDCLHKL: 0, + FHJDONJMNKP: None, + AHHLKMJEEAE: None, + HPMCPJGPKJB: 0, + } + } +} + +pub struct AvatarSkinBaseTemplateBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> AvatarSkinBaseTemplateBuilder<'a, 'b, A> { + #[inline] + pub fn add_id(&mut self, id: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_ID, id, 0); + } + #[inline] + pub fn add_server_only_0(&mut self, server_only_0: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_0, server_only_0, 0); + } + #[inline] + pub fn add_DLFHPHCLIBA(&mut self, DLFHPHCLIBA: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_DLFHPHCLIBA, + DLFHPHCLIBA, + ); + } + #[inline] + pub fn add_NFIEGMLEEFE(&mut self, NFIEGMLEEFE: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_NFIEGMLEEFE, + NFIEGMLEEFE, + ); + } + #[inline] + pub fn add_avatar_id(&mut self, avatar_id: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_AVATAR_ID, avatar_id, 0); + } + #[inline] + pub fn add_server_only_1(&mut self, server_only_1: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_1, server_only_1, 0); + } + #[inline] + pub fn add_server_only_2(&mut self, server_only_2: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_2, server_only_2, 0); + } + #[inline] + pub fn add_server_only_3(&mut self, server_only_3: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_3, server_only_3, 0); + } + #[inline] + pub fn add_GMBBOEGOEPH(&mut self, GMBBOEGOEPH: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_GMBBOEGOEPH, + GMBBOEGOEPH, + ); + } + #[inline] + pub fn add_HMIOIBHJGCM( + &mut self, + HMIOIBHJGCM: flatbuffers::WIPOffset< + flatbuffers::Vector<'b, flatbuffers::ForwardsUOffset<&'b str>>, + >, + ) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_HMIOIBHJGCM, + HMIOIBHJGCM, + ); + } + #[inline] + pub fn add_server_only_4(&mut self, server_only_4: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_4, server_only_4, 0); + } + #[inline] + pub fn add_OEMHKAENMHN(&mut self, OEMHKAENMHN: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_OEMHKAENMHN, OEMHKAENMHN, 0); + } + #[inline] + pub fn add_FGJJELBGBBC(&mut self, FGJJELBGBBC: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_FGJJELBGBBC, + FGJJELBGBBC, + ); + } + #[inline] + pub fn add_FKBJLMBAPDI(&mut self, FKBJLMBAPDI: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_FKBJLMBAPDI, FKBJLMBAPDI, 0); + } + #[inline] + pub fn add_server_only_5(&mut self, server_only_5: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_5, server_only_5, 0); + } + #[inline] + pub fn add_server_only_6(&mut self, server_only_6: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_6, server_only_6, 0); + } + #[inline] + pub fn add_server_only_7(&mut self, server_only_7: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_7, server_only_7, 0); + } + #[inline] + pub fn add_server_only_8(&mut self, server_only_8: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_8, server_only_8, 0); + } + #[inline] + pub fn add_server_only_9(&mut self, server_only_9: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_SERVER_ONLY_9, server_only_9, 0); + } + #[inline] + pub fn add_DIGLJDFKAMN(&mut self, DIGLJDFKAMN: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_DIGLJDFKAMN, + DIGLJDFKAMN, + ); + } + #[inline] + pub fn add_BKFKIDCLHKL(&mut self, BKFKIDCLHKL: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_BKFKIDCLHKL, BKFKIDCLHKL, 0); + } + #[inline] + pub fn add_FHJDONJMNKP(&mut self, FHJDONJMNKP: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_FHJDONJMNKP, + FHJDONJMNKP, + ); + } + #[inline] + pub fn add_AHHLKMJEEAE(&mut self, AHHLKMJEEAE: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>( + AvatarSkinBaseTemplate::VT_AHHLKMJEEAE, + AHHLKMJEEAE, + ); + } + #[inline] + pub fn add_HPMCPJGPKJB(&mut self, HPMCPJGPKJB: i32) { + self.fbb_ + .push_slot::(AvatarSkinBaseTemplate::VT_HPMCPJGPKJB, HPMCPJGPKJB, 0); + } + #[inline] + pub fn new( + _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + ) -> AvatarSkinBaseTemplateBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + AvatarSkinBaseTemplateBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +impl core::fmt::Debug for AvatarSkinBaseTemplate<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("AvatarSkinBaseTemplate"); + ds.field("id", &self.id()); + ds.field("server_only_0", &self.server_only_0()); + ds.field("DLFHPHCLIBA", &self.DLFHPHCLIBA()); + ds.field("NFIEGMLEEFE", &self.NFIEGMLEEFE()); + ds.field("avatar_id", &self.avatar_id()); + ds.field("server_only_1", &self.server_only_1()); + ds.field("server_only_2", &self.server_only_2()); + ds.field("server_only_3", &self.server_only_3()); + ds.field("GMBBOEGOEPH", &self.GMBBOEGOEPH()); + ds.field("HMIOIBHJGCM", &self.HMIOIBHJGCM()); + ds.field("server_only_4", &self.server_only_4()); + ds.field("OEMHKAENMHN", &self.OEMHKAENMHN()); + ds.field("FGJJELBGBBC", &self.FGJJELBGBBC()); + ds.field("FKBJLMBAPDI", &self.FKBJLMBAPDI()); + ds.field("server_only_5", &self.server_only_5()); + ds.field("server_only_6", &self.server_only_6()); + ds.field("server_only_7", &self.server_only_7()); + ds.field("server_only_8", &self.server_only_8()); + ds.field("server_only_9", &self.server_only_9()); + ds.field("DIGLJDFKAMN", &self.DIGLJDFKAMN()); + ds.field("BKFKIDCLHKL", &self.BKFKIDCLHKL()); + ds.field("FHJDONJMNKP", &self.FHJDONJMNKP()); + ds.field("AHHLKMJEEAE", &self.AHHLKMJEEAE()); + ds.field("HPMCPJGPKJB", &self.HPMCPJGPKJB()); + ds.finish() + } +} pub enum AvatarBaseTemplateTbOffset {} #[derive(Copy, Clone, PartialEq)] @@ -17304,3 +17994,123 @@ impl core::fmt::Debug for EquipmentLevelTemplateTb<'_> { ds.finish() } } +pub enum AvatarSkinBaseTemplateTbOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct AvatarSkinBaseTemplateTb<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for AvatarSkinBaseTemplateTb<'a> { + type Inner = AvatarSkinBaseTemplateTb<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } +} + +impl<'a> AvatarSkinBaseTemplateTb<'a> { + pub const VT_DATA: flatbuffers::VOffsetT = 4; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + AvatarSkinBaseTemplateTb { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args AvatarSkinBaseTemplateTbArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = AvatarSkinBaseTemplateTbBuilder::new(_fbb); + if let Some(x) = args.data { + builder.add_data(x); + } + builder.finish() + } + + #[inline] + pub fn data( + &self, + ) -> Option>>> + { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab.get::>, + >>(AvatarSkinBaseTemplateTb::VT_DATA, None) + } + } +} + +impl flatbuffers::Verifiable for AvatarSkinBaseTemplateTb<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, + pos: usize, + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>, + >>("data", Self::VT_DATA, false)? + .finish(); + Ok(()) + } +} +pub struct AvatarSkinBaseTemplateTbArgs<'a> { + pub data: Option< + flatbuffers::WIPOffset< + flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset>>, + >, + >, +} +impl<'a> Default for AvatarSkinBaseTemplateTbArgs<'a> { + #[inline] + fn default() -> Self { + AvatarSkinBaseTemplateTbArgs { data: None } + } +} + +pub struct AvatarSkinBaseTemplateTbBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> AvatarSkinBaseTemplateTbBuilder<'a, 'b, A> { + #[inline] + pub fn add_data( + &mut self, + data: flatbuffers::WIPOffset< + flatbuffers::Vector<'b, flatbuffers::ForwardsUOffset>>, + >, + ) { + self.fbb_ + .push_slot_always::>(AvatarSkinBaseTemplateTb::VT_DATA, data); + } + #[inline] + pub fn new( + _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + ) -> AvatarSkinBaseTemplateTbBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + AvatarSkinBaseTemplateTbBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +impl core::fmt::Debug for AvatarSkinBaseTemplateTb<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("AvatarSkinBaseTemplateTb"); + ds.field("data", &self.data()); + ds.finish() + } +} diff --git a/crates/trigger-fileconfig/src/lib.rs b/crates/trigger-fileconfig/src/lib.rs index dae9433..202554e 100644 --- a/crates/trigger-fileconfig/src/lib.rs +++ b/crates/trigger-fileconfig/src/lib.rs @@ -1,4 +1,4 @@ -#[allow(dead_code, unused_imports, unsafe_op_in_unsafe_fn)] +#[allow(dead_code, unused_imports, unsafe_op_in_unsafe_fn, non_snake_case)] #[path = "../gen_flatbuffers/tables_generated.rs"] mod data; pub mod main_city_script; @@ -65,4 +65,5 @@ file_cfg! { WeaponStarTemplateTb; AvatarPassiveSkillTemplateTb; EquipmentLevelTemplateTb; + AvatarSkinBaseTemplateTb; } diff --git a/crates/trigger-logic/src/template_ext.rs b/crates/trigger-logic/src/template_ext.rs index 98568bb..0d513f0 100644 --- a/crates/trigger-logic/src/template_ext.rs +++ b/crates/trigger-logic/src/template_ext.rs @@ -2,6 +2,7 @@ use trigger_fileconfig::NapFileCfg; pub trait TemplateExt { fn is_player_avatar(&self, avatar_id: i32) -> bool; + fn skin_targets_avatar(&self, avatar_skin_id: i32, avatar_id: i32) -> bool; fn procedure_allows_select_role(&self, procedure_id: i32) -> bool; fn is_last_procedure(&self, procedure_id: i32) -> bool; } @@ -16,6 +17,16 @@ impl TemplateExt for NapFileCfg { .unwrap_or(false) } + fn skin_targets_avatar(&self, avatar_skin_id: i32, avatar_id: i32) -> bool { + self.avatar_skin_base_template_tb() + .data() + .unwrap() + .iter() + .find(|tmpl| tmpl.id() == avatar_skin_id) + .map(|tmpl| tmpl.avatar_id() == avatar_id) + .unwrap_or(false) + } + fn procedure_allows_select_role(&self, procedure_id: i32) -> bool { self.procedure_config_template_tb() .data() diff --git a/crates/trigger-protobuf/out/_.rs b/crates/trigger-protobuf/out/_.rs index 3a453bd..7e9fbff 100644 --- a/crates/trigger-protobuf/out/_.rs +++ b/crates/trigger-protobuf/out/_.rs @@ -647,6 +647,15 @@ pub struct BeginnerbattleRebeginScRsp { pub retcode: i32, } #[derive(trigger_protobuf_derive::CmdID)] +#[cmdid(7562)] +#[derive(trigger_protobuf_derive::XorFields)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct UndressAvatarSkinCsReq { + #[xor(4218)] + #[prost(uint32, tag = "12")] + pub avatar_id: u32, +} +#[derive(trigger_protobuf_derive::CmdID)] #[derive(trigger_protobuf_derive::XorFields)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RallySceneInfo { @@ -1930,6 +1939,18 @@ pub struct GetBattlePassDataCsReq {} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct PostEnterWorldCsReq {} #[derive(trigger_protobuf_derive::CmdID)] +#[cmdid(8883)] +#[derive(trigger_protobuf_derive::XorFields)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct DressAvatarSkinCsReq { + #[xor(6961)] + #[prost(uint32, tag = "7")] + pub avatar_id: u32, + #[xor(59)] + #[prost(uint32, tag = "12")] + pub avatar_skin_id: u32, +} +#[derive(trigger_protobuf_derive::CmdID)] #[derive(trigger_protobuf_derive::XorFields)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PublicVariable { diff --git a/crates/trigger-protobuf/out/protocol_map.rs b/crates/trigger-protobuf/out/protocol_map.rs index 97587e3..d501809 100644 --- a/crates/trigger-protobuf/out/protocol_map.rs +++ b/crates/trigger-protobuf/out/protocol_map.rs @@ -315,6 +315,14 @@ pub fn pb_to_common_protocol_unit( ); Ok(Some(common_protocol_message.into())) } + UndressAvatarSkinCsReq::CMD_ID => { + let mut pb_message = UndressAvatarSkinCsReq::decode(pb)?; + pb_message.xor_fields(); + let common_protocol_message = ::trigger_protocol::UndressAvatarSkinCsReq::from( + pb_message, + ); + Ok(Some(common_protocol_message.into())) + } GetPlayerInfoCsReq::CMD_ID => { let mut pb_message = GetPlayerInfoCsReq::decode(pb)?; pb_message.xor_fields(); @@ -1035,6 +1043,14 @@ pub fn pb_to_common_protocol_unit( ); Ok(Some(common_protocol_message.into())) } + DressAvatarSkinCsReq::CMD_ID => { + let mut pb_message = DressAvatarSkinCsReq::decode(pb)?; + pb_message.xor_fields(); + let common_protocol_message = ::trigger_protocol::DressAvatarSkinCsReq::from( + pb_message, + ); + Ok(Some(common_protocol_message.into())) + } GetNewsStandDataCsReq::CMD_ID => { let mut pb_message = GetNewsStandDataCsReq::decode(pb)?; pb_message.xor_fields(); @@ -1550,6 +1566,14 @@ pub fn common_protocol_unit_to_pb( pb_message.xor_fields(); Ok(Some((BeginnerbattleRebeginScRsp::CMD_ID, pb_message.encode_to_vec()))) } + ::trigger_protocol::UndressAvatarSkinCsReq::CMD_ID => { + let common_protocol_message = ::trigger_protocol::UndressAvatarSkinCsReq::decode( + &mut ::std::io::Cursor::new(&unit.blob), + )?; + let mut pb_message = UndressAvatarSkinCsReq::from(common_protocol_message); + pb_message.xor_fields(); + Ok(Some((UndressAvatarSkinCsReq::CMD_ID, pb_message.encode_to_vec()))) + } ::trigger_protocol::GetPlayerInfoCsReq::CMD_ID => { let common_protocol_message = ::trigger_protocol::GetPlayerInfoCsReq::decode( &mut ::std::io::Cursor::new(&unit.blob), @@ -2313,6 +2337,14 @@ pub fn common_protocol_unit_to_pb( pb_message.xor_fields(); Ok(Some((PostEnterWorldCsReq::CMD_ID, pb_message.encode_to_vec()))) } + ::trigger_protocol::DressAvatarSkinCsReq::CMD_ID => { + let common_protocol_message = ::trigger_protocol::DressAvatarSkinCsReq::decode( + &mut ::std::io::Cursor::new(&unit.blob), + )?; + let mut pb_message = DressAvatarSkinCsReq::from(common_protocol_message); + pb_message.xor_fields(); + Ok(Some((DressAvatarSkinCsReq::CMD_ID, pb_message.encode_to_vec()))) + } ::trigger_protocol::GetNewsStandDataCsReq::CMD_ID => { let common_protocol_message = ::trigger_protocol::GetNewsStandDataCsReq::decode( &mut ::std::io::Cursor::new(&unit.blob), @@ -3637,6 +3669,24 @@ for BeginnerbattleRebeginScRsp { } } #[allow(unused)] +impl From for ::trigger_protocol::UndressAvatarSkinCsReq { + fn from(value: UndressAvatarSkinCsReq) -> Self { + Self { + avatar_id: value.avatar_id.into(), + ..Default::default() + } + } +} +#[allow(unused)] +impl From<::trigger_protocol::UndressAvatarSkinCsReq> for UndressAvatarSkinCsReq { + fn from(value: ::trigger_protocol::UndressAvatarSkinCsReq) -> Self { + Self { + avatar_id: value.avatar_id.into(), + ..Default::default() + } + } +} +#[allow(unused)] impl From for ::trigger_protocol::RallySceneInfo { fn from(value: RallySceneInfo) -> Self { Self { @@ -5865,6 +5915,26 @@ impl From<::trigger_protocol::PostEnterWorldCsReq> for PostEnterWorldCsReq { } } #[allow(unused)] +impl From for ::trigger_protocol::DressAvatarSkinCsReq { + fn from(value: DressAvatarSkinCsReq) -> Self { + Self { + avatar_id: value.avatar_id.into(), + avatar_skin_id: value.avatar_skin_id.into(), + ..Default::default() + } + } +} +#[allow(unused)] +impl From<::trigger_protocol::DressAvatarSkinCsReq> for DressAvatarSkinCsReq { + fn from(value: ::trigger_protocol::DressAvatarSkinCsReq) -> Self { + Self { + avatar_id: value.avatar_id.into(), + avatar_skin_id: value.avatar_skin_id.into(), + ..Default::default() + } + } +} +#[allow(unused)] impl From for ::trigger_protocol::PublicVariable { fn from(value: PublicVariable) -> Self { Self { diff --git a/crates/trigger-protocol/src/lib.rs b/crates/trigger-protocol/src/lib.rs index 0a2be8e..c9acf48 100644 --- a/crates/trigger-protocol/src/lib.rs +++ b/crates/trigger-protocol/src/lib.rs @@ -1052,6 +1052,31 @@ pub struct GetAvatarRecommendEquipScRsp { pub retcode: i32, } +#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)] +#[id(842)] +pub struct DressAvatarSkinCsReq { + pub avatar_id: u32, + pub avatar_skin_id: u32, +} + +#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)] +#[id(843)] +pub struct DressAvatarSkinScRsp { + pub retcode: i32, +} + +#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)] +#[id(844)] +pub struct UndressAvatarSkinCsReq { + pub avatar_id: u32, +} + +#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)] +#[id(845)] +pub struct UndressAvatarSkinScRsp { + pub retcode: i32, +} + // Bangboo #[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)] diff --git a/crates/trigger-sv/src/gm_command.rs b/crates/trigger-sv/src/gm_command.rs index 95086de..75e861e 100644 --- a/crates/trigger-sv/src/gm_command.rs +++ b/crates/trigger-sv/src/gm_command.rs @@ -43,6 +43,7 @@ pub enum GMCommand { UnlockAllHollow = 302, UnlockAllHollowBuff = 400, UnlockAllCafeItem = 401, + UnlockAllAvatarSkin = 402, } #[derive(thiserror::Error, Debug)]