Skip to main content

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