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 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<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<()> {
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)
}

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,
};
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<RwLock<PlayerInfo>>,
map: RwLock<Option<HollowGridMapProtocolInfo>>,
@ -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![],

View file

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

View file

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

View file

@ -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,
}