use getset::*;
use serde_derive::{Serialize, Deserialize};
use crate::error::{RLibError, Result};
use crate::binary::{ReadBytes, WriteBytes};
use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
use crate::utils::check_size_mismatch;
const SIGNATURE: &str = "VRNT";
const HEADER_LENGTH_V1: u32 = 20;
const HEADER_LENGTH_V2: u32 = 24;
pub const EXTENSION: &str = ".unit_variant";
#[cfg(test)] mod unit_variant_test;
#[derive(Eq, PartialEq, Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct UnitVariant {
version: u32,
unknown_1: u32,
categories: Vec<Category>,
}
#[derive(Eq, PartialEq, Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct Category {
name: String,
id: u64,
variants: Vec<Variant>,
}
#[derive(Eq, PartialEq, Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct Variant {
mesh_file: String,
texture_folder: String,
unknown_value: u16
}
impl UnitVariant {
fn read_header<R: ReadBytes>(data: &mut R) -> Result<(u32, u32, u32)> {
let signature = data.read_string_u8(SIGNATURE.len())?;
if signature != SIGNATURE {
return Err(RLibError::DecodingUnitVariantNotAUnitVariant)
}
let version = data.read_u32()?;
let categories_count = data.read_u32()?;
let _categories_index = data.read_u32()?;
let _variants_index = data.read_u32()?;
let unknown_1 = if version == 2 { data.read_u32()? } else { 0 };
Ok((version, categories_count, unknown_1))
}
pub fn get_header_size(&self) -> u32 {
if self.version == 2 { HEADER_LENGTH_V2 } else { HEADER_LENGTH_V1 }
}
}
impl Decodeable for UnitVariant {
fn decode<R: ReadBytes>(data: &mut R, _extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
let (version, categories_count, unknown_1) = Self::read_header(data)?;
let mut categories = Vec::with_capacity(categories_count as usize);
for _ in 0..categories_count {
let name = data.read_string_u16_0padded(512)?;
let id = data.read_u64()?;
let variants_on_this_category = data.read_u32()?;
let _variants_before_this_category = data.read_u32()?;
let category = Category {
name,
id,
variants: Vec::with_capacity(variants_on_this_category as usize),
};
categories.push(category)
}
for category in &mut categories {
for _ in 0..category.variants.capacity() {
let mesh_file = data.read_string_u16_0padded(512)?;
let texture_folder = data.read_string_u16_0padded(512)?;
let unknown_value = data.read_u16()?;
category.variants.push(Variant {
mesh_file,
texture_folder,
unknown_value
});
}
}
check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
Ok(Self {
version,
unknown_1,
categories
})
}
}
impl Encodeable for UnitVariant {
fn encode<W: WriteBytes>(&mut self, buffer: &mut W, _extra_data: &Option<EncodeableExtraData>) -> Result<()> {
let mut encoded_variants = vec![];
let mut encoded_categories = vec![];
let mut variants_count = 0;
for category in &self.categories {
encoded_categories.write_string_u16_0padded(&category.name, 512, true)?;
encoded_categories.write_u64(category.id)?;
encoded_categories.write_u32(category.variants.len() as u32)?;
encoded_categories.write_u32(variants_count)?;
for variant in &category.variants {
encoded_variants.write_string_u16_0padded(&variant.mesh_file, 512, true)?;
encoded_variants.write_string_u16_0padded(&variant.texture_folder, 512, true)?;
encoded_variants.write_u16(variant.unknown_value)?;
}
variants_count += category.variants.len() as u32;
}
buffer.write_string_u8(SIGNATURE)?;
buffer.write_u32(self.version)?;
buffer.write_u32(self.categories.len() as u32)?;
buffer.write_u32(self.get_header_size())?;
buffer.write_u32(self.get_header_size() + encoded_categories.len() as u32)?;
if self.version == 2 {
buffer.write_u32(self.unknown_1)?;
}
buffer.write_all(&encoded_categories)?;
buffer.write_all(&encoded_variants)?;
Ok(())
}
}