Implement NPC interactions

This commit is contained in:
xeon 2024-03-19 18:52:36 +03:00
parent 88cd9fa673
commit 921f9f932a
11 changed files with 193 additions and 27 deletions

View file

@ -23,7 +23,7 @@ leb128 = "0.2.5"
paste = "1.0.14"
sysinfo = "0.30.7"
serde = "1.0.197"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
tokio = { version = "1.36.0", features = ["full"] }

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,18 @@
mod templates;
use lazy_static::lazy_static;
pub use templates::*;
const MAIN_CITY_OBJECT_COLLECTION_JSON: &str =
include_str!("../../TemplateCollections/MainCityObjectTemplateCollection.json");
lazy_static! {
static ref MAIN_CITY_OBJECT_COLLECTION: Vec<MainCityObjectTemplate> =
serde_json::from_str(MAIN_CITY_OBJECT_COLLECTION_JSON).unwrap();
}
pub fn get_main_city_object(tag_id: i32, npc_id: i32) -> Option<&'static MainCityObjectTemplate> {
MAIN_CITY_OBJECT_COLLECTION
.iter()
.find(|object| object.tag_id == tag_id && object.npc_id == npc_id)
}

View file

@ -0,0 +1,57 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct MainCityObjectTemplate {
#[serde(rename = "TagID")]
pub tag_id: i32,
#[serde(rename = "NPCID")]
pub npc_id: i32,
#[serde(rename = "CreatePosition")]
pub create_position: String,
#[serde(rename = "CreateType")]
pub create_type: i32,
#[serde(rename = "DefaultInteractIDs")]
pub default_interact_ids: Vec<i32>,
#[serde(rename = "InteractName")]
pub interact_name: Option<String>,
#[serde(rename = "InteractShape")]
pub interact_shape: i32,
#[serde(rename = "InteractScale")]
pub interact_scale: String,
#[serde(rename = "FanInteractParam")]
pub fan_interact_param: Option<String>,
#[serde(rename = "FocusInteractScale")]
pub focus_interact_scale: f64,
#[serde(rename = "IgnoreCollider")]
pub ignore_collider: bool,
#[serde(rename = "LookIK")]
pub look_ik: bool,
#[serde(rename = "NPCLookIK")]
pub npc_look_ik: bool,
#[serde(rename = "SceneSoundID")]
pub scene_sound_id: i32,
#[serde(rename = "PlayerRotate")]
pub player_rotate: bool,
#[serde(rename = "NPCRotate")]
pub npc_rotate: bool,
#[serde(rename = "SceneObjectName")]
pub scene_object_name: Option<String>,
#[serde(rename = "CameraStoryKey")]
pub camera_story_key: Option<String>,
#[serde(rename = "ActionState")]
pub action_state: i32,
#[serde(rename = "ColliderState")]
pub collider_state: Option<String>,
#[serde(rename = "ItemState")]
pub item_state: Option<String>,
#[serde(rename = "ObjectIDs")]
pub object_ids: Vec<i32>,
#[serde(rename = "CreateInterval")]
pub create_interval: i32,
#[serde(rename = "CreateDelay")]
pub create_delay: i32,
#[serde(rename = "NPCIcon")]
pub npc_icon: Option<String>,
#[serde(rename = "ActionSwitch")]
pub action_switch: Option<String>,
}

View file

@ -42,6 +42,11 @@ impl SceneUnitManager {
uid
}
pub fn get(&self, uid: u64) -> SceneUnitProtocolInfo {
let units = self.units.borrow();
units.get(&uid).unwrap().clone()
}
pub fn sync(&self, scene_uid: u64, section_id: i32) -> PtcSyncSceneUnitArg {
PtcSyncSceneUnitArg {
scene_uid,

View file

@ -3,6 +3,7 @@ use std::path::Path;
use anyhow::Result;
use tracing::Level;
mod config;
mod game;
mod logging;
mod net;

View file

@ -6,3 +6,10 @@ pub async fn on_rpc_close_level_chg_tips_arg(
) -> Result<()> {
session.send_rpc_ret(RpcCloseLevelChgTipsRet::new()).await
}
pub async fn on_rpc_del_new_map_arg(
session: &NetworkSession,
_arg: &RpcDelNewMapArg,
) -> Result<()> {
session.send_rpc_ret(RpcDelNewMapRet::new()).await
}

View file

@ -2,6 +2,7 @@ use qwer::{
pdkhashmap, phashmap, phashset, PropertyDoubleKeyHashMap, PropertyHashMap, PropertyHashSet,
};
use crate::config;
use crate::game::{globals, util};
use super::*;
@ -23,6 +24,12 @@ pub async fn on_rpc_run_event_graph_arg(
) -> Result<()> {
tracing::info!("RunEventGraph requested");
let scene_unit_mgr = session.context.scene_unit_manager.borrow();
let unit = scene_unit_mgr.get(arg.owner_uid);
let SceneUnitProtocolInfo::NpcProtocolInfo { tag, id, .. } = unit;
let main_city_object = config::get_main_city_object(tag, id).unwrap();
let mut ptc_sync_event_info = PtcSyncEventInfoArg {
owner_type: EventGraphOwnerType::SceneUnit,
owner_uid: arg.owner_uid,
@ -30,7 +37,7 @@ pub async fn on_rpc_run_event_graph_arg(
};
ptc_sync_event_info.updated_events.insert(
10000009,
*main_city_object.default_interact_ids.iter().next().unwrap(),
100,
EventInfo {
id: 100,
@ -49,6 +56,41 @@ pub async fn on_rpc_run_event_graph_arg(
session.send_rpc_ret(RpcRunEventGraphRet::new()).await
}
#[tracing::instrument(skip(session))]
pub async fn on_rpc_finish_event_graph_perform_show_arg(
session: &NetworkSession,
arg: &RpcFinishEventGraphPerformShowArg,
) -> Result<()> {
tracing::info!("FinishEventGraphPerformShow");
let mut ptc_sync_event_info = PtcSyncEventInfoArg {
owner_type: EventGraphOwnerType::SceneUnit,
owner_uid: arg.owner_uid,
updated_events: pdkhashmap![],
};
ptc_sync_event_info.updated_events.insert(
arg.event_graph_id,
arg.event_id,
EventInfo {
id: arg.event_id,
cur_action_id: -1,
action_move_path: Vec::from([101, 102, 101, -1]),
state: EventState::Finished,
prev_state: EventState::Initing,
cur_action_info: ActionInfo::None {},
cur_action_state: ActionState::Init,
predicated_failed_actions: phashset![],
stack_frames: Vec::new(),
},
);
session.send_rpc_arg(177, &ptc_sync_event_info).await?;
session
.send_rpc_ret(RpcFinishEventGraphPerformShowRet::new())
.await
}
#[tracing::instrument(skip(session))]
pub async fn on_rpc_interact_with_unit_arg(
session: &NetworkSession,
@ -56,7 +98,12 @@ pub async fn on_rpc_interact_with_unit_arg(
) -> Result<()> {
tracing::info!("InteractWithUnit");
if arg.event_graph_id == 19900062 {
let scene_unit_mgr = session.context.scene_unit_manager.borrow();
let unit = scene_unit_mgr.get(arg.unit_uid);
let SceneUnitProtocolInfo::NpcProtocolInfo { tag, id, .. } = unit;
let main_city_object = config::get_main_city_object(tag, id).unwrap();
let mut ptc_sync_event_info = PtcSyncEventInfoArg {
owner_type: EventGraphOwnerType::SceneUnit,
owner_uid: arg.unit_uid,
@ -64,7 +111,7 @@ pub async fn on_rpc_interact_with_unit_arg(
};
ptc_sync_event_info.updated_events.insert(
10000009,
*main_city_object.default_interact_ids.iter().next().unwrap(),
100,
EventInfo {
id: 100,
@ -80,8 +127,6 @@ pub async fn on_rpc_interact_with_unit_arg(
);
session.send_rpc_arg(177, &ptc_sync_event_info).await?;
}
session.send_rpc_ret(RpcInteractWithUnitRet::new()).await
}

View file

@ -194,7 +194,7 @@ trait_handler! {
RpcCloseLevelChgTipsArg 244;
// RpcCreatePlayer 104;
// RpcDebugPay 216;
// RpcDelNewMap 287;
RpcDelNewMapArg 287;
// RpcDelNewRamen 228;
// RpcDressEquipment 112;
// RpcEatRamen 283;
@ -209,7 +209,7 @@ trait_handler! {
// RpcEquipmentStarUp 131;
RpcFinishACTPerformShowArg 185;
// RpcFinishBlackout 267;
// RpcFinishEventGraphPerformShow 187;
RpcFinishEventGraphPerformShowArg 187;
// RpcFinishGraphInClient 146;
// RpcGMCommand 113;
// RpcGacha 173;

View file

@ -20,6 +20,16 @@ pub enum HollowQuestType {
AvatarSide = 7,
}
#[derive(OctData, Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(i16)]
pub enum UnlockIDType {
HollowCard = 1,
HollowBuff = 2,
HollowEvent = 3,
HollowItem = 4,
Curse = 5,
}
#[derive(OctData, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum FairyState {

View file

@ -312,6 +312,22 @@ pub struct RpcEndBattleArg {
pub battle_statistics: LogBattleStatistics,
}
#[derive(OctData, Debug)]
pub struct RpcFinishEventGraphPerformShowArg {
pub owner_type: EventGraphOwnerType,
pub owner_uid: u64,
pub event_graph_id: i32,
pub event_id: i32,
pub step: u8,
pub return_map: HashMap<String, i32>,
}
#[derive(OctData, Debug)]
pub struct RpcDelNewMapArg {
pub map_type: UnlockIDType,
pub ids: PropertyHashSet<i32>,
}
ret! {
struct RpcLoginRet {
account_info: PropertyBlob,
@ -400,4 +416,10 @@ ret! {
hollow_event_id: i32,
reward_items_classify: HashMap<BattleRewardType, HashMap<u64, ItemIDCount>>,
}
struct RpcFinishEventGraphPerformShowRet {
}
struct RpcDelNewMapRet {
}
}