From 520bc2dc3b2ac58101cad1f37a42af73a0d488c8 Mon Sep 17 00:00:00 2001
From: xeon <xeon@xeondev.com>
Date: Fri, 14 Mar 2025 23:28:27 +0300
Subject: [PATCH] Implement Beginner Procedure

---
 Cargo.lock                                    |   1 +
 crates/game-server/src/logic/avatar_util.rs   |   7 -
 crates/game-server/src/logic/mod.rs           |   1 +
 crates/game-server/src/logic/player/mod.rs    |  56 +-
 .../src/logic/player/player_util.rs           |   7 +-
 crates/game-server/src/logic/scene/mod.rs     |  22 +
 .../game-server/src/session/message/player.rs |  41 +-
 .../game-server/src/session/message/scene.rs  | 120 +++-
 .../game-server/src/session/message/system.rs |  12 +
 .../src/session/message/workbench.rs          |   7 +
 crates/game-server/src/session/mod.rs         |  27 +-
 .../entity/src/player_basic_info.rs           |   1 +
 crates/trigger-fileconfig/fbs/tables.fbs      |  13 +
 .../gen_flatbuffers/tables_generated.rs       | 279 ++++++++++
 crates/trigger-fileconfig/src/lib.rs          |   1 +
 crates/trigger-logic/Cargo.toml               |   2 +
 crates/trigger-logic/src/lib.rs               |   1 +
 crates/trigger-logic/src/scene.rs             |   6 +
 crates/trigger-logic/src/template_ext.rs      |  42 ++
 crates/trigger-protobuf/out/_.rs              | 156 ++++++
 crates/trigger-protobuf/out/protocol_map.rs   | 520 ++++++++++++++++++
 crates/trigger-protocol/src/lib.rs            |  94 ++++
 22 files changed, 1392 insertions(+), 24 deletions(-)
 create mode 100644 crates/game-server/src/logic/scene/mod.rs
 create mode 100644 crates/trigger-logic/src/template_ext.rs

diff --git a/Cargo.lock b/Cargo.lock
index 7c5d40e..c1d30fd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3750,6 +3750,7 @@ version = "0.0.1"
 dependencies = [
  "num_enum",
  "prost",
+ "trigger-fileconfig",
 ]
 
 [[package]]
diff --git a/crates/game-server/src/logic/avatar_util.rs b/crates/game-server/src/logic/avatar_util.rs
index df59a77..fdae2bd 100644
--- a/crates/game-server/src/logic/avatar_util.rs
+++ b/crates/game-server/src/logic/avatar_util.rs
@@ -1,10 +1,3 @@
-pub const MALE_AVATAR_ID: u32 = 2011;
-pub const FEMALE_AVATAR_ID: u32 = 2021;
-
-pub fn is_player_avatar(id: u32) -> bool {
-    id == MALE_AVATAR_ID || id == FEMALE_AVATAR_ID
-}
-
 pub fn is_valid_talent_switch(v: &[bool]) -> bool {
     v.len() == 6
         && v[0..3]
diff --git a/crates/game-server/src/logic/mod.rs b/crates/game-server/src/logic/mod.rs
index bd37e43..e9efa41 100644
--- a/crates/game-server/src/logic/mod.rs
+++ b/crates/game-server/src/logic/mod.rs
@@ -4,6 +4,7 @@ pub mod dungeon_util;
 pub mod equip_util;
 pub mod gm_util;
 mod player;
+pub mod scene;
 pub mod scene_util;
 
 pub use player::NapPlayer;
diff --git a/crates/game-server/src/logic/player/mod.rs b/crates/game-server/src/logic/player/mod.rs
index 070145e..3e49d17 100644
--- a/crates/game-server/src/logic/player/mod.rs
+++ b/crates/game-server/src/logic/player/mod.rs
@@ -8,7 +8,7 @@ use role::RoleModel;
 use scene::SceneModel;
 use trigger_database::{entity::*, prelude::*, DatabaseConnection};
 use trigger_fileconfig::NapFileCfg;
-use trigger_logic::scene::ESceneType;
+use trigger_logic::{scene::ESceneType, template_ext::TemplateExt};
 use trigger_protocol::PlayerInfo;
 use trigger_sv::message::GameStateData;
 use yorozuya::YorozuyaModel;
@@ -62,11 +62,8 @@ impl NapPlayer {
             player_uid,
         };
 
-        let Some((player_basic_info, is_new_player)) =
-            player_util::load_player_basic_info(database, player_uid, create_if_not_exists).await
-        else {
-            return None;
-        };
+        let (player_basic_info, is_new_player) =
+            player_util::load_player_basic_info(database, player_uid, create_if_not_exists).await?;
 
         let role_model = RoleModel::init(context.clone()).await;
         let item_model = ItemModel::init(context.clone()).await;
@@ -95,6 +92,28 @@ impl NapPlayer {
         })
     }
 
+    pub fn beginner_procedure_id(&self) -> Option<i32> {
+        (self.player_basic_info.beginner_procedure_id != -1)
+            .then_some(self.player_basic_info.beginner_procedure_id)
+    }
+
+    pub async fn advance_beginner_procedure(&mut self, id: i32) {
+        let active_model = player_basic_info::ActiveModel {
+            beginner_procedure_id: Set(self
+                .context
+                .filecfg
+                .is_last_procedure(id)
+                .then_some(-1)
+                .unwrap_or(id)),
+            ..self.player_basic_info.clone().into()
+        };
+
+        self.player_basic_info = active_model
+            .update(self.context.database)
+            .await
+            .expect("player_basic_info::update failed");
+    }
+
     pub fn build_state_reentrant_data(&self, scene: &scene_info::Model) -> Option<GameStateData> {
         match ESceneType::try_from(scene.scene_type).unwrap() {
             ESceneType::Hall => Some(GameStateData::Hall {
@@ -106,6 +125,31 @@ impl NapPlayer {
         }
     }
 
+    pub async fn select_role(&mut self, avatar_id: u32) {
+        let mut active_model: player_basic_info::ActiveModel =
+            self.player_basic_info.clone().into();
+
+        active_model.set(
+            player_basic_info::Column::AvatarId,
+            (avatar_id as i32).into(),
+        );
+
+        active_model.set(
+            player_basic_info::Column::PlayerAvatarId,
+            (avatar_id as i32).into(),
+        );
+
+        active_model.set(
+            player_basic_info::Column::ControlAvatarId,
+            (avatar_id as i32).into(),
+        );
+
+        self.player_basic_info = active_model
+            .update(self.context.database)
+            .await
+            .expect("player_basic_info::update failed");
+    }
+
     pub async fn set_control_avatars(&mut self, player_avatar_id: u32, control_avatar_id: u32) {
         let mut active_model: player_basic_info::ActiveModel =
             self.player_basic_info.clone().into();
diff --git a/crates/game-server/src/logic/player/player_util.rs b/crates/game-server/src/logic/player/player_util.rs
index 13e85ab..f7179f0 100644
--- a/crates/game-server/src/logic/player/player_util.rs
+++ b/crates/game-server/src/logic/player/player_util.rs
@@ -32,9 +32,10 @@ fn create_default_player_basic_info(player_uid: i32) -> player_basic_info::Activ
         nick_name: String::from("ReversedRooms"),
         level: 60,
         exp: 0,
-        avatar_id: 2021,
-        player_avatar_id: 2021,
-        control_avatar_id: 1361,
+        avatar_id: 0,
+        player_avatar_id: 0,
+        control_avatar_id: 0,
+        beginner_procedure_id: 0,
     }
     .into()
 }
diff --git a/crates/game-server/src/logic/scene/mod.rs b/crates/game-server/src/logic/scene/mod.rs
new file mode 100644
index 0000000..1e6188f
--- /dev/null
+++ b/crates/game-server/src/logic/scene/mod.rs
@@ -0,0 +1,22 @@
+use trigger_logic::scene::ESceneType;
+
+#[derive(Debug)]
+pub enum ServerlessStateData {
+    FreshScene { procedure_id: i32 },
+}
+
+impl ServerlessStateData {
+    pub fn protocol_scene_data(&self) -> trigger_protocol::SceneData {
+        use trigger_protocol::*;
+
+        match self {
+            Self::FreshScene { procedure_id } => SceneData {
+                scene_type: ESceneType::Fresh.into(),
+                fresh_scene_info: Some(FreshSceneInfo {
+                    last_procedure_id: *procedure_id as u32,
+                }),
+                ..Default::default()
+            },
+        }
+    }
+}
diff --git a/crates/game-server/src/session/message/player.rs b/crates/game-server/src/session/message/player.rs
index 95d07bd..2fd503c 100644
--- a/crates/game-server/src/session/message/player.rs
+++ b/crates/game-server/src/session/message/player.rs
@@ -4,10 +4,9 @@ use trigger_codegen::handlers;
 #[handlers]
 mod player_module {
     use tracing::debug;
+    use trigger_logic::template_ext::TemplateExt;
     use trigger_sv::{net::ServerType, time_util};
 
-    use crate::logic::avatar_util;
-
     pub async fn on_get_player_info(
         context: &mut MessageContext<'_, '_>,
         _request: GetPlayerInfoCsReq,
@@ -39,6 +38,34 @@ mod player_module {
         }
     }
 
+    pub async fn on_select_role(
+        context: &mut MessageContext<'_, '_>,
+        request: SelectRoleCsReq,
+    ) -> SelectRoleScRsp {
+        if let Some(procedure_id) = context.player.beginner_procedure_id() {
+            if context
+                .state
+                .filecfg
+                .procedure_allows_select_role(procedure_id + 1)
+                && context
+                    .state
+                    .filecfg
+                    .is_player_avatar(request.avatar_id as i32)
+            {
+                context.player.select_role(request.avatar_id).await;
+
+                context.add_notify(PlayerSyncScNotify {
+                    player_info: Some(context.player.get_protocol_player_info()),
+                    ..Default::default()
+                });
+
+                return SelectRoleScRsp { retcode: 0 };
+            }
+        }
+
+        SelectRoleScRsp { retcode: 1 }
+    }
+
     pub async fn on_get_authkey(
         context: &mut MessageContext<'_, '_>,
         request: GetAuthkeyCsReq,
@@ -69,8 +96,14 @@ mod player_module {
         context: &mut MessageContext<'_, '_>,
         request: SwitchRoleCsReq,
     ) -> SwitchRoleScRsp {
-        if avatar_util::is_player_avatar(request.player_avatar_id)
-            && (avatar_util::is_player_avatar(request.control_avatar_id)
+        if context
+            .state
+            .filecfg
+            .is_player_avatar(request.player_avatar_id as i32)
+            && (context
+                .state
+                .filecfg
+                .is_player_avatar(request.control_avatar_id as i32)
                 || context
                     .player
                     .role_model
diff --git a/crates/game-server/src/session/message/scene.rs b/crates/game-server/src/session/message/scene.rs
index 166f7d3..26c7d1c 100644
--- a/crates/game-server/src/session/message/scene.rs
+++ b/crates/game-server/src/session/message/scene.rs
@@ -5,11 +5,28 @@ use trigger_codegen::handlers;
 mod scene_module {
     use tracing::debug;
     use trigger_logic::scene::{ELocalPlayType, ESceneType};
-    use trigger_sv::message::GameStateData;
+    use trigger_sv::{
+        message::{AvailableServerProtocolMessage, GameStateData},
+        net::ServerType,
+    };
 
-    use crate::logic::{dungeon_util, scene_util};
+    use crate::logic::{dungeon_util, scene::ServerlessStateData, scene_util};
 
     pub async fn on_enter_world(context: &mut MessageContext<'_, '_>, _request: EnterWorldCsReq) {
+        if let Some(procedure_id) = context.player.beginner_procedure_id() {
+            debug!("entering beginner procedure, id: {procedure_id}");
+
+            context
+                .session
+                .load_serverless_state(
+                    ServerlessStateData::FreshScene { procedure_id },
+                    context.request_id,
+                    EnterWorldScRsp::default(),
+                )
+                .await;
+            return;
+        }
+
         let scene_model = &mut context.player.scene_model;
 
         let scene_to_enter = match scene_model.get_current_scene().await {
@@ -24,7 +41,6 @@ mod scene_module {
         };
 
         let scene_to_enter = if scene_to_enter.is_none() {
-            // TODO: first scene to be created should be the 'Fresh' scene (beginner procedure)
             debug!(
                 "player with uid {} has no scene to enter, default hall scene will be created",
                 context.session.player_uid
@@ -149,6 +165,104 @@ mod scene_module {
             .await;
     }
 
+    pub async fn on_advance_beginner_procedure(
+        context: &mut MessageContext<'_, '_>,
+        request: AdvanceBeginnerProcedureCsReq,
+    ) {
+        let rsp = if let Some(procedure_id) = context.player.beginner_procedure_id() {
+            if request.procedure_id == procedure_id + 1 {
+                context
+                    .player
+                    .advance_beginner_procedure(request.procedure_id)
+                    .await;
+
+                let rsp = AdvanceBeginnerProcedureScRsp {
+                    retcode: 0,
+                    next_procedure_id: request.procedure_id,
+                };
+
+                if context.player.beginner_procedure_id().is_none() {
+                    // Beginner procedure finished, enter the hall scene now
+                    let scene_model = &mut context.player.scene_model;
+                    let scene = scene_model.create_scene_info(ESceneType::Hall).await;
+                    scene_model.set_default_scene(&scene).await;
+
+                    context
+                        .session
+                        .change_game_state(
+                            context.request_id,
+                            rsp,
+                            context.player.build_state_reentrant_data(&scene).unwrap(),
+                            &scene,
+                            context.player,
+                            false,
+                        )
+                        .await;
+
+                    None
+                } else {
+                    Some(rsp)
+                }
+            } else {
+                debug!(
+                    "invalid procedure transition (from: {}, to: {})",
+                    procedure_id, request.procedure_id
+                );
+
+                Some(AdvanceBeginnerProcedureScRsp {
+                    retcode: 1,
+                    ..Default::default()
+                })
+            }
+        } else {
+            Some(AdvanceBeginnerProcedureScRsp {
+                retcode: 1,
+                ..Default::default()
+            })
+        };
+
+        if let Some(rsp) = rsp {
+            context
+                .session
+                .network_mgr
+                .send_to(
+                    ServerType::GateServer,
+                    0,
+                    AvailableServerProtocolMessage {
+                        session_id: context.session.id,
+                        ack_request_id: context.request_id,
+                        notifies: Vec::new(),
+                        response: Some(rsp.into()),
+                    },
+                )
+                .await;
+        }
+    }
+
+    pub async fn on_beginnerbattle_begin(
+        _context: &mut MessageContext<'_, '_>,
+        request: BeginnerbattleBeginCsReq,
+    ) -> BeginnerbattleBeginScRsp {
+        BeginnerbattleBeginScRsp {
+            retcode: 0,
+            battle_uid: request.battle_id as i64,
+        }
+    }
+
+    pub async fn on_beginnerbattle_rebegin(
+        _context: &mut MessageContext<'_, '_>,
+        _request: BeginnerbattleRebeginCsReq,
+    ) -> BeginnerbattleRebeginScRsp {
+        BeginnerbattleRebeginScRsp { retcode: 0 }
+    }
+
+    pub async fn on_beginnerbattle_end(
+        _context: &mut MessageContext<'_, '_>,
+        _request: BeginnerbattleEndCsReq,
+    ) -> BeginnerbattleEndScRsp {
+        BeginnerbattleEndScRsp { retcode: 0 }
+    }
+
     pub async fn on_active_hollow_check_point(
         _context: &mut MessageContext<'_, '_>,
         request: ActiveHollowCheckPointCsReq,
diff --git a/crates/game-server/src/session/message/system.rs b/crates/game-server/src/session/message/system.rs
index 4edd274..4e53cf2 100644
--- a/crates/game-server/src/session/message/system.rs
+++ b/crates/game-server/src/session/message/system.rs
@@ -185,6 +185,18 @@ mod client_systems_module {
         }
     }
 
+    pub async fn on_end_newbie(
+        _context: &mut MessageContext<'_, '_>,
+        request: EndNewbieCsReq,
+    ) -> EndNewbieScRsp {
+        debug!("EndNewbie({})", request.group_id);
+
+        EndNewbieScRsp {
+            retcode: 0,
+            group_id: 0,
+        }
+    }
+
     pub async fn on_get_trashbin_hermit_data(
         _context: &mut MessageContext<'_, '_>,
         _request: GetTrashbinHermitDataCsReq,
diff --git a/crates/game-server/src/session/message/workbench.rs b/crates/game-server/src/session/message/workbench.rs
index 3fd8bf5..b91930b 100644
--- a/crates/game-server/src/session/message/workbench.rs
+++ b/crates/game-server/src/session/message/workbench.rs
@@ -35,4 +35,11 @@ mod workbench_module {
             abyss_reward_data: Some(AbyssRewardData::default()),
         }
     }
+
+    pub async fn on_unlock_clue_item(
+        _context: &mut MessageContext<'_, '_>,
+        _request: UnlockClueItemCsReq,
+    ) -> UnlockClueItemScRsp {
+        UnlockClueItemScRsp { retcode: 0 }
+    }
 }
diff --git a/crates/game-server/src/session/mod.rs b/crates/game-server/src/session/mod.rs
index d1bdc59..e016575 100644
--- a/crates/game-server/src/session/mod.rs
+++ b/crates/game-server/src/session/mod.rs
@@ -15,7 +15,7 @@ use trigger_sv::{
     net::{ServerNetworkManager, ServerType},
 };
 
-use crate::logic::{scene_util, NapPlayer};
+use crate::logic::{scene::ServerlessStateData, scene_util, NapPlayer};
 
 pub mod message;
 
@@ -50,6 +50,31 @@ impl GameSession {
         }
     }
 
+    pub async fn load_serverless_state(
+        &self,
+        state_data: ServerlessStateData,
+        ack_request_id: u32,
+        response: impl Into<ProtocolUnit>,
+    ) {
+        let enter_scene_notify = trigger_protocol::EnterSceneScNotify {
+            scene: Some(state_data.protocol_scene_data()),
+            dungeon: None,
+        };
+
+        self.network_mgr
+            .send_to(
+                ServerType::GateServer,
+                0,
+                AvailableServerProtocolMessage {
+                    session_id: self.id,
+                    ack_request_id,
+                    notifies: vec![enter_scene_notify.into()],
+                    response: Some(response.into()),
+                },
+            )
+            .await;
+    }
+
     pub async fn change_game_state(
         &self,
         ack_request_id: u32,
diff --git a/crates/trigger-database/entity/src/player_basic_info.rs b/crates/trigger-database/entity/src/player_basic_info.rs
index 5537285..84cf282 100644
--- a/crates/trigger-database/entity/src/player_basic_info.rs
+++ b/crates/trigger-database/entity/src/player_basic_info.rs
@@ -11,6 +11,7 @@ pub struct Model {
     pub avatar_id: i32,
     pub player_avatar_id: i32,
     pub control_avatar_id: i32,
+    pub beginner_procedure_id: i32,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
diff --git a/crates/trigger-fileconfig/fbs/tables.fbs b/crates/trigger-fileconfig/fbs/tables.fbs
index 7d667b6..23af39c 100644
--- a/crates/trigger-fileconfig/fbs/tables.fbs
+++ b/crates/trigger-fileconfig/fbs/tables.fbs
@@ -380,6 +380,15 @@ table ConditionConfigTemplate {
 	type: int;
 }
 
+table ProcedureConfigTemplate {
+	procedure_id: int;
+	procedure_type: int;
+	content_id: string;
+	jump_tos: [int];
+	procedure_banks: [string];
+	procedure_event: string;
+}
+
 table AvatarBaseTemplateTb {
 	data: [AvatarBaseTemplate];
 }
@@ -451,3 +460,7 @@ table TeleportConfigTemplateTb {
 table ConditionConfigTemplateTb {
 	data: [ConditionConfigTemplate];
 }
+
+table ProcedureConfigTemplateTb {
+	data: [ProcedureConfigTemplate];
+}
diff --git a/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs b/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs
index 43c5f57..f81514b 100644
--- a/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs
+++ b/crates/trigger-fileconfig/gen_flatbuffers/tables_generated.rs
@@ -7111,6 +7111,188 @@ impl core::fmt::Debug for ConditionConfigTemplate<'_> {
       ds.finish()
   }
 }
+pub enum ProcedureConfigTemplateOffset {}
+#[derive(Copy, Clone, PartialEq)]
+
+pub struct ProcedureConfigTemplate<'a> {
+  pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for ProcedureConfigTemplate<'a> {
+  type Inner = ProcedureConfigTemplate<'a>;
+  #[inline]
+  unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+    Self { _tab: flatbuffers::Table::new(buf, loc) }
+  }
+}
+
+impl<'a> ProcedureConfigTemplate<'a> {
+  pub const VT_PROCEDURE_ID: flatbuffers::VOffsetT = 4;
+  pub const VT_PROCEDURE_TYPE: flatbuffers::VOffsetT = 6;
+  pub const VT_CONTENT_ID: flatbuffers::VOffsetT = 8;
+  pub const VT_JUMP_TOS: flatbuffers::VOffsetT = 10;
+  pub const VT_PROCEDURE_BANKS: flatbuffers::VOffsetT = 12;
+  pub const VT_PROCEDURE_EVENT: flatbuffers::VOffsetT = 14;
+
+  #[inline]
+  pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+    ProcedureConfigTemplate { _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 ProcedureConfigTemplateArgs<'args>
+  ) -> flatbuffers::WIPOffset<ProcedureConfigTemplate<'bldr>> {
+    let mut builder = ProcedureConfigTemplateBuilder::new(_fbb);
+    if let Some(x) = args.procedure_event { builder.add_procedure_event(x); }
+    if let Some(x) = args.procedure_banks { builder.add_procedure_banks(x); }
+    if let Some(x) = args.jump_tos { builder.add_jump_tos(x); }
+    if let Some(x) = args.content_id { builder.add_content_id(x); }
+    builder.add_procedure_type(args.procedure_type);
+    builder.add_procedure_id(args.procedure_id);
+    builder.finish()
+  }
+
+
+  #[inline]
+  pub fn procedure_id(&self) -> i32 {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<i32>(ProcedureConfigTemplate::VT_PROCEDURE_ID, Some(0)).unwrap()}
+  }
+  #[inline]
+  pub fn procedure_type(&self) -> i32 {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<i32>(ProcedureConfigTemplate::VT_PROCEDURE_TYPE, Some(0)).unwrap()}
+  }
+  #[inline]
+  pub fn content_id(&self) -> Option<&'a str> {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(ProcedureConfigTemplate::VT_CONTENT_ID, None)}
+  }
+  #[inline]
+  pub fn jump_tos(&self) -> Option<flatbuffers::Vector<'a, i32>> {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, i32>>>(ProcedureConfigTemplate::VT_JUMP_TOS, None)}
+  }
+  #[inline]
+  pub fn procedure_banks(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>> {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>>>(ProcedureConfigTemplate::VT_PROCEDURE_BANKS, None)}
+  }
+  #[inline]
+  pub fn procedure_event(&self) -> Option<&'a str> {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(ProcedureConfigTemplate::VT_PROCEDURE_EVENT, None)}
+  }
+}
+
+impl flatbuffers::Verifiable for ProcedureConfigTemplate<'_> {
+  #[inline]
+  fn run_verifier(
+    v: &mut flatbuffers::Verifier, pos: usize
+  ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+    use self::flatbuffers::Verifiable;
+    v.visit_table(pos)?
+     .visit_field::<i32>("procedure_id", Self::VT_PROCEDURE_ID, false)?
+     .visit_field::<i32>("procedure_type", Self::VT_PROCEDURE_TYPE, false)?
+     .visit_field::<flatbuffers::ForwardsUOffset<&str>>("content_id", Self::VT_CONTENT_ID, false)?
+     .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, i32>>>("jump_tos", Self::VT_JUMP_TOS, false)?
+     .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<&'_ str>>>>("procedure_banks", Self::VT_PROCEDURE_BANKS, false)?
+     .visit_field::<flatbuffers::ForwardsUOffset<&str>>("procedure_event", Self::VT_PROCEDURE_EVENT, false)?
+     .finish();
+    Ok(())
+  }
+}
+pub struct ProcedureConfigTemplateArgs<'a> {
+    pub procedure_id: i32,
+    pub procedure_type: i32,
+    pub content_id: Option<flatbuffers::WIPOffset<&'a str>>,
+    pub jump_tos: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, i32>>>,
+    pub procedure_banks: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>>>,
+    pub procedure_event: Option<flatbuffers::WIPOffset<&'a str>>,
+}
+impl<'a> Default for ProcedureConfigTemplateArgs<'a> {
+  #[inline]
+  fn default() -> Self {
+    ProcedureConfigTemplateArgs {
+      procedure_id: 0,
+      procedure_type: 0,
+      content_id: None,
+      jump_tos: None,
+      procedure_banks: None,
+      procedure_event: None,
+    }
+  }
+}
+
+pub struct ProcedureConfigTemplateBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> {
+  fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>,
+  start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> ProcedureConfigTemplateBuilder<'a, 'b, A> {
+  #[inline]
+  pub fn add_procedure_id(&mut self, procedure_id: i32) {
+    self.fbb_.push_slot::<i32>(ProcedureConfigTemplate::VT_PROCEDURE_ID, procedure_id, 0);
+  }
+  #[inline]
+  pub fn add_procedure_type(&mut self, procedure_type: i32) {
+    self.fbb_.push_slot::<i32>(ProcedureConfigTemplate::VT_PROCEDURE_TYPE, procedure_type, 0);
+  }
+  #[inline]
+  pub fn add_content_id(&mut self, content_id: flatbuffers::WIPOffset<&'b  str>) {
+    self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(ProcedureConfigTemplate::VT_CONTENT_ID, content_id);
+  }
+  #[inline]
+  pub fn add_jump_tos(&mut self, jump_tos: flatbuffers::WIPOffset<flatbuffers::Vector<'b , i32>>) {
+    self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(ProcedureConfigTemplate::VT_JUMP_TOS, jump_tos);
+  }
+  #[inline]
+  pub fn add_procedure_banks(&mut self, procedure_banks: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<&'b  str>>>) {
+    self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(ProcedureConfigTemplate::VT_PROCEDURE_BANKS, procedure_banks);
+  }
+  #[inline]
+  pub fn add_procedure_event(&mut self, procedure_event: flatbuffers::WIPOffset<&'b  str>) {
+    self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(ProcedureConfigTemplate::VT_PROCEDURE_EVENT, procedure_event);
+  }
+  #[inline]
+  pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> ProcedureConfigTemplateBuilder<'a, 'b, A> {
+    let start = _fbb.start_table();
+    ProcedureConfigTemplateBuilder {
+      fbb_: _fbb,
+      start_: start,
+    }
+  }
+  #[inline]
+  pub fn finish(self) -> flatbuffers::WIPOffset<ProcedureConfigTemplate<'a>> {
+    let o = self.fbb_.end_table(self.start_);
+    flatbuffers::WIPOffset::new(o.value())
+  }
+}
+
+impl core::fmt::Debug for ProcedureConfigTemplate<'_> {
+  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+    let mut ds = f.debug_struct("ProcedureConfigTemplate");
+      ds.field("procedure_id", &self.procedure_id());
+      ds.field("procedure_type", &self.procedure_type());
+      ds.field("content_id", &self.content_id());
+      ds.field("jump_tos", &self.jump_tos());
+      ds.field("procedure_banks", &self.procedure_banks());
+      ds.field("procedure_event", &self.procedure_event());
+      ds.finish()
+  }
+}
 pub enum AvatarBaseTemplateTbOffset {}
 #[derive(Copy, Clone, PartialEq)]
 
@@ -8857,3 +9039,100 @@ impl core::fmt::Debug for ConditionConfigTemplateTb<'_> {
       ds.finish()
   }
 }
+pub enum ProcedureConfigTemplateTbOffset {}
+#[derive(Copy, Clone, PartialEq)]
+
+pub struct ProcedureConfigTemplateTb<'a> {
+  pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for ProcedureConfigTemplateTb<'a> {
+  type Inner = ProcedureConfigTemplateTb<'a>;
+  #[inline]
+  unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+    Self { _tab: flatbuffers::Table::new(buf, loc) }
+  }
+}
+
+impl<'a> ProcedureConfigTemplateTb<'a> {
+  pub const VT_DATA: flatbuffers::VOffsetT = 4;
+
+  #[inline]
+  pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+    ProcedureConfigTemplateTb { _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 ProcedureConfigTemplateTbArgs<'args>
+  ) -> flatbuffers::WIPOffset<ProcedureConfigTemplateTb<'bldr>> {
+    let mut builder = ProcedureConfigTemplateTbBuilder::new(_fbb);
+    if let Some(x) = args.data { builder.add_data(x); }
+    builder.finish()
+  }
+
+
+  #[inline]
+  pub fn data(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<ProcedureConfigTemplate<'a>>>> {
+    // Safety:
+    // Created from valid Table for this object
+    // which contains a valid value in this slot
+    unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<ProcedureConfigTemplate>>>>(ProcedureConfigTemplateTb::VT_DATA, None)}
+  }
+}
+
+impl flatbuffers::Verifiable for ProcedureConfigTemplateTb<'_> {
+  #[inline]
+  fn run_verifier(
+    v: &mut flatbuffers::Verifier, pos: usize
+  ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+    use self::flatbuffers::Verifiable;
+    v.visit_table(pos)?
+     .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<ProcedureConfigTemplate>>>>("data", Self::VT_DATA, false)?
+     .finish();
+    Ok(())
+  }
+}
+pub struct ProcedureConfigTemplateTbArgs<'a> {
+    pub data: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<ProcedureConfigTemplate<'a>>>>>,
+}
+impl<'a> Default for ProcedureConfigTemplateTbArgs<'a> {
+  #[inline]
+  fn default() -> Self {
+    ProcedureConfigTemplateTbArgs {
+      data: None,
+    }
+  }
+}
+
+pub struct ProcedureConfigTemplateTbBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> {
+  fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>,
+  start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> ProcedureConfigTemplateTbBuilder<'a, 'b, A> {
+  #[inline]
+  pub fn add_data(&mut self, data: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<ProcedureConfigTemplate<'b >>>>) {
+    self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(ProcedureConfigTemplateTb::VT_DATA, data);
+  }
+  #[inline]
+  pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> ProcedureConfigTemplateTbBuilder<'a, 'b, A> {
+    let start = _fbb.start_table();
+    ProcedureConfigTemplateTbBuilder {
+      fbb_: _fbb,
+      start_: start,
+    }
+  }
+  #[inline]
+  pub fn finish(self) -> flatbuffers::WIPOffset<ProcedureConfigTemplateTb<'a>> {
+    let o = self.fbb_.end_table(self.start_);
+    flatbuffers::WIPOffset::new(o.value())
+  }
+}
+
+impl core::fmt::Debug for ProcedureConfigTemplateTb<'_> {
+  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+    let mut ds = f.debug_struct("ProcedureConfigTemplateTb");
+      ds.field("data", &self.data());
+      ds.finish()
+  }
+}
diff --git a/crates/trigger-fileconfig/src/lib.rs b/crates/trigger-fileconfig/src/lib.rs
index 50be6ac..042b276 100644
--- a/crates/trigger-fileconfig/src/lib.rs
+++ b/crates/trigger-fileconfig/src/lib.rs
@@ -45,6 +45,7 @@ file_cfg! {
     WeaponTemplateTb;
     EquipmentTemplateTb;
     EquipmentSuitTemplateTb;
+    ProcedureConfigTemplateTb;
     UnlockConfigTemplateTb;
     PostGirlConfigTemplateTb;
     ArchiveFileQuestTemplateTb;
diff --git a/crates/trigger-logic/Cargo.toml b/crates/trigger-logic/Cargo.toml
index 051224e..ddcabe1 100644
--- a/crates/trigger-logic/Cargo.toml
+++ b/crates/trigger-logic/Cargo.toml
@@ -6,3 +6,5 @@ version.workspace = true
 [dependencies]
 num_enum.workspace = true
 prost.workspace = true
+
+trigger-fileconfig.workspace = true
diff --git a/crates/trigger-logic/src/lib.rs b/crates/trigger-logic/src/lib.rs
index ce07c15..982a71e 100644
--- a/crates/trigger-logic/src/lib.rs
+++ b/crates/trigger-logic/src/lib.rs
@@ -3,3 +3,4 @@ pub mod item;
 pub mod quest;
 pub mod scene;
 pub mod skill;
+pub mod template_ext;
diff --git a/crates/trigger-logic/src/scene.rs b/crates/trigger-logic/src/scene.rs
index 51d7312..596b8fb 100644
--- a/crates/trigger-logic/src/scene.rs
+++ b/crates/trigger-logic/src/scene.rs
@@ -107,3 +107,9 @@ impl From<Vec<f64>> for Vector3f {
         }
     }
 }
+
+impl From<ESceneType> for u32 {
+    fn from(value: ESceneType) -> Self {
+        i16::from(value) as u32
+    }
+}
diff --git a/crates/trigger-logic/src/template_ext.rs b/crates/trigger-logic/src/template_ext.rs
new file mode 100644
index 0000000..98568bb
--- /dev/null
+++ b/crates/trigger-logic/src/template_ext.rs
@@ -0,0 +1,42 @@
+use trigger_fileconfig::NapFileCfg;
+
+pub trait TemplateExt {
+    fn is_player_avatar(&self, avatar_id: i32) -> bool;
+    fn procedure_allows_select_role(&self, procedure_id: i32) -> bool;
+    fn is_last_procedure(&self, procedure_id: i32) -> bool;
+}
+
+impl TemplateExt for NapFileCfg {
+    fn is_player_avatar(&self, avatar_id: i32) -> bool {
+        self.avatar_base_template_tb()
+            .data()
+            .unwrap()
+            .iter()
+            .find_map(|tmpl| (tmpl.id() == avatar_id && tmpl.camp() == 0).then_some(true))
+            .unwrap_or(false)
+    }
+
+    fn procedure_allows_select_role(&self, procedure_id: i32) -> bool {
+        self.procedure_config_template_tb()
+            .data()
+            .unwrap()
+            .iter()
+            .find_map(|tmpl| {
+                (tmpl.procedure_id() == procedure_id && tmpl.procedure_type() == 4).then_some(true)
+            })
+            .unwrap_or(false)
+    }
+
+    fn is_last_procedure(&self, procedure_id: i32) -> bool {
+        // faggots nuked JumpTos from client data btw!
+
+        self.procedure_config_template_tb()
+            .data()
+            .unwrap()
+            .iter()
+            .max_by_key(|tmpl| tmpl.procedure_id())
+            .unwrap()
+            .procedure_id()
+            == procedure_id
+    }
+}
diff --git a/crates/trigger-protobuf/out/_.rs b/crates/trigger-protobuf/out/_.rs
index 1b57c68..a163dc7 100644
--- a/crates/trigger-protobuf/out/_.rs
+++ b/crates/trigger-protobuf/out/_.rs
@@ -10,6 +10,18 @@ pub struct GetRewardBuffDataScRsp {
     pub retcode: i32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(7670)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct BeginnerbattleBeginScRsp {
+    #[xor(8649)]
+    #[prost(int64, tag = "14")]
+    pub battle_uid: i64,
+    #[xor(10326)]
+    #[prost(int32, tag = "3")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
 pub struct PlayerInfo {
@@ -85,6 +97,15 @@ pub struct Equip {
     pub exp: u32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(3935)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct SelectRoleCsReq {
+    #[xor(9750)]
+    #[prost(uint32, tag = "7")]
+    pub avatar_id: u32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(1850)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
@@ -362,6 +383,15 @@ pub struct DressEquipmentCsReq {
     pub equip_uid: u32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(6113)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct BeginnerbattleBeginCsReq {
+    #[xor(12379)]
+    #[prost(int32, tag = "15")]
+    pub battle_id: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(6803)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
@@ -398,6 +428,27 @@ pub struct GetActivityDataScRsp {
     pub retcode: i32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(1970)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct BeginnerbattleEndCsReq {
+    #[xor(322)]
+    #[prost(int64, tag = "4")]
+    pub battle_uid: i64,
+    #[xor(1154)]
+    #[prost(int32, tag = "11")]
+    pub battle_id: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(5251)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct UnlockClueItemScRsp {
+    #[xor(379)]
+    #[prost(int32, tag = "7")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(8370)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
@@ -509,6 +560,15 @@ pub struct TipsSync {
     pub fairy_groups: ::std::collections::HashMap<i32, i32>,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(842)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct BeginnerbattleEndScRsp {
+    #[xor(12999)]
+    #[prost(int32, tag = "11")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
 pub struct Transform {
@@ -549,6 +609,15 @@ pub struct EnterSectionCsReq {
     pub owner_type: i32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(9995)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct BeginnerbattleRebeginScRsp {
+    #[xor(9333)]
+    #[prost(int32, tag = "7")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
 pub struct RallySceneInfo {
@@ -660,6 +729,18 @@ pub struct AbyssGetDataScRsp {
     pub abyss_group_list: ::prost::alloc::vec::Vec<AbyssGroup>,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(480)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct BeginnerbattleRebeginCsReq {
+    #[xor(3447)]
+    #[prost(int64, tag = "9")]
+    pub battle_uid: i64,
+    #[xor(4358)]
+    #[prost(int32, tag = "15")]
+    pub battle_id: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
 pub struct VhsGuestInfo {
@@ -683,6 +764,18 @@ pub struct GetExplorationDataCsReq {}
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
 pub struct GetResourceDataCsReq {}
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(3734)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AdvanceBeginnerProcedureCsReq {
+    #[xor(4241)]
+    #[prost(int32, tag = "5")]
+    pub params: i32,
+    #[xor(7267)]
+    #[prost(int32, tag = "7")]
+    pub procedure_id: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(4813)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
@@ -726,6 +819,14 @@ pub struct StartHollowQuestScRsp {
 }
 #[derive(trigger_protobuf_derive::CmdID)]
 #[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct FreshSceneInfo {
+    #[xor(13677)]
+    #[prost(uint32, tag = "7")]
+    pub last_procedure_id: u32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
+#[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
 pub struct TipsInfo {
     #[prost(int32, repeated, tag = "12")]
@@ -752,6 +853,9 @@ pub struct SavePlayerSystemSettingCsReq {
     #[xor(6028)]
     #[prost(uint32, tag = "10")]
     pub r#type: u32,
+    #[xor(8376)]
+    #[prost(uint32, tag = "14")]
+    pub params: u32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(2418)]
@@ -1001,6 +1105,18 @@ pub struct WeaponDressCsReq {
     pub weapon_uid: u32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(8333)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct EndNewbieScRsp {
+    #[xor(7830)]
+    #[prost(uint32, tag = "9")]
+    pub group_id: u32,
+    #[xor(16016)]
+    #[prost(int32, tag = "2")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(8553)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
@@ -1029,6 +1145,14 @@ pub struct HollowInfo {
     pub hollow_quest_id: u32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(5937)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct UnlockClueItemCsReq {
+    #[prost(enumeration = "Lclkcaiolep", tag = "4")]
+    pub r#type: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(9350)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
@@ -1136,6 +1260,18 @@ pub struct ActiveHollowCheckPointCsReq {
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
 pub struct GetServerTimestampCsReq {}
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(9745)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct AdvanceBeginnerProcedureScRsp {
+    #[xor(9328)]
+    #[prost(int32, tag = "6")]
+    pub next_procedure_id: i32,
+    #[xor(5852)]
+    #[prost(int32, tag = "7")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(7723)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
@@ -1476,6 +1612,15 @@ pub struct VhsFlowBuffInfo {
     pub buff_source: i32,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(4652)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct SelectRoleScRsp {
+    #[xor(417)]
+    #[prost(int32, tag = "7")]
+    pub retcode: i32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[cmdid(6289)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
@@ -1983,6 +2128,15 @@ pub struct VhsStoreData {
     pub is_need_refresh: bool,
 }
 #[derive(trigger_protobuf_derive::CmdID)]
+#[cmdid(5983)]
+#[derive(trigger_protobuf_derive::XorFields)]
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct EndNewbieCsReq {
+    #[xor(413)]
+    #[prost(uint32, tag = "11")]
+    pub group_id: u32,
+}
+#[derive(trigger_protobuf_derive::CmdID)]
 #[derive(trigger_protobuf_derive::XorFields)]
 #[derive(Clone, PartialEq, ::prost::Message)]
 pub struct SystemSettings {
@@ -2055,6 +2209,8 @@ pub struct MusicPlayerItem {
 pub struct SceneData {
     #[prost(message, optional, tag = "11")]
     pub hall_scene_info: ::core::option::Option<HallSceneInfo>,
+    #[prost(message, optional, tag = "12")]
+    pub fresh_scene_info: ::core::option::Option<FreshSceneInfo>,
     #[xor(10113)]
     #[prost(uint32, tag = "6")]
     pub local_play_type: u32,
diff --git a/crates/trigger-protobuf/out/protocol_map.rs b/crates/trigger-protobuf/out/protocol_map.rs
index cd40281..5532243 100644
--- a/crates/trigger-protobuf/out/protocol_map.rs
+++ b/crates/trigger-protobuf/out/protocol_map.rs
@@ -11,6 +11,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        BeginnerbattleBeginScRsp::CMD_ID => {
+            let mut pb_message = BeginnerbattleBeginScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleBeginScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetBuddyDataCsReq::CMD_ID => {
             let mut pb_message = GetBuddyDataCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -27,6 +35,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        SelectRoleCsReq::CMD_ID => {
+            let mut pb_message = SelectRoleCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::SelectRoleCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         HollowDataRefreshCsReq::CMD_ID => {
             let mut pb_message = HollowDataRefreshCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -163,6 +179,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        BeginnerbattleBeginCsReq::CMD_ID => {
+            let mut pb_message = BeginnerbattleBeginCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleBeginCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetTipsDataScRsp::CMD_ID => {
             let mut pb_message = GetTipsDataScRsp::decode(pb)?;
             pb_message.xor_fields();
@@ -187,6 +211,22 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        BeginnerbattleEndCsReq::CMD_ID => {
+            let mut pb_message = BeginnerbattleEndCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleEndCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
+        UnlockClueItemScRsp::CMD_ID => {
+            let mut pb_message = UnlockClueItemScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::UnlockClueItemScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         PerformTriggerCsReq::CMD_ID => {
             let mut pb_message = PerformTriggerCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -243,6 +283,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        BeginnerbattleEndScRsp::CMD_ID => {
+            let mut pb_message = BeginnerbattleEndScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleEndScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         PerformJumpCsReq::CMD_ID => {
             let mut pb_message = PerformJumpCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -259,6 +307,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        BeginnerbattleRebeginScRsp::CMD_ID => {
+            let mut pb_message = BeginnerbattleRebeginScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleRebeginScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetPlayerInfoCsReq::CMD_ID => {
             let mut pb_message = GetPlayerInfoCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -331,6 +387,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        BeginnerbattleRebeginCsReq::CMD_ID => {
+            let mut pb_message = BeginnerbattleRebeginCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleRebeginCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetExplorationDataCsReq::CMD_ID => {
             let mut pb_message = GetExplorationDataCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -347,6 +411,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        AdvanceBeginnerProcedureCsReq::CMD_ID => {
+            let mut pb_message = AdvanceBeginnerProcedureCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::AdvanceBeginnerProcedureCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         AbyssGetDataCsReq::CMD_ID => {
             let mut pb_message = AbyssGetDataCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -547,6 +619,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        EndNewbieScRsp::CMD_ID => {
+            let mut pb_message = EndNewbieScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::EndNewbieScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetRamenDataCsReq::CMD_ID => {
             let mut pb_message = GetRamenDataCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -563,6 +643,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        UnlockClueItemCsReq::CMD_ID => {
+            let mut pb_message = UnlockClueItemCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::UnlockClueItemCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetAvatarDataCsReq::CMD_ID => {
             let mut pb_message = GetAvatarDataCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -635,6 +723,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        AdvanceBeginnerProcedureScRsp::CMD_ID => {
+            let mut pb_message = AdvanceBeginnerProcedureScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::AdvanceBeginnerProcedureScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         PerformEndCsReq::CMD_ID => {
             let mut pb_message = PerformEndCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -771,6 +867,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        SelectRoleScRsp::CMD_ID => {
+            let mut pb_message = SelectRoleScRsp::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::SelectRoleScRsp::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         GetUnlockDataCsReq::CMD_ID => {
             let mut pb_message = GetUnlockDataCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -1051,6 +1155,14 @@ pub fn pb_to_common_protocol_unit(
             );
             Ok(Some(common_protocol_message.into()))
         }
+        EndNewbieCsReq::CMD_ID => {
+            let mut pb_message = EndNewbieCsReq::decode(pb)?;
+            pb_message.xor_fields();
+            let common_protocol_message = ::trigger_protocol::EndNewbieCsReq::from(
+                pb_message,
+            );
+            Ok(Some(common_protocol_message.into()))
+        }
         LeaveCurSceneCsReq::CMD_ID => {
             let mut pb_message = LeaveCurSceneCsReq::decode(pb)?;
             pb_message.xor_fields();
@@ -1124,6 +1236,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((GetRewardBuffDataScRsp::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::BeginnerbattleBeginScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleBeginScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = BeginnerbattleBeginScRsp::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((BeginnerbattleBeginScRsp::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::GetBuddyDataCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::GetBuddyDataCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1140,6 +1260,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((BattleReportCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::SelectRoleCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::SelectRoleCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = SelectRoleCsReq::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((SelectRoleCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::HollowDataRefreshCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::HollowDataRefreshCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1282,6 +1410,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((DressEquipmentCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::BeginnerbattleBeginCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleBeginCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = BeginnerbattleBeginCsReq::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((BeginnerbattleBeginCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::GetTipsDataScRsp::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::GetTipsDataScRsp::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1306,6 +1442,22 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((GetActivityDataScRsp::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::BeginnerbattleEndCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleEndCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = BeginnerbattleEndCsReq::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((BeginnerbattleEndCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
+        ::trigger_protocol::UnlockClueItemScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::UnlockClueItemScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = UnlockClueItemScRsp::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((UnlockClueItemScRsp::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::PerformTriggerCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::PerformTriggerCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1364,6 +1516,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((GetBuddyDataScRsp::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::BeginnerbattleEndScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleEndScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = BeginnerbattleEndScRsp::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((BeginnerbattleEndScRsp::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::PerformJumpCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::PerformJumpCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1380,6 +1540,16 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((EnterSectionCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::BeginnerbattleRebeginScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleRebeginScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = BeginnerbattleRebeginScRsp::from(
+                common_protocol_message,
+            );
+            pb_message.xor_fields();
+            Ok(Some((BeginnerbattleRebeginScRsp::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),
@@ -1454,6 +1624,16 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((AbyssGetDataScRsp::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::BeginnerbattleRebeginCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::BeginnerbattleRebeginCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = BeginnerbattleRebeginCsReq::from(
+                common_protocol_message,
+            );
+            pb_message.xor_fields();
+            Ok(Some((BeginnerbattleRebeginCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::GetExplorationDataCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::GetExplorationDataCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1470,6 +1650,16 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((GetResourceDataCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::AdvanceBeginnerProcedureCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::AdvanceBeginnerProcedureCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = AdvanceBeginnerProcedureCsReq::from(
+                common_protocol_message,
+            );
+            pb_message.xor_fields();
+            Ok(Some((AdvanceBeginnerProcedureCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::AbyssGetDataCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::AbyssGetDataCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1690,6 +1880,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((WeaponDressCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::EndNewbieScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::EndNewbieScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = EndNewbieScRsp::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((EndNewbieScRsp::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::GetRamenDataCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::GetRamenDataCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1706,6 +1904,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((RunEventGraphScRsp::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::UnlockClueItemCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::UnlockClueItemCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = UnlockClueItemCsReq::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((UnlockClueItemCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::GetAvatarDataCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::GetAvatarDataCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1780,6 +1986,16 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((GetServerTimestampCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::AdvanceBeginnerProcedureScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::AdvanceBeginnerProcedureScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = AdvanceBeginnerProcedureScRsp::from(
+                common_protocol_message,
+            );
+            pb_message.xor_fields();
+            Ok(Some((AdvanceBeginnerProcedureScRsp::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::PerformEndCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::PerformEndCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -1927,6 +2143,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((GetPlayerInfoScRsp::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::SelectRoleScRsp::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::SelectRoleScRsp::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = SelectRoleScRsp::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((SelectRoleScRsp::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::GetUnlockDataCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::GetUnlockDataCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -2213,6 +2437,14 @@ pub fn common_protocol_unit_to_pb(
             pb_message.xor_fields();
             Ok(Some((ClickHollowSystemCsReq::CMD_ID, pb_message.encode_to_vec())))
         }
+        ::trigger_protocol::EndNewbieCsReq::CMD_ID => {
+            let common_protocol_message = ::trigger_protocol::EndNewbieCsReq::decode(
+                &mut ::std::io::Cursor::new(&unit.blob),
+            )?;
+            let mut pb_message = EndNewbieCsReq::from(common_protocol_message);
+            pb_message.xor_fields();
+            Ok(Some((EndNewbieCsReq::CMD_ID, pb_message.encode_to_vec())))
+        }
         ::trigger_protocol::LeaveCurSceneCsReq::CMD_ID => {
             let common_protocol_message = ::trigger_protocol::LeaveCurSceneCsReq::decode(
                 &mut ::std::io::Cursor::new(&unit.blob),
@@ -2295,6 +2527,26 @@ impl From<::trigger_protocol::GetRewardBuffDataScRsp> for GetRewardBuffDataScRsp
     }
 }
 #[allow(unused)]
+impl From<BeginnerbattleBeginScRsp> for ::trigger_protocol::BeginnerbattleBeginScRsp {
+    fn from(value: BeginnerbattleBeginScRsp) -> Self {
+        Self {
+            battle_uid: value.battle_uid.into(),
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::BeginnerbattleBeginScRsp> for BeginnerbattleBeginScRsp {
+    fn from(value: ::trigger_protocol::BeginnerbattleBeginScRsp) -> Self {
+        Self {
+            battle_uid: value.battle_uid.into(),
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<PlayerInfo> for ::trigger_protocol::PlayerInfo {
     fn from(value: PlayerInfo) -> Self {
         Self {
@@ -2409,6 +2661,24 @@ impl From<::trigger_protocol::Equip> for Equip {
     }
 }
 #[allow(unused)]
+impl From<SelectRoleCsReq> for ::trigger_protocol::SelectRoleCsReq {
+    fn from(value: SelectRoleCsReq) -> Self {
+        Self {
+            avatar_id: value.avatar_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::SelectRoleCsReq> for SelectRoleCsReq {
+    fn from(value: ::trigger_protocol::SelectRoleCsReq) -> Self {
+        Self {
+            avatar_id: value.avatar_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<HollowDataRefreshCsReq> for ::trigger_protocol::HollowDataRefreshCsReq {
     fn from(value: HollowDataRefreshCsReq) -> Self {
         Self { ..Default::default() }
@@ -2961,6 +3231,24 @@ impl From<::trigger_protocol::DressEquipmentCsReq> for DressEquipmentCsReq {
     }
 }
 #[allow(unused)]
+impl From<BeginnerbattleBeginCsReq> for ::trigger_protocol::BeginnerbattleBeginCsReq {
+    fn from(value: BeginnerbattleBeginCsReq) -> Self {
+        Self {
+            battle_id: value.battle_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::BeginnerbattleBeginCsReq> for BeginnerbattleBeginCsReq {
+    fn from(value: ::trigger_protocol::BeginnerbattleBeginCsReq) -> Self {
+        Self {
+            battle_id: value.battle_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<GetTipsDataScRsp> for ::trigger_protocol::GetTipsDataScRsp {
     fn from(value: GetTipsDataScRsp) -> Self {
         Self {
@@ -3023,6 +3311,44 @@ impl From<::trigger_protocol::GetActivityDataScRsp> for GetActivityDataScRsp {
     }
 }
 #[allow(unused)]
+impl From<BeginnerbattleEndCsReq> for ::trigger_protocol::BeginnerbattleEndCsReq {
+    fn from(value: BeginnerbattleEndCsReq) -> Self {
+        Self {
+            battle_uid: value.battle_uid.into(),
+            battle_id: value.battle_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::BeginnerbattleEndCsReq> for BeginnerbattleEndCsReq {
+    fn from(value: ::trigger_protocol::BeginnerbattleEndCsReq) -> Self {
+        Self {
+            battle_uid: value.battle_uid.into(),
+            battle_id: value.battle_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<UnlockClueItemScRsp> for ::trigger_protocol::UnlockClueItemScRsp {
+    fn from(value: UnlockClueItemScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::UnlockClueItemScRsp> for UnlockClueItemScRsp {
+    fn from(value: ::trigger_protocol::UnlockClueItemScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<PerformTriggerCsReq> for ::trigger_protocol::PerformTriggerCsReq {
     fn from(value: PerformTriggerCsReq) -> Self {
         Self {
@@ -3211,6 +3537,24 @@ impl From<::trigger_protocol::GetBuddyDataScRsp> for GetBuddyDataScRsp {
     }
 }
 #[allow(unused)]
+impl From<BeginnerbattleEndScRsp> for ::trigger_protocol::BeginnerbattleEndScRsp {
+    fn from(value: BeginnerbattleEndScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::BeginnerbattleEndScRsp> for BeginnerbattleEndScRsp {
+    fn from(value: ::trigger_protocol::BeginnerbattleEndScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<Transform> for ::trigger_protocol::Transform {
     fn from(value: Transform) -> Self {
         Self {
@@ -3273,6 +3617,26 @@ impl From<::trigger_protocol::EnterSectionCsReq> for EnterSectionCsReq {
     }
 }
 #[allow(unused)]
+impl From<BeginnerbattleRebeginScRsp>
+for ::trigger_protocol::BeginnerbattleRebeginScRsp {
+    fn from(value: BeginnerbattleRebeginScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::BeginnerbattleRebeginScRsp>
+for BeginnerbattleRebeginScRsp {
+    fn from(value: ::trigger_protocol::BeginnerbattleRebeginScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<RallySceneInfo> for ::trigger_protocol::RallySceneInfo {
     fn from(value: RallySceneInfo) -> Self {
         Self {
@@ -3467,6 +3831,28 @@ impl From<::trigger_protocol::AbyssGetDataScRsp> for AbyssGetDataScRsp {
     }
 }
 #[allow(unused)]
+impl From<BeginnerbattleRebeginCsReq>
+for ::trigger_protocol::BeginnerbattleRebeginCsReq {
+    fn from(value: BeginnerbattleRebeginCsReq) -> Self {
+        Self {
+            battle_uid: value.battle_uid.into(),
+            battle_id: value.battle_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::BeginnerbattleRebeginCsReq>
+for BeginnerbattleRebeginCsReq {
+    fn from(value: ::trigger_protocol::BeginnerbattleRebeginCsReq) -> Self {
+        Self {
+            battle_uid: value.battle_uid.into(),
+            battle_id: value.battle_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<GetExplorationDataCsReq> for ::trigger_protocol::GetExplorationDataCsReq {
     fn from(value: GetExplorationDataCsReq) -> Self {
         Self { ..Default::default() }
@@ -3491,6 +3877,28 @@ impl From<::trigger_protocol::GetResourceDataCsReq> for GetResourceDataCsReq {
     }
 }
 #[allow(unused)]
+impl From<AdvanceBeginnerProcedureCsReq>
+for ::trigger_protocol::AdvanceBeginnerProcedureCsReq {
+    fn from(value: AdvanceBeginnerProcedureCsReq) -> Self {
+        Self {
+            params: value.params.into(),
+            procedure_id: value.procedure_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::AdvanceBeginnerProcedureCsReq>
+for AdvanceBeginnerProcedureCsReq {
+    fn from(value: ::trigger_protocol::AdvanceBeginnerProcedureCsReq) -> Self {
+        Self {
+            params: value.params.into(),
+            procedure_id: value.procedure_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<AbyssGetDataCsReq> for ::trigger_protocol::AbyssGetDataCsReq {
     fn from(value: AbyssGetDataCsReq) -> Self {
         Self { ..Default::default() }
@@ -3561,6 +3969,24 @@ impl From<::trigger_protocol::StartHollowQuestScRsp> for StartHollowQuestScRsp {
     }
 }
 #[allow(unused)]
+impl From<FreshSceneInfo> for ::trigger_protocol::FreshSceneInfo {
+    fn from(value: FreshSceneInfo) -> Self {
+        Self {
+            last_procedure_id: value.last_procedure_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::FreshSceneInfo> for FreshSceneInfo {
+    fn from(value: ::trigger_protocol::FreshSceneInfo) -> Self {
+        Self {
+            last_procedure_id: value.last_procedure_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<TipsInfo> for ::trigger_protocol::TipsInfo {
     fn from(value: TipsInfo) -> Self {
         Self {
@@ -3614,6 +4040,7 @@ for ::trigger_protocol::SavePlayerSystemSettingCsReq {
     fn from(value: SavePlayerSystemSettingCsReq) -> Self {
         Self {
             r#type: value.r#type.into(),
+            params: value.params.into(),
             ..Default::default()
         }
     }
@@ -3624,6 +4051,7 @@ for SavePlayerSystemSettingCsReq {
     fn from(value: ::trigger_protocol::SavePlayerSystemSettingCsReq) -> Self {
         Self {
             r#type: value.r#type.into(),
+            params: value.params.into(),
             ..Default::default()
         }
     }
@@ -4115,6 +4543,26 @@ impl From<::trigger_protocol::WeaponDressCsReq> for WeaponDressCsReq {
     }
 }
 #[allow(unused)]
+impl From<EndNewbieScRsp> for ::trigger_protocol::EndNewbieScRsp {
+    fn from(value: EndNewbieScRsp) -> Self {
+        Self {
+            group_id: value.group_id.into(),
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::EndNewbieScRsp> for EndNewbieScRsp {
+    fn from(value: ::trigger_protocol::EndNewbieScRsp) -> Self {
+        Self {
+            group_id: value.group_id.into(),
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<GetRamenDataCsReq> for ::trigger_protocol::GetRamenDataCsReq {
     fn from(value: GetRamenDataCsReq) -> Self {
         Self { ..Default::default() }
@@ -4177,6 +4625,18 @@ impl From<::trigger_protocol::HollowInfo> for HollowInfo {
     }
 }
 #[allow(unused)]
+impl From<UnlockClueItemCsReq> for ::trigger_protocol::UnlockClueItemCsReq {
+    fn from(value: UnlockClueItemCsReq) -> Self {
+        Self { ..Default::default() }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::UnlockClueItemCsReq> for UnlockClueItemCsReq {
+    fn from(value: ::trigger_protocol::UnlockClueItemCsReq) -> Self {
+        Self { ..Default::default() }
+    }
+}
+#[allow(unused)]
 impl From<GetAvatarDataCsReq> for ::trigger_protocol::GetAvatarDataCsReq {
     fn from(value: GetAvatarDataCsReq) -> Self {
         Self { ..Default::default() }
@@ -4443,6 +4903,28 @@ impl From<::trigger_protocol::GetServerTimestampCsReq> for GetServerTimestampCsR
     }
 }
 #[allow(unused)]
+impl From<AdvanceBeginnerProcedureScRsp>
+for ::trigger_protocol::AdvanceBeginnerProcedureScRsp {
+    fn from(value: AdvanceBeginnerProcedureScRsp) -> Self {
+        Self {
+            next_procedure_id: value.next_procedure_id.into(),
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::AdvanceBeginnerProcedureScRsp>
+for AdvanceBeginnerProcedureScRsp {
+    fn from(value: ::trigger_protocol::AdvanceBeginnerProcedureScRsp) -> Self {
+        Self {
+            next_procedure_id: value.next_procedure_id.into(),
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<PerformEndCsReq> for ::trigger_protocol::PerformEndCsReq {
     fn from(value: PerformEndCsReq) -> Self {
         Self {
@@ -4895,6 +5377,24 @@ impl From<::trigger_protocol::GetPlayerInfoScRsp> for GetPlayerInfoScRsp {
     }
 }
 #[allow(unused)]
+impl From<SelectRoleScRsp> for ::trigger_protocol::SelectRoleScRsp {
+    fn from(value: SelectRoleScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::SelectRoleScRsp> for SelectRoleScRsp {
+    fn from(value: ::trigger_protocol::SelectRoleScRsp) -> Self {
+        Self {
+            retcode: value.retcode.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<GetUnlockDataCsReq> for ::trigger_protocol::GetUnlockDataCsReq {
     fn from(value: GetUnlockDataCsReq) -> Self {
         Self { ..Default::default() }
@@ -5821,6 +6321,24 @@ impl From<::trigger_protocol::VhsStoreData> for VhsStoreData {
     }
 }
 #[allow(unused)]
+impl From<EndNewbieCsReq> for ::trigger_protocol::EndNewbieCsReq {
+    fn from(value: EndNewbieCsReq) -> Self {
+        Self {
+            group_id: value.group_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
+impl From<::trigger_protocol::EndNewbieCsReq> for EndNewbieCsReq {
+    fn from(value: ::trigger_protocol::EndNewbieCsReq) -> Self {
+        Self {
+            group_id: value.group_id.into(),
+            ..Default::default()
+        }
+    }
+}
+#[allow(unused)]
 impl From<SystemSettings> for ::trigger_protocol::SystemSettings {
     fn from(value: SystemSettings) -> Self {
         Self {
@@ -5969,6 +6487,7 @@ impl From<SceneData> for ::trigger_protocol::SceneData {
     fn from(value: SceneData) -> Self {
         Self {
             hall_scene_info: value.hall_scene_info.map(|v| v.into()),
+            fresh_scene_info: value.fresh_scene_info.map(|v| v.into()),
             local_play_type: value.local_play_type.into(),
             fight_scene_info: value.fight_scene_info.map(|v| v.into()),
             scene_type: value.scene_type.into(),
@@ -5983,6 +6502,7 @@ impl From<::trigger_protocol::SceneData> for SceneData {
     fn from(value: ::trigger_protocol::SceneData) -> Self {
         Self {
             hall_scene_info: value.hall_scene_info.map(|v| v.into()),
+            fresh_scene_info: value.fresh_scene_info.map(|v| v.into()),
             local_play_type: value.local_play_type.into(),
             fight_scene_info: value.fight_scene_info.map(|v| v.into()),
             scene_type: value.scene_type.into(),
diff --git a/crates/trigger-protocol/src/lib.rs b/crates/trigger-protocol/src/lib.rs
index 428c7bb..b47963d 100644
--- a/crates/trigger-protocol/src/lib.rs
+++ b/crates/trigger-protocol/src/lib.rs
@@ -85,6 +85,18 @@ pub struct PlayerLogoutScRsp {
     pub retcode: i32,
 }
 
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(9)]
+pub struct SelectRoleCsReq {
+    pub avatar_id: u32,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(10)]
+pub struct SelectRoleScRsp {
+    pub retcode: i32,
+}
+
 #[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
 #[id(80)]
 pub struct SwitchRoleCsReq {
@@ -269,6 +281,7 @@ pub struct SceneData {
     pub local_play_type: u32,
     pub hall_scene_info: Option<HallSceneInfo>,
     pub fight_scene_info: Option<FightSceneInfo>,
+    pub fresh_scene_info: Option<FreshSceneInfo>,
     pub rally_scene_info: Option<RallySceneInfo>,
 }
 
@@ -322,6 +335,11 @@ pub struct FightSceneInfo {
     pub level_reward_info: Option<LevelRewardInfo>,
 }
 
+#[derive(Default, Debug, Clone, Encodeable, Decodeable)]
+pub struct FreshSceneInfo {
+    pub last_procedure_id: u32,
+}
+
 #[derive(Default, Debug, Clone, Encodeable, Decodeable)]
 pub struct PublicVariable {
     pub r#type: u32,
@@ -560,6 +578,59 @@ pub struct ActiveHollowCheckPointScRsp {
     pub retcode: i32,
 }
 
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(477)]
+pub struct AdvanceBeginnerProcedureCsReq {
+    pub procedure_id: i32,
+    pub params: i32,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(478)]
+pub struct AdvanceBeginnerProcedureScRsp {
+    pub retcode: i32,
+    pub next_procedure_id: i32,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(479)]
+pub struct BeginnerbattleBeginCsReq {
+    pub battle_id: i32,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(480)]
+pub struct BeginnerbattleBeginScRsp {
+    pub retcode: i32,
+    pub battle_uid: i64,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(481)]
+pub struct BeginnerbattleRebeginCsReq {
+    pub battle_id: i32,
+    pub battle_uid: i64,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(482)]
+pub struct BeginnerbattleRebeginScRsp {
+    pub retcode: i32,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(483)]
+pub struct BeginnerbattleEndCsReq {
+    pub battle_id: i32,
+    pub battle_uid: i64,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(484)]
+pub struct BeginnerbattleEndScRsp {
+    pub retcode: i32,
+}
+
 // Quest
 
 #[derive(Default, Debug, Clone, Encodeable, Decodeable)]
@@ -1272,6 +1343,19 @@ pub struct GetNewsStandDataScRsp {
     pub news_stand_data: Option<NewsStandData>,
 }
 
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(1323)]
+pub struct EndNewbieCsReq {
+    pub group_id: u32,
+}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(1324)]
+pub struct EndNewbieScRsp {
+    pub retcode: i32,
+    pub group_id: u32,
+}
+
 #[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
 #[id(1340)]
 pub struct GetTrashbinHermitDataCsReq {}
@@ -1489,6 +1573,16 @@ pub struct GetWorkbenchDataScRsp {
     pub workbench_data: Option<WorkbenchData>,
 }
 
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(2002)]
+pub struct UnlockClueItemCsReq {}
+
+#[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
+#[id(2003)]
+pub struct UnlockClueItemScRsp {
+    pub retcode: i32,
+}
+
 #[derive(Default, Debug, Clone, Encodeable, Decodeable, ClientCmdID)]
 #[id(2010)]
 pub struct GetPartnerDataCsReq {}