Skip to main content

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