rpfm_lib/files/portrait_settings/
mod.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2024 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
11//! This is a module to read/write binary Portrait Settings files.
12//!
13//! Portrait settings are files containing information about the small portrait each unit uses,
14//! tipically at the bottom left of the screen (may vary from game to game) or in the Character Screen in campaign.
15//!
16//! TODO: add format info.
17
18use getset::*;
19use serde_derive::{Serialize, Deserialize};
20
21use crate::error::{Result, RLibError};
22use crate::binary::{ReadBytes, WriteBytes};
23use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
24use crate::utils::check_size_mismatch;
25
26/// Extension used by PortraitSettings.
27pub const EXTENSION: &str = ".bin";
28
29mod versions;
30
31#[cfg(test)] mod portrait_settings_test;
32
33//---------------------------------------------------------------------------//
34//                              Enum & Structs
35//---------------------------------------------------------------------------//
36
37/// This represents an entire PortraitSettings decoded in memory.
38#[derive(PartialEq, Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)]
39#[getset(get = "pub", get_mut = "pub", set = "pub")]
40pub struct PortraitSettings {
41
42    /// Version of the PortraitSettings.
43    version: u32,
44
45    /// Entries on the PortraitSettings.
46    entries: Vec<Entry>,
47}
48
49/// This represents a generic Portrait Settings Entry.
50#[derive(PartialEq, Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)]
51#[getset(get = "pub", get_mut = "pub", set = "pub")]
52pub struct Entry {
53
54    /// Id of the entry. Points to an art set key.
55    id: String,
56
57    /// Settings for the head camera.
58    ///
59    /// This is the porthole camera you see in campaign, at the bottom left.
60    camera_settings_head: CameraSetting,
61
62    /// Settings for the body camera. Optional.
63    ///
64    /// This is the camera used for displaying the full body of the character in their details window in campaign.
65    /// This is only needed for characters. Regular units do not have access to the characters window, so it's not needed for them.
66    camera_settings_body: Option<CameraSetting>,
67
68    /// Variants? Need more info about this.
69    variants: Vec<Variant>
70}
71
72/// This represents a Camera setting of a Portrait.
73///
74/// Note that the camera has an auto-level feature, so the camera may autorotate to compensate vertical rotation (pitch)
75/// greater than 90/-90 degrees.
76#[derive(PartialEq, Clone, Debug, Default, Getters, MutGetters, Setters, Serialize, Deserialize)]
77#[getset(get = "pub", get_mut = "pub", set = "pub")]
78pub struct CameraSetting {
79
80    /// Distance from the character to the camera.
81    z: f32,
82
83    /// Vertical displacement of the camera.
84    y: f32,
85
86    /// Rotation angle of the camera, sideways. In degrees.
87    yaw: f32,
88
89    /// Rotation angle of the camera, vertically. In degrees.
90    pitch: f32,
91
92    /// Only in V1.
93    distance: f32,
94
95    /// Only in V1.
96    theta: f32,
97
98    /// Only in V1.
99    phi: f32,
100
101    /// Field of View.
102    fov: f32,
103
104    /// Skeleton node that the camera will use as default focus point.
105    ///
106    /// Optional. If provided, all displacementes/rotations are relative to this point.
107    skeleton_node: String,
108}
109
110/// This represents a generic variant of a Portrait.
111#[derive(PartialEq, Eq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
112#[getset(get = "pub", get_mut = "pub", set = "pub")]
113pub struct Variant {
114
115    /// Variant Filename. Points to the column of the same name in the Variants table.
116    filename: String,
117
118    /// Path of the diffuse image of the Variant.
119    file_diffuse: String,
120
121    /// No idea. Optional.
122    file_mask_1: String,
123
124    /// No idea. Optional.
125    file_mask_2: String,
126
127    /// No idea. Optional.
128    file_mask_3: String,
129
130    /// Only in v1.
131    season: String,
132
133    /// Only in v1.
134    level: i32,
135
136    /// Only in v1.
137    age: i32,
138
139    /// Only in v1.
140    politician: bool,
141
142    /// Only in v1.
143    faction_leader: bool,
144}
145
146//---------------------------------------------------------------------------//
147//                       Implementation of PortraitSettings
148//---------------------------------------------------------------------------//
149
150impl Decodeable for PortraitSettings {
151
152    fn decode<R: ReadBytes>(data: &mut R, _extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
153        let version = data.read_u32()?;
154
155        let mut settings = Self::default();
156        settings.version = version;
157
158        match version {
159            1 => settings.read_v1(data)?,
160            4 => settings.read_v4(data)?,
161            _ => Err(RLibError::DecodingPortraitSettingUnsupportedVersion(version as usize))?,
162        }
163
164        // Trigger an error if there's left data on the source.
165        check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
166
167        Ok(settings)
168    }
169}
170
171impl Encodeable for PortraitSettings {
172
173    fn encode<W: WriteBytes>(&mut self, buffer: &mut W, _extra_data: &Option<EncodeableExtraData>) -> Result<()> {
174        buffer.write_u32(self.version)?;
175
176        match self.version {
177            1 => self.write_v1(buffer)?,
178            4 => self.write_v4(buffer)?,
179            _ => unimplemented!()
180        }
181
182        Ok(())
183    }
184}
185
186
187impl PortraitSettings {
188
189    pub fn from_json(data: &str) -> Result<Self> {
190        serde_json::from_str(data).map_err(From::from)
191    }
192
193    pub fn to_json(&self) -> Result<String> {
194        serde_json::to_string_pretty(&self).map_err(From::from)
195    }
196}
197
198impl Default for Variant {
199    fn default() -> Self {
200        Self {
201            filename: Default::default(),
202            file_diffuse: Default::default(),
203            file_mask_1: Default::default(),
204            file_mask_2: Default::default(),
205            file_mask_3: Default::default(),
206            season: "none".to_owned(),
207            level: Default::default(),
208            age: Default::default(),
209            politician: Default::default(),
210            faction_leader: Default::default(),
211        }
212    }
213}