rpfm_lib/files/fastbin_lists/
mod.rs1use getset::*;
23use serde_derive::{Serialize, Deserialize};
24
25use crate::binary::{ReadBytes, WriteBytes};
26use crate::error::{Result, RLibError};
27use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
28use crate::files::bmd::civilian_deployment_list::CivilianDeploymentList;
29use crate::files::bmd::civilian_shelter_list::CivilianShelterList;
30use crate::files::bmd_vegetation::grass_list::GrassList;
31use crate::files::bmd_vegetation::tree_list::TreeList;
32use crate::utils::check_size_mismatch;
33
34pub const TREE_LIST_EXTENSION: &str = ".tree_list.bin";
36
37pub const GRASS_LIST_EXTENSION: &str = ".grass_list.bin";
39
40pub const CIVILIAN_DEPLOYMENT_FILE_NAME: &str = "civilian_deployment.bin";
42
43pub const CIVILIAN_SHELTER_FILE_NAME: &str = "civilian_shelter.bin";
45
46pub const SIGNATURE: &[u8; 8] = b"FASTBIN0";
48
49const CIVILIAN_LIST_VERSION: u16 = 1;
51
52#[cfg(test)] mod fastbin_lists_test;
53
54#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
60#[getset(get = "pub", get_mut = "pub", set = "pub")]
61pub struct TreeListFile {
62 tree_list: TreeList,
63}
64
65#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
67#[getset(get = "pub", get_mut = "pub", set = "pub")]
68pub struct GrassListFile {
69 grass_list: GrassList,
70}
71
72#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
74#[getset(get = "pub", get_mut = "pub", set = "pub")]
75pub struct CivilianDeploymentFile {
76 serialise_version: u16,
77 civilian_deployment_list: CivilianDeploymentList,
78}
79
80#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
82#[getset(get = "pub", get_mut = "pub", set = "pub")]
83pub struct CivilianShelterFile {
84 serialise_version: u16,
85 civilian_shelter_list: CivilianShelterList,
86}
87
88impl Decodeable for TreeListFile {
93
94 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
95 read_signature(data)?;
96 let tree_list = TreeList::decode(data, extra_data)?;
97 check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
98
99 Ok(Self { tree_list })
100 }
101}
102
103impl Encodeable for TreeListFile {
104
105 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
106 buffer.write_all(SIGNATURE)?;
107 self.tree_list.encode(buffer, extra_data)
108 }
109}
110
111impl Decodeable for GrassListFile {
112
113 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
114 read_signature(data)?;
115 let grass_list = GrassList::decode(data, extra_data)?;
116 check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
117
118 Ok(Self { grass_list })
119 }
120}
121
122impl Encodeable for GrassListFile {
123
124 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
125 buffer.write_all(SIGNATURE)?;
126 self.grass_list.encode(buffer, extra_data)
127 }
128}
129
130impl Decodeable for CivilianDeploymentFile {
131
132 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
133 read_signature(data)?;
134 let serialise_version = read_civilian_list_version(data, "CivilianDeploymentFile")?;
135 let civilian_deployment_list = CivilianDeploymentList::decode(data, extra_data)?;
136 check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
137
138 Ok(Self { serialise_version, civilian_deployment_list })
139 }
140}
141
142impl Encodeable for CivilianDeploymentFile {
143
144 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
145 buffer.write_all(SIGNATURE)?;
146 buffer.write_u16(self.serialise_version)?;
147 self.civilian_deployment_list.encode(buffer, extra_data)
148 }
149}
150
151impl Decodeable for CivilianShelterFile {
152
153 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
154 read_signature(data)?;
155 let serialise_version = read_civilian_list_version(data, "CivilianShelterFile")?;
156 let civilian_shelter_list = CivilianShelterList::decode(data, extra_data)?;
157 check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
158
159 Ok(Self { serialise_version, civilian_shelter_list })
160 }
161}
162
163impl Encodeable for CivilianShelterFile {
164
165 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
166 buffer.write_all(SIGNATURE)?;
167 buffer.write_u16(self.serialise_version)?;
168 self.civilian_shelter_list.encode(buffer, extra_data)
169 }
170}
171
172fn read_signature<R: ReadBytes>(data: &mut R) -> Result<()> {
174 let signature = data.read_slice(8, false)?;
175 if signature.as_slice() != SIGNATURE {
176 return Err(RLibError::DecodingFastBinUnsupportedSignature(signature));
177 }
178
179 Ok(())
180}
181
182fn read_civilian_list_version<R: ReadBytes>(data: &mut R, file_type: &str) -> Result<u16> {
184 let version = data.read_u16()?;
185 if version != CIVILIAN_LIST_VERSION {
186 return Err(RLibError::DecodingFastBinUnsupportedVersion(file_type.to_owned(), version));
187 }
188
189 Ok(version)
190}