rpfm_lib/files/bmd/common/properties/mod.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
11//! Building and entity property definitions for BMD files.
12//!
13//! This module defines the [`Properties`] structure containing various properties
14//! that control building behavior, gameplay mechanics, and rendering settings.
15//!
16//! # Property Categories
17//!
18//! - **State**: `on_fire`, `start_disabled`, `starting_damage_unary`
19//! - **Gameplay**: `weak_point`, `ai_breachable`, `indestructible`, `dockable`, `toggleable`
20//! - **Rendering**: `lite`, `cast_shadows`, `clamp_to_surface`, `include_in_fog`
21//! - **Strategic**: `key_building`, `key_building_use_fort`, `settlement_level_configurable`
22//! - **Misc**: `dont_merge_building`, `is_prop_in_outfield`, `hide_tooltip`, `tint_inherit_from_parent`
23//!
24//! # Supported Versions
25//!
26//! - **Version 4**: Early format
27//! - **Version 6**: Mid format
28//! - **Version 7**: Enhanced format
29//! - **Version 11**: Current format
30//!
31//! # Usage
32//!
33//! ```ignore
34//! use rpfm_lib::files::bmd::common::properties::Properties;
35//! use rpfm_lib::files::Decodeable;
36//!
37//! let properties = Properties::decode(&mut reader, &None)?;
38//! println!("Building ID: {}", properties.building_id());
39//! if *properties.indestructible() {
40//! println!("This building cannot be destroyed");
41//! }
42//! ```
43
44use getset::*;
45use serde_derive::{Serialize, Deserialize};
46
47use crate::binary::{ReadBytes, WriteBytes};
48use crate::error::{Result, RLibError};
49use crate::files::{Decodeable, EncodeableExtraData, Encodeable};
50
51use super::*;
52
53mod v4;
54mod v6;
55mod v7;
56mod v11;
57
58//---------------------------------------------------------------------------//
59// Enum & Structs
60//---------------------------------------------------------------------------//
61
62/// Building and entity properties controlling behavior and rendering.
63///
64/// This structure contains a comprehensive set of properties that define how
65/// buildings and entities behave in the game, including damage states, AI
66/// interactions, rendering settings, and strategic importance.
67///
68/// # Property Categories
69///
70/// ## State Properties
71/// - `building_id`: Unique identifier for the building
72/// - `starting_damage_unary`: Initial damage level (0.0 = undamaged, 1.0 = destroyed)
73/// - `on_fire`: Whether the building starts on fire
74/// - `start_disabled`: Whether the building starts in disabled state
75///
76/// ## Gameplay Properties
77/// - `weak_point`: Whether this is a weak point for siege battles
78/// - `ai_breachable`: Whether AI can breach through this building
79/// - `indestructible`: Whether the building cannot be destroyed
80/// - `dockable`: Whether siege engines can dock at this building
81/// - `toggleable`: Whether the building can be toggled on/off
82///
83/// ## Rendering Properties
84/// - `lite`: Use simplified rendering (lower detail)
85/// - `clamp_to_surface`: Clamp building position to terrain surface
86/// - `cast_shadows`: Whether the building casts shadows
87/// - `include_in_fog`: Whether the building is affected by fog of war
88/// - `tint_inherit_from_parent`: Inherit color tint from parent entity
89///
90/// ## Strategic Properties
91/// - `key_building`: Whether this is a key strategic building
92/// - `key_building_use_fort`: Whether key building uses fort mechanics
93/// - `settlement_level_configurable`: Whether properties vary by settlement level
94///
95/// ## Miscellaneous
96/// - `dont_merge_building`: Prevent building mesh merging optimization
97/// - `is_prop_in_outfield`: Whether this prop is in the outfield area
98/// - `hide_tooltip`: Hide tooltip UI for this building
99///
100/// # Example
101///
102/// ```ignore
103/// use rpfm_lib::files::bmd::common::properties::Properties;
104///
105/// let mut props = Properties::default();
106/// props.set_serialise_version(11);
107/// props.set_building_id("main_gate".to_string());
108/// props.set_indestructible(false);
109/// props.set_weak_point(true);
110/// props.set_starting_damage_unary(0.0);
111/// ```
112#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
113#[getset(get = "pub", get_mut = "pub", set = "pub")]
114pub struct Properties {
115 /// Format version number (4, 6, 7, or 11).
116 serialise_version: u16,
117
118 /// Unique identifier for this building.
119 building_id: String,
120
121 /// Initial damage level (0.0 = undamaged, 1.0 = destroyed).
122 starting_damage_unary: f32,
123
124 /// Whether the building starts on fire.
125 on_fire: bool,
126
127 /// Whether the building starts in disabled state.
128 start_disabled: bool,
129
130 /// Whether this is a weak point for siege battles.
131 weak_point: bool,
132
133 /// Whether AI can breach through this building.
134 ai_breachable: bool,
135
136 /// Whether the building cannot be destroyed.
137 indestructible: bool,
138
139 /// Whether siege engines can dock at this building.
140 dockable: bool,
141
142 /// Whether the building can be toggled on/off.
143 toggleable: bool,
144
145 /// Use simplified rendering (lower detail).
146 lite: bool,
147
148 /// Clamp building position to terrain surface.
149 clamp_to_surface: bool,
150
151 /// Whether the building casts shadows.
152 cast_shadows: bool,
153
154 /// Prevent building mesh merging optimization.
155 dont_merge_building: bool,
156
157 /// Whether this is a key strategic building.
158 key_building: bool,
159
160 /// Whether key building uses fort mechanics.
161 key_building_use_fort: bool,
162
163 /// Whether this prop is in the outfield area.
164 is_prop_in_outfield: bool,
165
166 /// Whether properties vary by settlement level.
167 settlement_level_configurable: bool,
168
169 /// Hide tooltip UI for this building.
170 hide_tooltip: bool,
171
172 /// Whether the building is affected by fog of war.
173 include_in_fog: bool,
174
175 /// Inherit color tint from parent entity.
176 tint_inherit_from_parent: bool,
177}
178
179//---------------------------------------------------------------------------//
180// Implementation of Properties
181//---------------------------------------------------------------------------//
182
183impl Decodeable for Properties {
184
185 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
186 let mut flags = Self::default();
187 flags.serialise_version = data.read_u16()?;
188
189 match flags.serialise_version {
190 4 => flags.read_v4(data, extra_data)?,
191 6 => flags.read_v6(data, extra_data)?,
192 7 => flags.read_v7(data, extra_data)?,
193 11 => flags.read_v11(data, extra_data)?,
194 _ => return Err(RLibError::DecodingFastBinUnsupportedVersion(String::from("Properties"), flags.serialise_version)),
195 }
196
197 Ok(flags)
198 }
199}
200
201impl Encodeable for Properties {
202
203 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
204 buffer.write_u16(self.serialise_version)?;
205
206 match self.serialise_version {
207 4 => self.write_v4(buffer, extra_data)?,
208 6 => self.write_v6(buffer, extra_data)?,
209 7 => self.write_v7(buffer, extra_data)?,
210 11 => self.write_v11(buffer, extra_data)?,
211 _ => return Err(RLibError::EncodingFastBinUnsupportedVersion(String::from("Properties"), self.serialise_version)),
212 }
213
214 Ok(())
215 }
216}