From e84cad1f79598099a83cf86e516341bf26b4c010 Mon Sep 17 00:00:00 2001 From: xeon Date: Thu, 30 May 2024 19:07:16 +0300 Subject: [PATCH] Actual parsing of EventGraphCollection --- .../BinOutput}/EventGraphCollection.json | 0 gameserver/src/data/event_graph.rs | 100 ++++++++++++++++++ gameserver/src/data/mod.rs | 19 +++- gameserver/src/game/data.rs | 17 --- gameserver/src/game/manager/hollow_grid.rs | 86 +++++++-------- gameserver/src/game/mod.rs | 1 - protocol/Cargo.toml | 1 + protocol/src/enums.rs | 18 +++- 8 files changed, 173 insertions(+), 69 deletions(-) rename {gameserver => assets/BinOutput}/EventGraphCollection.json (100%) create mode 100644 gameserver/src/data/event_graph.rs delete mode 100644 gameserver/src/game/data.rs diff --git a/gameserver/EventGraphCollection.json b/assets/BinOutput/EventGraphCollection.json similarity index 100% rename from gameserver/EventGraphCollection.json rename to assets/BinOutput/EventGraphCollection.json diff --git a/gameserver/src/data/event_graph.rs b/gameserver/src/data/event_graph.rs new file mode 100644 index 0000000..f48ad73 --- /dev/null +++ b/gameserver/src/data/event_graph.rs @@ -0,0 +1,100 @@ +#![allow(unused)] + +use std::collections::{BTreeMap, HashSet}; + +use protocol::{HollowEventType, NodeState, NodeVisible}; +use serde::{Deserialize, Deserializer}; + +#[derive(Deserialize)] +#[serde(rename_all = "PascalCase")] +pub struct ConfigEventGraph { + #[serde(rename = "ID")] + pub id: i32, + pub events: BTreeMap, +} + +#[derive(Deserialize, Default)] +#[serde(untagged)] +pub enum ConfigValue { + Constant(i32), + Expression(String), + #[default] + Empty, +} + +#[derive(Deserialize, Ord, PartialOrd, Eq, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub enum ConfigEventType { + OnStart, + OnEnd, + #[serde(other)] + Unknown, +} + +#[derive(Deserialize)] +#[serde(rename_all = "PascalCase")] +pub struct ConfigEvent { + #[serde(default)] + pub actions: Vec, +} + +#[derive(Deserialize, Default)] +pub enum HollowPositionOffsetType { + #[default] + Relative = 0, + Absolute = 1, + EventPos = 2, +} + +#[derive(Deserialize, Default)] +#[serde(tag = "$type")] +pub enum ConfigAction { + #[serde(rename = "Share.CConfigEmpty")] + ConfigEmpty, + #[serde(rename = "Share.CConfigSetMapState")] + #[serde(rename_all = "PascalCase")] + ConfigSetMapState { + #[serde(default)] + x: ConfigValue, + #[serde(default)] + y: ConfigValue, + #[serde(default)] + position: HollowPositionOffsetType, + radius: Option, + count: Option, + #[serde(default)] + r#type: HashSet, + event_type_tag: Option, + #[serde(default)] + from_visible_state: HashSet, + #[serde(default)] + to_visible_state: Vec, + #[serde(default)] + from_state: HashSet, + #[serde(default)] + to_state: Vec, + #[serde(default)] + exclude_player_pos: bool, + #[serde(default)] + index_list: Vec, + #[serde(default)] + use_perform: bool, + }, + #[serde(rename = "Share.CConfigTriggerBattle")] + #[serde(rename_all = "PascalCase")] + ConfigTriggerBattle { + #[serde(rename = "BattleID")] + battle_id: ConfigValue, + on_success: Option, + on_failure: Option, + #[serde(default)] + end_hollow: bool, + #[serde(default)] + goto_next_hollow: bool, + }, + #[serde(rename = "Share.CConfigFinishHollow")] + ConfigFinishHollow, + #[default] + #[serde(other)] + ConfigUnknown, +} diff --git a/gameserver/src/data/mod.rs b/gameserver/src/data/mod.rs index 3de1a85..93be281 100644 --- a/gameserver/src/data/mod.rs +++ b/gameserver/src/data/mod.rs @@ -1,9 +1,11 @@ +mod event_graph; mod templates; mod tsv_util; -use std::path::Path; +use std::{collections::HashMap, path::Path}; use anyhow::{bail, Result}; +pub use event_graph::*; use paste::paste; pub use templates::*; use tokio::sync::OnceCell; @@ -38,6 +40,15 @@ template_collections! { MainCityObject; } +static EVENT_GRAPH_COLLECTION: OnceCell> = OnceCell::const_new(); + +fn init_binoutput() -> Result<()> { + let _ = EVENT_GRAPH_COLLECTION.set(serde_json::from_str( + std::fs::read_to_string("assets/BinOutput/EventGraphCollection.json")?.as_str(), + )?); + Ok(()) +} + pub fn init_assets() -> Result<()> { if !Path::new("assets/").exists() { bail!( @@ -46,9 +57,13 @@ pub fn init_assets() -> Result<()> { } init_template_collections()?; - Ok(()) + init_binoutput() } pub fn get_main_city_object(tag_id: i32, npc_id: i32) -> Option<&'static MainCityObjectTemplate> { iter_main_city_object_collection().find(|o| o.tag_id == tag_id && o.npc_id == npc_id) } + +pub fn get_event_graph(id: i32) -> Option<&'static ConfigEventGraph> { + EVENT_GRAPH_COLLECTION.get().unwrap().get(&id) +} diff --git a/gameserver/src/game/data.rs b/gameserver/src/game/data.rs deleted file mode 100644 index eea452c..0000000 --- a/gameserver/src/game/data.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::sync::LazyLock; - -use serde_json::{Map, Value}; - -pub const EVENT_GRAPH_COLLECTION: &str = include_str!("../../EventGraphCollection.json"); - -static EVENT_MAP: LazyLock> = LazyLock::new(|| { - serde_json::from_str::(EVENT_GRAPH_COLLECTION) - .unwrap() - .as_object() - .unwrap() - .clone() -}); - -pub fn get_event_config_json(id: i32) -> &'static Value { - EVENT_MAP.get(&id.to_string()).unwrap() -} diff --git a/gameserver/src/game/manager/hollow_grid.rs b/gameserver/src/game/manager/hollow_grid.rs index b0ab3db..0904e7f 100644 --- a/gameserver/src/game/manager/hollow_grid.rs +++ b/gameserver/src/game/manager/hollow_grid.rs @@ -3,11 +3,12 @@ use std::{ sync::Arc, }; -use crate::game::data; use protocol::*; use qwer::{phashmap, phashset, PropertyHashMap, PropertyHashSet}; use tokio::sync::RwLock; +use crate::data::{self, ConfigAction, ConfigEventType, ConfigValue}; + pub struct HollowGridManager { player: Arc>, map: RwLock>, @@ -97,15 +98,14 @@ impl HollowGridManager { let map = map.as_ref().unwrap(); let cur_grid = map.grids.get(&map.start_grid).unwrap(); - let event_config = - data::get_event_config_json(cur_grid.grid.event_graph_info.hollow_event_template_id); + let graph = + data::get_event_graph(cur_grid.grid.event_graph_info.hollow_event_template_id).unwrap(); let mut hollow_finished = false; - let actions = event_config["Events"]["OnEnd"]["Actions"] - .as_array() - .unwrap(); - if let Some(action) = actions.first() { - hollow_finished = action["$type"].as_str().unwrap() == "Share.CConfigFinishHollow"; + if let Some(event) = graph.events.get(&ConfigEventType::OnEnd) { + if let Some(ConfigAction::ConfigFinishHollow) = event.actions.first() { + hollow_finished = true; + } } ( @@ -199,31 +199,29 @@ impl HollowGridManager { let sync_hollow_event = { let info = map.grids.get(&(event_graph_uid as u16)).unwrap().clone(); - let event_config = - data::get_event_config_json(info.grid.event_graph_info.hollow_event_template_id); + let graph = + data::get_event_graph(info.grid.event_graph_info.hollow_event_template_id).unwrap(); + + let mut last_action = &ConfigAction::ConfigEmpty; - let mut last_exec_type = ""; for id in &move_path { let index = (id % 1000) - 1; - let actions = if id / 1000 == 1 { - event_config["Events"]["OnStart"]["Actions"] - .as_array() - .unwrap() + let event = if id / 1000 == 1 { + graph.events.get(&ConfigEventType::OnStart) } else { - event_config["Events"]["OnEnd"]["Actions"] - .as_array() - .unwrap() + graph.events.get(&ConfigEventType::OnEnd) }; - if let Some(action) = actions.get(index as usize) { - last_exec_type = action["$type"].as_str().unwrap(); + if let Some(action) = event.unwrap().actions.get(index as usize) { + last_action = action; - // ugly, we have to parse these configs properly - match action["$type"].as_str().unwrap() { - "Share.CConfigSetMapState" => { - let x = action["X"].as_i64().unwrap() as u16; - let y = action["Y"].as_i64().unwrap() as u16; + match action { + ConfigAction::ConfigSetMapState { x, y, .. } => { + let (ConfigValue::Constant(x), ConfigValue::Constant(y)) = (x, y) + else { + panic!("ConfigSetMapState: only constant values are supported"); + }; - let uid = (y * 11) + x; + let uid = ((y * 11) + x) as u16; if let Some(info) = map.grids.get_mut(&uid) { info.grid.flag |= HollowGridFlag::Visible as i32 | HollowGridFlag::CanMove as i32 @@ -232,14 +230,14 @@ impl HollowGridManager { grid_update.grids.insert(uid, info.clone()); } } - "Share.CConfigTriggerBattle" => { + ConfigAction::ConfigTriggerBattle { .. } => { trigger_battle_id = Some(match info.grid.event_graph_info.hollow_event_template_id { 1000107 => 10101002, _ => 10101001, }); } - "Share.CConfigFinishHollow" => { + ConfigAction::ConfigFinishHollow => { hollow_finished = true; } _ => {} @@ -251,13 +249,9 @@ impl HollowGridManager { let last_client_action = *action_move_path.last().unwrap(); let actions = if last_client_action / 1000 == 1 { - event_config["Events"]["OnStart"]["Actions"] - .as_array() - .unwrap() + &graph.events.get(&ConfigEventType::OnStart).unwrap().actions } else { - event_config["Events"]["OnEnd"]["Actions"] - .as_array() - .unwrap() + &graph.events.get(&ConfigEventType::OnEnd).unwrap().actions }; let state = if last_client_action == -1 { EventState::Finished @@ -265,24 +259,24 @@ impl HollowGridManager { action_move_path.push(-1); EventState::Finished } else { - if last_exec_type != "Share.CConfigEmpty" { + if !matches!(last_action, ConfigAction::ConfigEmpty) { action_move_path.push(last_client_action + 1); } EventState::WaitingClient }; - let finish_event = if last_exec_type != "Share.CConfigTriggerBattle" { + let finish_event = if let ConfigAction::ConfigTriggerBattle { .. } = last_action { PtcSyncHollowEventInfoArg { event_graph_uid, hollow_event_template_id: info.grid.event_graph_info.hollow_event_template_id, event_graph_id: info.grid.event_graph_info.hollow_event_template_id, updated_event: EventInfo { - id: 1000, - cur_action_id: *action_move_path.last().unwrap(), - action_move_path, - state, - prev_state: EventState::Running, + id: 0, + cur_action_id: 0, + action_move_path: vec![], + state: EventState::Initing, + prev_state: EventState::Initing, cur_action_info: ActionInfo::None {}, cur_action_state: ActionState::Init, predicated_failed_actions: phashset![], @@ -296,11 +290,11 @@ impl HollowGridManager { hollow_event_template_id: info.grid.event_graph_info.hollow_event_template_id, event_graph_id: info.grid.event_graph_info.hollow_event_template_id, updated_event: EventInfo { - id: 0, - cur_action_id: 0, - action_move_path: vec![], - state: EventState::Initing, - prev_state: EventState::Initing, + id: 1000, + cur_action_id: *action_move_path.last().unwrap(), + action_move_path, + state, + prev_state: EventState::Running, cur_action_info: ActionInfo::None {}, cur_action_state: ActionState::Init, predicated_failed_actions: phashset![], diff --git a/gameserver/src/game/mod.rs b/gameserver/src/game/mod.rs index e67697e..3283106 100644 --- a/gameserver/src/game/mod.rs +++ b/gameserver/src/game/mod.rs @@ -1,5 +1,4 @@ mod context; -pub mod data; pub mod manager; pub mod util; diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index c709721..5223e22 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -7,3 +7,4 @@ version.workspace = true byteorder.workspace = true hex.workspace = true qwer.workspace = true +serde.workspace = true diff --git a/protocol/src/enums.rs b/protocol/src/enums.rs index aa2eb70..73bad36 100644 --- a/protocol/src/enums.rs +++ b/protocol/src/enums.rs @@ -1,3 +1,5 @@ +use serde::Deserialize; + use super::*; #[derive(OctData, Clone, Debug, PartialEq, Eq)] @@ -560,7 +562,7 @@ flag! { } } -#[derive(OctData, Clone, Debug)] +#[derive(OctData, Clone, Debug, Hash, PartialEq, Eq, Deserialize)] #[repr(i16)] pub enum NodeState { All = 0, @@ -577,7 +579,7 @@ pub enum NodeState { EnumCount = 11, } -#[derive(OctData, Clone, Debug)] +#[derive(OctData, Clone, Debug, Hash, PartialEq, Eq, Deserialize)] #[repr(i16)] pub enum NodeVisible { All = 0, @@ -588,24 +590,34 @@ pub enum NodeVisible { EnumCount = 5, } -#[derive(OctData, Clone, Debug)] +#[derive(OctData, Clone, Debug, Hash, PartialEq, Eq, Deserialize)] #[repr(i16)] pub enum HollowEventType { None = 0, All = 1, Begin = 10, End = 20, + #[serde(rename = "Interact_End")] InteractEnd = 21, + #[serde(rename = "Battle_End")] BattleEnd = 22, + #[serde(rename = "Change_Level_Interact")] ChangeLevelInteract = 23, + #[serde(rename = "Change_Level_Fight")] ChangeLevelFight = 24, Battle = 30, + #[serde(rename = "Battle_Normal")] BattleNormal = 31, + #[serde(rename = "Battle_Elite")] BattleElite = 32, + #[serde(rename = "Battle_Boss")] BattleBoss = 33, Dialog = 40, + #[serde(rename = "Dialog_Positive")] DialogPositive = 41, + #[serde(rename = "Dialog_Negative")] DialogNegative = 42, + #[serde(rename = "Dialog_Special")] DialogSpecial = 43, }