wicked-waifus-rs/wicked-waifus-data/src/lib.rs

219 lines
6.3 KiB
Rust

use std::fs::File;
use std::io::BufReader;
use paste::paste;
pub use level_entity_config::LevelEntityConfigData;
pub use misc_data::*;
pub mod node_data;
pub mod pb_components;
pub mod text_map_data;
mod misc_data;
#[derive(thiserror::Error, Debug)]
pub enum LoadDataError {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Failed to parse json: {0}")]
Json(#[from] serde_json::Error),
}
macro_rules! json_data {
($($table_type:ident;)*) => {
$(paste! {
mod [<$table_type:snake>];
pub use [<$table_type:snake>]::[<$table_type Data>];
})*
$(paste! {
pub mod [<$table_type:snake _data>] {
use std::sync::OnceLock;
type Data = super::[<$table_type Data>];
pub(crate) static TABLE: OnceLock<Vec<Data>> = OnceLock::new();
pub fn iter() -> std::slice::Iter<'static, Data> {
TABLE.get().unwrap().iter()
}
}
})*
fn load_json_data(base_path: &str) -> Result<(), LoadDataError> {
$(paste! {
let path = format!("{}/{}.json", base_path, stringify!($table_type));
tracing::debug!("Loading data started: {path}");
let file = File::open(&path)?;
let reader = BufReader::new(file);
let _ = [<$table_type:snake _data>]::TABLE.set(serde_json::from_reader(reader)?);
tracing::info!("Loading data finished: {path}");
})*
Ok(())
}
};
}
macro_rules! json_hash_table_data {
($($table_type:ident, $key_param:expr, $key_type:ty;)*) => {
$(paste! {
mod [<$table_type:snake>];
pub use [<$table_type:snake>]::[<$table_type Data>];
})*
$(paste! {
pub mod [<$table_type:snake _data>] {
use std::collections::HashMap;
use std::sync::OnceLock;
pub(crate) type Data = super::[<$table_type Data>];
pub(crate) static TABLE: OnceLock<HashMap<$key_type, Data>> = OnceLock::new();
pub fn iter() -> std::collections::hash_map::Iter<'static, $key_type, Data> {
TABLE.get().unwrap().iter()
}
pub fn get(k: &$key_type) -> Option<&'static Data> {
TABLE.get().unwrap().get(k)
}
}
})*
fn load_json_hash_table_data(base_path: &str) -> Result<(), LoadDataError> {
$(paste! {
let path = format!("{}/{}.json", base_path, stringify!($table_type));
tracing::debug!("Loading data started: {path}");
let file = File::open(&path)?;
let reader = BufReader::new(file);
// Key.clone() is required for String keys, for other types like ints, it doesn't
// have any effect since clone is *value
let _ = [<$table_type:snake _data>]::TABLE.set(
serde_json::from_reader::<BufReader<File>, Vec<[<$table_type:snake _data>]::Data>>(reader)?
.into_iter()
.map(|element| (element.$key_param.clone(), element))
.collect::<std::collections::HashMap<_, _>>()
);
tracing::info!("Loading data finished: {path}");
})*
Ok(())
}
};
}
pub fn load_all_json_data(base_path: &str) -> Result<(), LoadDataError> {
load_json_data(base_path)?;
load_json_hash_table_data(base_path)?;
load_json_entity_level_config_data(base_path)?;
Ok(())
}
json_data! {
Achievement;
AdventureTask;
Area;
BaseProperty;
CalabashDevelopReward;
CalabashLevel;
Damage;
DungeonDetection;
ExchangeReward;
ExchangeShared;
ExploreProgress;
ExploreTools;
FavorGoods;
FavorLevel;
FavorStory;
FavorWord;
ForgeFormula;
FunctionCondition;
Gacha;
GachaPool;
GachaViewInfo;
GuideGroup;
GuideTutorial;
InstanceDungeon;
ItemExchangeContent;
// LevelPlayData;
LevelPlayNodeData;
LivenessTask;
LordGym;
MonsterDetection;
MonsterPropertyGrowth;
Motion;
QuestNodeData;
ResonanceAmplification;
ResonantChain;
RoleBreach;
RoleExpItem;
RoleInfo;
RoleLevelConsume;
RolePropertyGrowth;
RoleSkin;
SilentAreaDetection;
SynthesisFormula;
Teleporter;
WeaponBreach;
WeaponConf;
WeaponExpItem;
WeaponLevel;
WeaponPropertyGrowth;
WeaponReson;
}
json_hash_table_data! {
AiBase, id, i32;
AiStateMachineConfig, id, String;
BlueprintConfig, blueprint_type, String;
DragonPool, id, i32;
DropPackage, id, i32;
TemplateConfig, blueprint_type, String;
SummonCfg, blueprint_type, String;
Buff, id, i64;
}
mod level_entity_config;
pub mod level_entity_config_data {
use std::collections::HashMap;
use std::sync::OnceLock;
pub(crate) type Data = super::LevelEntityConfigData;
pub(crate) static TABLE: OnceLock<HashMap<String, Data>> = OnceLock::new();
pub fn iter() -> std::collections::hash_map::Iter<'static, String, Data> {
TABLE.get().unwrap().iter()
}
pub fn get(map_id: i32, entity_id: i64) -> Option<&'static Data> {
TABLE
.get()
.unwrap()
.get(&create_key_internal(map_id, entity_id))
}
#[inline(always)]
pub fn create_key(element: &Data) -> String {
create_key_internal(element.map_id, element.entity_id)
}
#[inline(always)]
fn create_key_internal(map_id: i32, entity_id: i64) -> String {
format!("{}_{}", map_id, entity_id)
}
}
fn load_json_entity_level_config_data(base_path: &str) -> Result<(), LoadDataError> {
let path = format!("{}/LevelEntityConfig.json", base_path);
tracing::debug!("Loading data started: {path}");
let file = File::open(&path)?;
let reader = BufReader::new(file);
let _ = level_entity_config_data::TABLE.set(
serde_json::from_reader::<BufReader<File>, Vec<level_entity_config_data::Data>>(reader)?
.into_iter()
.map(|element| (level_entity_config_data::create_key(&element), element))
.collect::<std::collections::HashMap<_, _>>(),
);
tracing::info!("Loading data finished: {path}");
Ok(())
}