rpfm_extensions/startpos/world/writer/
government.rs1use std::collections::HashMap;
17
18use rpfm_lib::error::Result;
19use rpfm_lib::files::esf::{NodeType, RecordNode};
20
21use super::{child, WorldInputs, WorldPlan};
22use crate::startpos::world::government::{government_posts, post_holders, PostGroup, FACTION_LEADER_POSITION};
23
24const GOVERNMENT_PATH: &str = "CAMPAIGN_STARTPOS/CAMPAIGN_ENV/CAMPAIGN_MODEL/WORLD/FACTION_ARRAY/FACTION/GOVERNMENT";
26
27const POSTS_PATH: &str = "CAMPAIGN_STARTPOS/CAMPAIGN_ENV/CAMPAIGN_MODEL/WORLD/FACTION_ARRAY/FACTION/GOVERNMENT/CHARACTER_POSTS";
29
30#[derive(Debug, Clone, Default)]
36pub struct PostPlan {
37
38 groups: HashMap<String, Vec<(PostGroup, u32)>>,
40
41 posts_of: HashMap<String, u32>,
43}
44
45impl PostPlan {
50
51 pub fn new(inputs: &WorldInputs, plan: &WorldPlan) -> Result<Self> {
57 let (mut groups, mut posts_of) = (HashMap::new(), HashMap::new());
58
59 if inputs.layout.record(&format!("{}/FACTION_ARRAY/FACTION/GOVERNMENT/CHARACTER_POSTS", super::WORLD_PATH)).is_none() {
61 return Ok(Self { groups, posts_of });
62 }
63 let mut next_post = 1;
64 for faction in plan.factions() {
65 let mut faction_groups = vec![];
66 for group in government_posts(inputs.tables, inputs.index, faction)? {
67 let count = group.count();
68 let holders = post_holders(inputs.tables, inputs.index, faction, group.position())?;
69 for (post, holder) in (next_post..next_post + count).zip(holders) {
70 posts_of.entry(holder).or_insert(post);
71 }
72 faction_groups.push((group, next_post));
73 next_post += count;
74 }
75 groups.insert(faction.key().to_owned(), faction_groups);
76 }
77 Ok(Self { groups, posts_of })
78 }
79
80 pub fn post_of(&self, character: &str) -> Option<u32> {
82 self.posts_of.get(character).copied()
83 }
84
85 pub fn holder_of(&self, post: u32) -> Option<&str> {
87 self.posts_of.iter().find(|(_, held)| **held == post).map(|(holder, _)| holder.as_str())
88 }
89
90 pub fn groups_of(&self, faction: &str) -> &[(PostGroup, u32)] {
92 self.groups.get(faction).map(Vec::as_slice).unwrap_or_default()
93 }
94
95 pub fn leader_post(&self, faction: &str) -> Option<u32> {
97 self.groups_of(faction).iter().find(|(group, _)| group.position() == FACTION_LEADER_POSITION).map(|(_, id)| *id)
98 }
99}
100
101pub fn write_character_posts(inputs: &WorldInputs, posts: &PostPlan, faction: &str, runtime_id: impl Fn(&str) -> Option<u32>) -> Result<RecordNode> {
115 let mut array = child(inputs.layout, GOVERNMENT_PATH, "CHARACTER_POSTS")?;
116 for (group, first_id) in posts.groups_of(faction) {
117 let entry = array.push_group()?;
118 entry.set_u32("^+1", group.count())?;
119 for index in 0..group.count() {
120 let holder = posts.holder_of(first_id + index).and_then(&runtime_id).unwrap_or_default();
121 let mut post = child(inputs.layout, POSTS_PATH, "CHARACTER_POST")?;
122 post.group()?
123 .set_u32("^+1", first_id + index)?
124 .set_str("^+2", group.position())?
125 .set_u32("^+3", holder)?
126 .set("^+5", NodeType::I64(group.unique_id()))?;
127 let key = if index == 0 { "CHARACTER_POST".to_owned() } else { format!("CHARACTER_POST@{}", index + 1) };
128 entry.set_record(&key, Some(post.build()?))?;
129 }
130 }
131 array.build()
132}