Skip to main content

rpfm_lib/files/group_formations/versions/
warhammer_3.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::v2;
16
17impl GroupFormations {
18
19    pub(crate) fn decode_wh3<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_u8()?;
25            formation.ai_priority = data.read_f32()?;
26            formation.ai_purpose = AIPurpose::V2(v2::AIPurposeFlags::from_bits_truncate(data.read_u32()?));
27            formation.uk_2 = data.read_u32()?;
28
29            // MinUnitCategoryPercentage
30            for _ in 0..data.read_u32()? {
31                let mut min_unit_category_percentage = MinUnitCategoryPercentage::default();
32                min_unit_category_percentage.category = UnitCategory::try_from(data.read_u32()?)?;
33                min_unit_category_percentage.percentage = data.read_u32()?;
34                formation.min_unit_category_percentage.push(min_unit_category_percentage);
35            }
36
37            for _ in 0..data.read_u32()? {
38                formation.ai_supported_subcultures.push(data.read_sized_string_u8()?);
39            }
40
41            for _ in 0..data.read_u32()? {
42                formation.ai_supported_factions.push(data.read_sized_string_u8()?);
43            }
44
45            // GroupFormationBlock
46            for _ in 0..data.read_u32()? {
47                let mut block = GroupFormationBlock::default();
48                block.block_id = data.read_u32()?;
49
50                let block_type = data.read_u32()?;
51                match block_type {
52
53                    // ContainerAbsolute
54                    0 => {
55                        let mut container = ContainerAbsolute::default();
56                        container.block_priority = data.read_f32()?;
57                        container.entity_arrangement = EntityArrangement::try_from(data.read_u32()?)?;
58                        container.inter_entity_spacing = data.read_f32()?;
59                        container.crescent_y_offset = data.read_f32()?;
60                        container.position_x = data.read_f32()?;
61                        container.position_y = data.read_f32()?;
62                        container.minimum_entity_threshold = data.read_i32()?;
63                        container.maximum_entity_threshold = data.read_i32()?;
64
65                        for _ in 0..data.read_u32()? {
66                            let mut entity_pref = EntityPreference::default();
67                            entity_pref.priority = data.read_f32()?;
68                            entity_pref.entity = Entity::V2(v2::EntityType::try_from(data.read_u32()?)?);
69                            entity_pref.entity_weight = EntityWeight::try_from(data.read_u32()?)?;
70                            entity_pref.uk_1 = data.read_u32()?;
71                            entity_pref.entity_class = data.read_sized_string_u8()?;
72                            container.entity_preferences.push(entity_pref);
73                        }
74
75                        block.block = Block::ContainerAbsolute(container);
76                    },
77
78                    // ContainerRelative
79                    1 => {
80                        let mut container = ContainerRelative::default();
81                        container.block_priority = data.read_f32()?;
82                        container.relative_block_id = data.read_u32()?;
83                        container.entity_arrangement = EntityArrangement::try_from(data.read_u32()?)?;
84                        container.inter_entity_spacing = data.read_f32()?;
85                        container.crescent_y_offset = data.read_f32()?;
86                        container.position_x = data.read_f32()?;
87                        container.position_y = data.read_f32()?;
88                        container.minimum_entity_threshold = data.read_i32()?;
89                        container.maximum_entity_threshold = data.read_i32()?;
90
91                        for _ in 0..data.read_u32()? {
92                            let mut entity_pref = EntityPreference::default();
93                            entity_pref.priority = data.read_f32()?;
94                            entity_pref.entity = Entity::V2(v2::EntityType::try_from(data.read_u32()?)?);
95                            entity_pref.entity_weight = EntityWeight::try_from(data.read_u32()?)?;
96                            entity_pref.uk_1 = data.read_u32()?;
97                            entity_pref.entity_class = data.read_sized_string_u8()?;
98                            container.entity_preferences.push(entity_pref);
99                        }
100
101                        block.block = Block::ContainerRelative(container);
102                    },
103
104                    // Spanning
105                    3 => {
106                        let mut container = Spanning::default();
107                        for _ in 0..data.read_u32()? {
108                            container.spanned_block_ids.push(data.read_u32()?);
109                        }
110                        block.block = Block::Spanning(container);
111                    },
112                    _ => todo!("unknown block type {}.", block_type),
113                }
114
115                formation.group_formation_blocks.push(block);
116            }
117
118            self.formations.push(formation);
119        }
120
121        Ok(())
122    }
123
124    pub(crate) fn encode_wh3<W: WriteBytes>(&mut self, buffer: &mut W) -> Result<()> {
125        buffer.write_u32(self.formations.len() as u32)?;
126        for formation in self.formations() {
127            buffer.write_sized_string_u8(formation.name())?;
128            buffer.write_f32(formation.ai_priority)?;
129
130            if let AIPurpose::V2(data) = &formation.ai_purpose {
131                buffer.write_u32(data.bits())?;
132            }
133
134            buffer.write_u32(formation.uk_2)?;
135
136            buffer.write_u32(formation.min_unit_category_percentage.len() as u32)?;
137            for mucp in formation.min_unit_category_percentage() {
138                buffer.write_u32(mucp.category.into())?;
139                buffer.write_u32(mucp.percentage)?;
140            }
141
142            buffer.write_u32(formation.ai_supported_subcultures.len() as u32)?;
143            for s in formation.ai_supported_subcultures() {
144                buffer.write_sized_string_u8(s)?;
145            }
146
147            buffer.write_u32(formation.ai_supported_factions.len() as u32)?;
148            for s in formation.ai_supported_factions() {
149                buffer.write_sized_string_u8(s)?;
150            }
151
152            buffer.write_u32(formation.group_formation_blocks.len() as u32)?;
153            for block in formation.group_formation_blocks() {
154                buffer.write_u32(block.block_id)?;
155
156                match block.block {
157                    Block::ContainerAbsolute(ref b) => {
158                        buffer.write_u32(0)?;
159                        buffer.write_f32(b.block_priority)?;
160                        buffer.write_u32(b.entity_arrangement.into())?;
161                        buffer.write_f32(b.inter_entity_spacing)?;
162                        buffer.write_f32(b.crescent_y_offset)?;
163                        buffer.write_f32(b.position_x)?;
164                        buffer.write_f32(b.position_y)?;
165                        buffer.write_i32(b.minimum_entity_threshold)?;
166                        buffer.write_i32(b.maximum_entity_threshold)?;
167
168                        buffer.write_u32(b.entity_preferences.len() as u32)?;
169                        for ep in b.entity_preferences() {
170                            buffer.write_f32(ep.priority)?;
171                            if let Entity::V2(data) = &ep.entity {
172                                buffer.write_u32((*data).into())?;
173                            }
174                            buffer.write_u32(ep.entity_weight.into())?;
175                            buffer.write_u32(ep.uk_1)?;
176                            buffer.write_sized_string_u8(&ep.entity_class)?;
177                        }
178                    },
179
180                    Block::ContainerRelative(ref b) => {
181                        buffer.write_u32(1)?;
182                        buffer.write_f32(b.block_priority)?;
183                        buffer.write_u32(b.relative_block_id)?;
184                        buffer.write_u32(b.entity_arrangement.into())?;
185                        buffer.write_f32(b.inter_entity_spacing)?;
186                        buffer.write_f32(b.crescent_y_offset)?;
187                        buffer.write_f32(b.position_x)?;
188                        buffer.write_f32(b.position_y)?;
189                        buffer.write_i32(b.minimum_entity_threshold)?;
190                        buffer.write_i32(b.maximum_entity_threshold)?;
191
192                        buffer.write_u32(b.entity_preferences.len() as u32)?;
193                        for ep in b.entity_preferences() {
194                            buffer.write_f32(ep.priority)?;
195                            if let Entity::V2(data) = &ep.entity {
196                                buffer.write_u32((*data).into())?;
197                            }
198                            buffer.write_u32(ep.entity_weight.into())?;
199                            buffer.write_u32(ep.uk_1)?;
200                            buffer.write_sized_string_u8(&ep.entity_class)?;
201                        }
202                    },
203
204                    Block::Spanning(ref b) => {
205                        buffer.write_u32(3)?;
206                        buffer.write_u32(b.spanned_block_ids.len() as u32)?;
207                        for id in b.spanned_block_ids() {
208                            buffer.write_u32(*id)?;
209                        }
210                    },
211                }
212            }
213        }
214
215        Ok(())
216    }
217}