Actual parsing of EventGraphCollection

This commit is contained in:
xeon 2024-05-30 19:07:16 +03:00
parent f0fe7622b2
commit e84cad1f79
8 changed files with 173 additions and 69 deletions

View file

@ -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<ConfigEventType, ConfigEvent>,
}
#[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<ConfigAction>,
}
#[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<ConfigValue>,
count: Option<ConfigValue>,
#[serde(default)]
r#type: HashSet<HollowEventType>,
event_type_tag: Option<String>,
#[serde(default)]
from_visible_state: HashSet<NodeVisible>,
#[serde(default)]
to_visible_state: Vec<NodeVisible>,
#[serde(default)]
from_state: HashSet<NodeState>,
#[serde(default)]
to_state: Vec<NodeState>,
#[serde(default)]
exclude_player_pos: bool,
#[serde(default)]
index_list: Vec<ConfigValue>,
#[serde(default)]
use_perform: bool,
},
#[serde(rename = "Share.CConfigTriggerBattle")]
#[serde(rename_all = "PascalCase")]
ConfigTriggerBattle {
#[serde(rename = "BattleID")]
battle_id: ConfigValue,
on_success: Option<String>,
on_failure: Option<String>,
#[serde(default)]
end_hollow: bool,
#[serde(default)]
goto_next_hollow: bool,
},
#[serde(rename = "Share.CConfigFinishHollow")]
ConfigFinishHollow,
#[default]
#[serde(other)]
ConfigUnknown,
}

View file

@ -1,9 +1,11 @@
mod event_graph;
mod templates; mod templates;
mod tsv_util; mod tsv_util;
use std::path::Path; use std::{collections::HashMap, path::Path};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
pub use event_graph::*;
use paste::paste; use paste::paste;
pub use templates::*; pub use templates::*;
use tokio::sync::OnceCell; use tokio::sync::OnceCell;
@ -38,6 +40,15 @@ template_collections! {
MainCityObject; MainCityObject;
} }
static EVENT_GRAPH_COLLECTION: OnceCell<HashMap<i32, ConfigEventGraph>> = 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<()> { pub fn init_assets() -> Result<()> {
if !Path::new("assets/").exists() { if !Path::new("assets/").exists() {
bail!( bail!(
@ -46,9 +57,13 @@ pub fn init_assets() -> Result<()> {
} }
init_template_collections()?; init_template_collections()?;
Ok(()) init_binoutput()
} }
pub fn get_main_city_object(tag_id: i32, npc_id: i32) -> Option<&'static MainCityObjectTemplate> { 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) 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)
}

View file

@ -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<Map<String, Value>> = LazyLock::new(|| {
serde_json::from_str::<Value>(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()
}

View file

@ -3,11 +3,12 @@ use std::{
sync::Arc, sync::Arc,
}; };
use crate::game::data;
use protocol::*; use protocol::*;
use qwer::{phashmap, phashset, PropertyHashMap, PropertyHashSet}; use qwer::{phashmap, phashset, PropertyHashMap, PropertyHashSet};
use tokio::sync::RwLock; use tokio::sync::RwLock;
use crate::data::{self, ConfigAction, ConfigEventType, ConfigValue};
pub struct HollowGridManager { pub struct HollowGridManager {
player: Arc<RwLock<PlayerInfo>>, player: Arc<RwLock<PlayerInfo>>,
map: RwLock<Option<HollowGridMapProtocolInfo>>, map: RwLock<Option<HollowGridMapProtocolInfo>>,
@ -97,15 +98,14 @@ impl HollowGridManager {
let map = map.as_ref().unwrap(); let map = map.as_ref().unwrap();
let cur_grid = map.grids.get(&map.start_grid).unwrap(); let cur_grid = map.grids.get(&map.start_grid).unwrap();
let event_config = let graph =
data::get_event_config_json(cur_grid.grid.event_graph_info.hollow_event_template_id); data::get_event_graph(cur_grid.grid.event_graph_info.hollow_event_template_id).unwrap();
let mut hollow_finished = false; let mut hollow_finished = false;
let actions = event_config["Events"]["OnEnd"]["Actions"] if let Some(event) = graph.events.get(&ConfigEventType::OnEnd) {
.as_array() if let Some(ConfigAction::ConfigFinishHollow) = event.actions.first() {
.unwrap(); hollow_finished = true;
if let Some(action) = actions.first() { }
hollow_finished = action["$type"].as_str().unwrap() == "Share.CConfigFinishHollow";
} }
( (
@ -199,31 +199,29 @@ impl HollowGridManager {
let sync_hollow_event = { let sync_hollow_event = {
let info = map.grids.get(&(event_graph_uid as u16)).unwrap().clone(); let info = map.grids.get(&(event_graph_uid as u16)).unwrap().clone();
let event_config = let graph =
data::get_event_config_json(info.grid.event_graph_info.hollow_event_template_id); 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 { for id in &move_path {
let index = (id % 1000) - 1; let index = (id % 1000) - 1;
let actions = if id / 1000 == 1 { let event = if id / 1000 == 1 {
event_config["Events"]["OnStart"]["Actions"] graph.events.get(&ConfigEventType::OnStart)
.as_array()
.unwrap()
} else { } else {
event_config["Events"]["OnEnd"]["Actions"] graph.events.get(&ConfigEventType::OnEnd)
.as_array()
.unwrap()
}; };
if let Some(action) = actions.get(index as usize) { if let Some(action) = event.unwrap().actions.get(index as usize) {
last_exec_type = action["$type"].as_str().unwrap(); last_action = action;
// ugly, we have to parse these configs properly match action {
match action["$type"].as_str().unwrap() { ConfigAction::ConfigSetMapState { x, y, .. } => {
"Share.CConfigSetMapState" => { let (ConfigValue::Constant(x), ConfigValue::Constant(y)) = (x, y)
let x = action["X"].as_i64().unwrap() as u16; else {
let y = action["Y"].as_i64().unwrap() as u16; 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) { if let Some(info) = map.grids.get_mut(&uid) {
info.grid.flag |= HollowGridFlag::Visible as i32 info.grid.flag |= HollowGridFlag::Visible as i32
| HollowGridFlag::CanMove as i32 | HollowGridFlag::CanMove as i32
@ -232,14 +230,14 @@ impl HollowGridManager {
grid_update.grids.insert(uid, info.clone()); grid_update.grids.insert(uid, info.clone());
} }
} }
"Share.CConfigTriggerBattle" => { ConfigAction::ConfigTriggerBattle { .. } => {
trigger_battle_id = trigger_battle_id =
Some(match info.grid.event_graph_info.hollow_event_template_id { Some(match info.grid.event_graph_info.hollow_event_template_id {
1000107 => 10101002, 1000107 => 10101002,
_ => 10101001, _ => 10101001,
}); });
} }
"Share.CConfigFinishHollow" => { ConfigAction::ConfigFinishHollow => {
hollow_finished = true; hollow_finished = true;
} }
_ => {} _ => {}
@ -251,13 +249,9 @@ impl HollowGridManager {
let last_client_action = *action_move_path.last().unwrap(); let last_client_action = *action_move_path.last().unwrap();
let actions = if last_client_action / 1000 == 1 { let actions = if last_client_action / 1000 == 1 {
event_config["Events"]["OnStart"]["Actions"] &graph.events.get(&ConfigEventType::OnStart).unwrap().actions
.as_array()
.unwrap()
} else { } else {
event_config["Events"]["OnEnd"]["Actions"] &graph.events.get(&ConfigEventType::OnEnd).unwrap().actions
.as_array()
.unwrap()
}; };
let state = if last_client_action == -1 { let state = if last_client_action == -1 {
EventState::Finished EventState::Finished
@ -265,24 +259,24 @@ impl HollowGridManager {
action_move_path.push(-1); action_move_path.push(-1);
EventState::Finished EventState::Finished
} else { } else {
if last_exec_type != "Share.CConfigEmpty" { if !matches!(last_action, ConfigAction::ConfigEmpty) {
action_move_path.push(last_client_action + 1); action_move_path.push(last_client_action + 1);
} }
EventState::WaitingClient EventState::WaitingClient
}; };
let finish_event = if last_exec_type != "Share.CConfigTriggerBattle" { let finish_event = if let ConfigAction::ConfigTriggerBattle { .. } = last_action {
PtcSyncHollowEventInfoArg { PtcSyncHollowEventInfoArg {
event_graph_uid, event_graph_uid,
hollow_event_template_id: info.grid.event_graph_info.hollow_event_template_id, 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, event_graph_id: info.grid.event_graph_info.hollow_event_template_id,
updated_event: EventInfo { updated_event: EventInfo {
id: 1000, id: 0,
cur_action_id: *action_move_path.last().unwrap(), cur_action_id: 0,
action_move_path, action_move_path: vec![],
state, state: EventState::Initing,
prev_state: EventState::Running, prev_state: EventState::Initing,
cur_action_info: ActionInfo::None {}, cur_action_info: ActionInfo::None {},
cur_action_state: ActionState::Init, cur_action_state: ActionState::Init,
predicated_failed_actions: phashset![], predicated_failed_actions: phashset![],
@ -296,11 +290,11 @@ impl HollowGridManager {
hollow_event_template_id: info.grid.event_graph_info.hollow_event_template_id, 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, event_graph_id: info.grid.event_graph_info.hollow_event_template_id,
updated_event: EventInfo { updated_event: EventInfo {
id: 0, id: 1000,
cur_action_id: 0, cur_action_id: *action_move_path.last().unwrap(),
action_move_path: vec![], action_move_path,
state: EventState::Initing, state,
prev_state: EventState::Initing, prev_state: EventState::Running,
cur_action_info: ActionInfo::None {}, cur_action_info: ActionInfo::None {},
cur_action_state: ActionState::Init, cur_action_state: ActionState::Init,
predicated_failed_actions: phashset![], predicated_failed_actions: phashset![],

View file

@ -1,5 +1,4 @@
mod context; mod context;
pub mod data;
pub mod manager; pub mod manager;
pub mod util; pub mod util;

View file

@ -7,3 +7,4 @@ version.workspace = true
byteorder.workspace = true byteorder.workspace = true
hex.workspace = true hex.workspace = true
qwer.workspace = true qwer.workspace = true
serde.workspace = true

View file

@ -1,3 +1,5 @@
use serde::Deserialize;
use super::*; use super::*;
#[derive(OctData, Clone, Debug, PartialEq, Eq)] #[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)] #[repr(i16)]
pub enum NodeState { pub enum NodeState {
All = 0, All = 0,
@ -577,7 +579,7 @@ pub enum NodeState {
EnumCount = 11, EnumCount = 11,
} }
#[derive(OctData, Clone, Debug)] #[derive(OctData, Clone, Debug, Hash, PartialEq, Eq, Deserialize)]
#[repr(i16)] #[repr(i16)]
pub enum NodeVisible { pub enum NodeVisible {
All = 0, All = 0,
@ -588,24 +590,34 @@ pub enum NodeVisible {
EnumCount = 5, EnumCount = 5,
} }
#[derive(OctData, Clone, Debug)] #[derive(OctData, Clone, Debug, Hash, PartialEq, Eq, Deserialize)]
#[repr(i16)] #[repr(i16)]
pub enum HollowEventType { pub enum HollowEventType {
None = 0, None = 0,
All = 1, All = 1,
Begin = 10, Begin = 10,
End = 20, End = 20,
#[serde(rename = "Interact_End")]
InteractEnd = 21, InteractEnd = 21,
#[serde(rename = "Battle_End")]
BattleEnd = 22, BattleEnd = 22,
#[serde(rename = "Change_Level_Interact")]
ChangeLevelInteract = 23, ChangeLevelInteract = 23,
#[serde(rename = "Change_Level_Fight")]
ChangeLevelFight = 24, ChangeLevelFight = 24,
Battle = 30, Battle = 30,
#[serde(rename = "Battle_Normal")]
BattleNormal = 31, BattleNormal = 31,
#[serde(rename = "Battle_Elite")]
BattleElite = 32, BattleElite = 32,
#[serde(rename = "Battle_Boss")]
BattleBoss = 33, BattleBoss = 33,
Dialog = 40, Dialog = 40,
#[serde(rename = "Dialog_Positive")]
DialogPositive = 41, DialogPositive = 41,
#[serde(rename = "Dialog_Negative")]
DialogNegative = 42, DialogNegative = 42,
#[serde(rename = "Dialog_Special")]
DialogSpecial = 43, DialogSpecial = 43,
} }