Skip to main content

rpfm_lib/files/group_formations/versions/
shogun_2.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11use crate::binary::{ReadBytes, WriteBytes};
12use crate::error::Result;
13
14use super::*;
15use super::versions::v1;
16
17impl GroupFormations {
18
19    pub(crate) fn decode_sho_2<R: ReadBytes>(&mut self, data: &mut R) -> Result<()> {
20
21        //GroupFormation
22        for _ in 0..data.read_u32()? {
23            let mut formation = GroupFormation::default();
24            formation.name = data.read_sized_string_u16()?;
25            formation.ai_priority = data.read_f32()?;
26            formation.ai_purpose = AIPurpose::V1(v1::AIPurposeFlags::from_bits_truncate(data.read_u32()?));
27
28            // MinUnitCategoryPercentage
29            for _ in 0..data.read_u32()? {
30                let mut min_unit_category_percentage = MinUnitCategoryPercentage::default();
31                min_unit_category_percentage.category = UnitCategory::try_from(data.read_u32()?)?;
32                min_unit_category_percentage.percentage = data.read_u32()?;
33                formation.min_unit_category_percentage.push(min_unit_category_percentage);
34            }
35
36            // AiSupportedFaction
37            for _ in 0..data.read_u32()? {
38                formation.ai_supported_factions.push(data.read_sized_string_u16()?);
39            }
40
41            // GroupFormationBlock
42            for _ in 0..data.read_u32()? {
43                let mut block = GroupFormationBlock::default();
44                block.block_id = data.read_u32()?;
45
46                let block_type = data.read_u32()?;
47                match block_type {
48
49                    // ContainerAbsolute
50                    0 => {
51                        let mut container = ContainerAbsolute::default();
52                        container.block_priority = data.read_f32()?;
53                        container.entity_arrangement = EntityArrangement::try_from(data.read_u32()?)?;
54                        container.inter_entity_spacing = data.read_f32()?;
55                        container.crescent_y_offset = data.read_f32()?;
56                        container.position_x = data.read_f32()?;
57                        container.position_y = data.read_f32()?;
58                        container.minimum_entity_threshold = data.read_i32()?;
59                        container.maximum_entity_threshold = data.read_i32()?;
60
61                        for _ in 0..data.read_u32()? {
62                            let mut entity_pref = EntityPreference::default();
63                            entity_pref.priority = data.read_f32()?;
64                            entity_pref.entity = Entity::V1(v1::EntityType::try_from(data.read_u32()?)?);
65                            container.entity_preferences.push(entity_pref);
66                        }
67
68                        block.block = Block::ContainerAbsolute(container);
69                    },
70
71                    // ContainerRelative
72                    1 => {
73                        let mut container = ContainerRelative::default();
74                        container.block_priority = data.read_f32()?;
75                        container.relative_block_id = data.read_u32()?;
76                        container.entity_arrangement = EntityArrangement::try_from(data.read_u32()?)?;
77                        container.inter_entity_spacing = data.read_f32()?;
78                        container.crescent_y_offset = data.read_f32()?;
79                        container.position_x = data.read_f32()?;
80                        container.position_y = data.read_f32()?;
81                        container.minimum_entity_threshold = data.read_i32()?;
82                        container.maximum_entity_threshold = data.read_i32()?;
83
84                        for _ in 0..data.read_u32()? {
85                            let mut entity_pref = EntityPreference::default();
86                            entity_pref.priority = data.read_f32()?;
87                            entity_pref.entity = Entity::V1(v1::EntityType::try_from(data.read_u32()?)?);
88                            container.entity_preferences.push(entity_pref);
89                        }
90
91                        block.block = Block::ContainerRelative(container);
92                    },
93
94                    // Spanning
95                    3 => {
96                        let mut container = Spanning::default();
97                        for _ in 0..data.read_u32()? {
98                            container.spanned_block_ids.push(data.read_u32()?);
99                        }
100                        block.block = Block::Spanning(container);
101                    },
102                    _ => todo!("unknown block type {}.", block_type),
103                }
104
105                formation.group_formation_blocks.push(block);
106            }
107
108            self.formations.push(formation);
109        }
110
111        Ok(())
112    }
113
114    pub(crate) fn encode_sho_2<W: WriteBytes>(&mut self, buffer: &mut W) -> Result<()> {
115        buffer.write_u32(self.formations.len() as u32)?;
116        for formation in self.formations() {
117            buffer.write_sized_string_u16(formation.name())?;
118            buffer.write_f32(formation.ai_priority)?;
119
120            if let AIPurpose::V1(data) = &formation.ai_purpose {
121                buffer.write_u32(data.bits())?;
122            }
123
124            buffer.write_u32(formation.min_unit_category_percentage.len() as u32)?;
125            for mucp in formation.min_unit_category_percentage() {
126                buffer.write_u32(mucp.category.into())?;
127                buffer.write_u32(mucp.percentage)?;
128            }
129
130            buffer.write_u32(formation.ai_supported_factions.len() as u32)?;
131            for s in formation.ai_supported_factions() {
132                buffer.write_sized_string_u16(s)?;
133            }
134
135            buffer.write_u32(formation.group_formation_blocks.len() as u32)?;
136            for block in formation.group_formation_blocks() {
137                buffer.write_u32(block.block_id)?;
138
139                match block.block {
140                    Block::ContainerAbsolute(ref b) => {
141                        buffer.write_u32(0)?;
142                        buffer.write_f32(b.block_priority)?;
143                        buffer.write_u32(b.entity_arrangement.into())?;
144                        buffer.write_f32(b.inter_entity_spacing)?;
145                        buffer.write_f32(b.crescent_y_offset)?;
146                        buffer.write_f32(b.position_x)?;
147                        buffer.write_f32(b.position_y)?;
148                        buffer.write_i32(b.minimum_entity_threshold)?;
149                        buffer.write_i32(b.maximum_entity_threshold)?;
150
151                        buffer.write_u32(b.entity_preferences.len() as u32)?;
152                        for ep in b.entity_preferences() {
153                            buffer.write_f32(ep.priority)?;
154                            if let Entity::V1(data) = &ep.entity {
155                                buffer.write_u32((*data).into())?;
156                            }
157                        }
158                    },
159
160                    Block::ContainerRelative(ref b) => {
161                        buffer.write_u32(1)?;
162                        buffer.write_f32(b.block_priority)?;
163                        buffer.write_u32(b.relative_block_id)?;
164                        buffer.write_u32(b.entity_arrangement.into())?;
165                        buffer.write_f32(b.inter_entity_spacing)?;
166                        buffer.write_f32(b.crescent_y_offset)?;
167                        buffer.write_f32(b.position_x)?;
168                        buffer.write_f32(b.position_y)?;
169                        buffer.write_i32(b.minimum_entity_threshold)?;
170                        buffer.write_i32(b.maximum_entity_threshold)?;
171
172                        buffer.write_u32(b.entity_preferences.len() as u32)?;
173                        for ep in b.entity_preferences() {
174                            buffer.write_f32(ep.priority)?;
175                            if let Entity::V1(data) = &ep.entity {
176                                buffer.write_u32((*data).into())?;
177                            }
178                        }
179                    },
180
181                    Block::Spanning(ref b) => {
182                        buffer.write_u32(3)?;
183                        buffer.write_u32(b.spanned_block_ids.len() as u32)?;
184                        for id in b.spanned_block_ids() {
185                            buffer.write_u32(*id)?;
186                        }
187                    },
188                }
189            }
190        }
191
192        Ok(())
193    }
194}