mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Move common components to shared lib
This commit is contained in:
234
rc_core/src/persist/config/cubes_json.rs
Normal file
234
rc_core/src/persist/config/cubes_json.rs
Normal file
@@ -0,0 +1,234 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use polariton::operation::{Typed, Dict};
|
||||
use polariton::serdes::TypePrefix;
|
||||
|
||||
use super::super::{MovementCategoryData, MovementData, Cube, ItemCategory, ItemTier, BattleConfig};
|
||||
|
||||
const CUBE_CONFIG_FILENAME: &str = "config.json";
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CubeConfig {
|
||||
cubes: HashMap<String, Cube>,
|
||||
movement: HashMap<ItemCategory, MovementCategoryData>,
|
||||
lerp_value: f32,
|
||||
battle: BattleConfig,
|
||||
}
|
||||
|
||||
impl CubeConfig {
|
||||
pub fn load(root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
||||
let file = std::fs::File::open(root.as_ref().join(CUBE_CONFIG_FILENAME))?;
|
||||
let buffered = std::io::BufReader::new(file);
|
||||
let result = serde_json::from_reader(buffered)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl <C: Clone> super::ConfigProvider<C> for CubeConfig {
|
||||
fn cube_list(&self) -> Typed<C> {
|
||||
Typed::Dict(Dict {
|
||||
key_ty: TypePrefix::Str,
|
||||
val_ty: TypePrefix::HashMap,
|
||||
items: self.cubes.values().map(|cube| {
|
||||
let cube_d: crate::data::cube_list::CubeInfo<C> = cube.info.clone().into();
|
||||
cube_d.as_transmissible_key_val(cube.id)
|
||||
}).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
fn movement_list(&self) -> Typed<C> {
|
||||
let mut movements_stats = HashMap::<ItemCategory, HashMap<ItemTier, MovementData>>::new();
|
||||
for cube in self.cubes.values() {
|
||||
if let Some(movement_data) = &cube.movement {
|
||||
let category_map = if let Some(x) = movements_stats.get_mut(&cube.info.category) {
|
||||
x
|
||||
} else {
|
||||
movements_stats.insert(cube.info.category, HashMap::new());
|
||||
movements_stats.get_mut(&cube.info.category).unwrap()
|
||||
};
|
||||
category_map.insert(cube.info.size, movement_data.to_owned());
|
||||
}
|
||||
}
|
||||
let mut movement_cat_stats = Vec::with_capacity(self.movement.len());
|
||||
for (k, v) in self.movement.iter() {
|
||||
let stats: Vec<_> = if let Some(stats) = movements_stats.get(&k) {
|
||||
stats.iter().map(|(k, v)| (k.to_owned(), v.to_owned())).collect()
|
||||
} else {
|
||||
Vec::default()
|
||||
};
|
||||
let key: crate::data::weapon_list::ItemCategory = k.to_owned().into();
|
||||
let key_typed = Typed::<C>::Str(key.as_str().into());
|
||||
|
||||
let value_data = v.to_owned().into_data(stats);
|
||||
movement_cat_stats.push((key_typed, value_data.as_transmissible()));
|
||||
}
|
||||
Typed::Dict(Dict {
|
||||
key_ty: TypePrefix::Str,
|
||||
val_ty: TypePrefix::HashMap,
|
||||
items: vec![
|
||||
(Typed::Str("Global".into()), Typed::HashMap(vec![
|
||||
(Typed::Str("lerpValue".into()), Typed::Float(self.lerp_value)),
|
||||
].into())),
|
||||
(Typed::Str("Movements".into()), Typed::HashMap(movement_cat_stats.into())),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn weapon_list(&self) -> Typed<C> {
|
||||
let mut weapon_stats = HashMap::new();
|
||||
for cube in self.cubes.values() {
|
||||
if let Some(weapon_data) = &cube.weapon {
|
||||
let category_map = if let Some(x) = weapon_stats.get_mut(&cube.info.category) {
|
||||
x
|
||||
} else {
|
||||
weapon_stats.insert(cube.info.category, HashMap::new());
|
||||
weapon_stats.get_mut(&cube.info.category).unwrap()
|
||||
};
|
||||
category_map.insert(cube.info.size, weapon_data.to_owned());
|
||||
}
|
||||
}
|
||||
let mut weapons_vec: Vec<(Typed<C>, Typed<C>)> = Vec::with_capacity(weapon_stats.len());
|
||||
for (k, v) in weapon_stats {
|
||||
let cat_data: crate::data::weapon_list::ItemCategory = k.into();
|
||||
let mut tiers_vec = Vec::with_capacity(v.len());
|
||||
for (k, v) in v {
|
||||
let tier_data: crate::data::cube_list::ItemTier = k.into();
|
||||
let val_data: crate::data::weapon_list::WeaponData = v.into();
|
||||
tiers_vec.push((Typed::Str(tier_data.as_str().into()), val_data.as_transmissible()));
|
||||
}
|
||||
weapons_vec.push((Typed::Str(cat_data.as_str().into()), Typed::HashMap(tiers_vec.into())));
|
||||
}
|
||||
Typed::Dict(Dict {
|
||||
key_ty: TypePrefix::Str,
|
||||
val_ty: TypePrefix::HashMap,
|
||||
items: weapons_vec,
|
||||
})
|
||||
}
|
||||
|
||||
fn weapon_upgrade_list(&self) -> Typed<C> {
|
||||
let mut seen_keys = std::collections::HashSet::new();
|
||||
let mut weapon_upgrades = Vec::new();
|
||||
for cube in self.cubes.values() {
|
||||
if let Some(weapon_up) = &cube.weapon_upgrade {
|
||||
let key = (cube.info.category, cube.info.size);
|
||||
if seen_keys.contains(&key) {
|
||||
log::warn!("Weapon upgrade info for {:?} already exists, skipping", key);
|
||||
} else {
|
||||
seen_keys.insert(key);
|
||||
let weapon_upgrade_data = weapon_up.to_owned().into_data(cube.info.size, cube.info.category);
|
||||
weapon_upgrades.push(weapon_upgrade_data.as_transmissible());
|
||||
}
|
||||
}
|
||||
}
|
||||
Typed::ObjArr(weapon_upgrades.into())
|
||||
}
|
||||
|
||||
fn weapon_keys(&self) -> Typed<C> {
|
||||
let mut seen_keys = std::collections::HashSet::new();
|
||||
for cube in self.cubes.values() {
|
||||
if cube.weapon.is_some() {
|
||||
let key = crate::data::cube_list::item_key(cube.info.category.into(), cube.info.size.into());
|
||||
seen_keys.insert(key);
|
||||
}
|
||||
}
|
||||
let keys_vec: Vec<i32> = seen_keys.into_iter().collect();
|
||||
Typed::IntArr(keys_vec.into())
|
||||
}
|
||||
|
||||
fn tech_tree_nodes(&self, unlocked_cubes: &std::collections::HashSet<u32>) -> Typed<C> {
|
||||
let mut seen_cubes = std::collections::HashSet::with_capacity(self.cubes.len());
|
||||
let mut needed_cubes = std::collections::HashSet::with_capacity(self.cubes.len());
|
||||
let mut typed_nodes = Vec::new();
|
||||
for cube in self.cubes.values() {
|
||||
if let Some(tree_data) = &cube.tree {
|
||||
let is_unlocked = unlocked_cubes.contains(&cube.id);
|
||||
let is_unlockable = tree_data.requires.iter().all(|id| unlocked_cubes.contains(id));
|
||||
tree_data.neighbours.iter().for_each(|id| { needed_cubes.insert(*id); });
|
||||
seen_cubes.insert(cube.id);
|
||||
let node_data = tree_data.to_owned().into_data(cube.id, is_unlocked, is_unlockable);
|
||||
typed_nodes.push(node_data.as_transmissible_key_val());
|
||||
}
|
||||
}
|
||||
for needed_cube_id in needed_cubes {
|
||||
if !seen_cubes.contains(&needed_cube_id) {
|
||||
log::warn!("Tech tree needs cube {} but it doesn't have tree info", needed_cube_id);
|
||||
}
|
||||
}
|
||||
Typed::Dict(Dict {
|
||||
key_ty: TypePrefix::Str,
|
||||
val_ty: TypePrefix::HashMap,
|
||||
items: typed_nodes,
|
||||
})
|
||||
}
|
||||
|
||||
fn ids(&self) -> Vec<u32> {
|
||||
self.cubes.values().map(|cube| cube.id).collect()
|
||||
}
|
||||
|
||||
fn regen_config(&self) -> Typed<C> {
|
||||
let regen_data: crate::data::auto_regen::AutoRegenHealthConfig = self.battle.regen.clone().into();
|
||||
regen_data.as_transmissible()
|
||||
}
|
||||
|
||||
fn after_battle_vote_config(&self) -> Typed<C> {
|
||||
let mut vote_data = Vec::with_capacity(self.battle.votes.len()); // probably len() == 2
|
||||
for (key, val) in self.battle.votes.iter() {
|
||||
let key_data: crate::data::voting::Vote = key.to_owned().into();
|
||||
let mut val_data = Vec::with_capacity(val.len());
|
||||
for item in val {
|
||||
let vote_data: crate::data::voting::VoteThresholdData = item.to_owned().into();
|
||||
val_data.push(vote_data.as_transmissible());
|
||||
}
|
||||
vote_data.push((Typed::Str(key_data.as_str().into()), Typed::ObjArr(val_data.into())));
|
||||
}
|
||||
Typed::Dict(Dict {
|
||||
key_ty: TypePrefix::Str,
|
||||
val_ty: TypePrefix::Any,
|
||||
items: vote_data,
|
||||
})
|
||||
}
|
||||
|
||||
fn game_mode_config(&self) -> Typed<C> {
|
||||
let game_mode_data: crate::data::game_mode::GameModeConfigs = self.battle.games.into();
|
||||
game_mode_data.as_transmissible()
|
||||
}
|
||||
|
||||
fn campaigns_parameters(&self) -> Typed<C> {
|
||||
self.battle.singleplayer.clone().into_campaign_params().as_transmissible()
|
||||
}
|
||||
|
||||
fn campaign_waves(&self) -> Typed<C> {
|
||||
self.battle.singleplayer.clone().into_waves().as_transmissible()
|
||||
}
|
||||
|
||||
fn campaign_version(&self) -> Typed<C> {
|
||||
let mut locked_map = std::collections::HashMap::with_capacity(self.battle.singleplayer.campaigns.len());
|
||||
for campaign in self.battle.singleplayer.campaigns.iter() {
|
||||
locked_map.insert(campaign.id.clone(), true);
|
||||
}
|
||||
crate::data::campaign::GameModeVersionParameters {
|
||||
current_version: 0,
|
||||
is_locked: locked_map,
|
||||
}.as_transmissible()
|
||||
}
|
||||
|
||||
fn campaign_details(&self) -> super::CompleteCampaignProvider {
|
||||
let mut map = std::collections::HashMap::with_capacity(self.battle.singleplayer.campaigns.len());
|
||||
for campaign in self.battle.singleplayer.campaigns.iter() {
|
||||
//let waves_data: Vec<crate::data::campaign::CompleteWaveData> = campaign.waves.iter().map(|x| x.clone().into()).collect();
|
||||
let mut difficulty_map = std::collections::HashMap::with_capacity(campaign.difficulties.len());
|
||||
for difficulty in campaign.difficulties.iter() {
|
||||
let difficulty_data: crate::data::campaign::CampaignDifficultyData = difficulty.clone().into();
|
||||
let complete_campaign = crate::data::campaign::CampaignWavesDifficultyData {
|
||||
difficulty: difficulty_data,
|
||||
waves: campaign.waves.iter().map(|x| x.clone().into()).collect(),
|
||||
};
|
||||
difficulty_map.insert(difficulty.level, complete_campaign);
|
||||
}
|
||||
map.insert(campaign.id.clone(), difficulty_map);
|
||||
}
|
||||
super::CompleteCampaignProvider::new(map)
|
||||
}
|
||||
}
|
||||
13
rc_core/src/persist/config/mod.rs
Normal file
13
rc_core/src/persist/config/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
mod cubes_json;
|
||||
pub use cubes_json::CubeConfig;
|
||||
|
||||
mod traits;
|
||||
pub use traits::{ConfigProvider, CompleteCampaignProvider};
|
||||
|
||||
pub type ConfigImpl = CubeConfig;
|
||||
|
||||
fn __must_impl<T: ConfigProvider<()>>() {}
|
||||
|
||||
fn __test_impl() {
|
||||
__must_impl::<ConfigImpl>();
|
||||
}
|
||||
42
rc_core/src/persist/config/traits.rs
Normal file
42
rc_core/src/persist/config/traits.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use polariton::operation::Typed;
|
||||
|
||||
pub trait ConfigProvider<C> {
|
||||
fn cube_list(&self) -> Typed<C>;
|
||||
fn movement_list(&self) -> Typed<C>;
|
||||
fn weapon_list(&self) -> Typed<C>;
|
||||
fn weapon_upgrade_list(&self) -> Typed<C>;
|
||||
fn weapon_keys(&self) -> Typed<C>;
|
||||
fn tech_tree_nodes(&self, unlocked_cubes: &std::collections::HashSet<u32>) -> Typed<C>;
|
||||
fn ids(&self) -> Vec<u32>;
|
||||
fn regen_config(&self) -> Typed<C>;
|
||||
fn after_battle_vote_config(&self) -> Typed<C>;
|
||||
fn game_mode_config(&self) -> Typed<C>;
|
||||
fn campaigns_parameters(&self) -> Typed<C>;
|
||||
fn campaign_waves(&self) -> Typed<C>;
|
||||
fn campaign_version(&self) -> Typed<C>;
|
||||
fn campaign_details(&self) -> CompleteCampaignProvider;
|
||||
}
|
||||
|
||||
pub struct CompleteCampaignProvider {
|
||||
map: std::collections::HashMap<String, std::collections::HashMap<i32, crate::data::campaign::CampaignWavesDifficultyData>>,
|
||||
}
|
||||
|
||||
impl CompleteCampaignProvider {
|
||||
pub fn new(map: std::collections::HashMap<String, std::collections::HashMap<i32, crate::data::campaign::CampaignWavesDifficultyData>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
|
||||
pub fn get<C>(&self, id: &str, difficulty: &i32) -> Result<Typed<C>, i16> {
|
||||
if let Some(campaign) = self.map.get(id) {
|
||||
if let Some(details) = campaign.get(difficulty) {
|
||||
Ok(details.as_transmissible())
|
||||
} else {
|
||||
log::warn!("Couldn't find difficulty {} in campaign `{}`", difficulty, id);
|
||||
Err(crate::data::error_codes::WebServicesError::DatabaseError as i16)
|
||||
}
|
||||
} else {
|
||||
log::warn!("Couldn't find campaign {} (ignoring difficulty {})", id, difficulty);
|
||||
Err(crate::data::error_codes::WebServicesError::DatabaseError as i16)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user