rpfm_lib/files/sound_events/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//! Sound events configuration for older Total War games.
12//!
13//! This module handles the `sound_events` file found in Shogun 2, Napoleon, and Empire.
14//! These files define sound event categories, event records, ambience maps, and movie
15//! audio settings used by the game's audio system.
16//!
17//! These files are not versioned, so only the latest format per game is supported.
18
19use getset::*;
20use serde_derive::{Serialize, Deserialize};
21
22use crate::binary::{ReadBytes, WriteBytes};
23use crate::error::{Result, RLibError};
24use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
25use crate::games::supported_games::{KEY_SHOGUN_2, KEY_EMPIRE};
26use crate::utils::check_size_mismatch;
27
28/// Path to the sound events file within a pack.
29pub const PATH: &str = "sounds_packed/sound_events";
30
31mod games;
32
33#[cfg(test)] mod sound_events_test;
34
35//---------------------------------------------------------------------------//
36// Enum & Structs
37//---------------------------------------------------------------------------//
38
39/// Sound events configuration for a game.
40///
41/// Contains the complete audio event system configuration including categories,
42/// event definitions, ambience mappings, and movie audio settings.
43///
44/// Note: Many fields in this format are not fully understood and are marked as `uk_*`.
45#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
46#[getset(get = "pub", get_mut = "pub", set = "pub")]
47pub struct SoundEvents {
48 /// Master volume level for all sounds.
49 master_volume: f32,
50 /// Sound categories (e.g., music, SFX, voice).
51 categories: Vec<Category>,
52 /// Unknown data section 1.
53 uk_1: Vec<Uk1>,
54 /// Unknown data section 4.
55 uk_4: Vec<Uk4>,
56 /// Unknown data section 5.
57 uk_5: Vec<Uk5>,
58 /// Unknown value 6.
59 uk_6: u32,
60 /// Unknown value 7.
61 uk_7: u32,
62 /// Unknown data section 8.
63 uk_8: Vec<Uk8>,
64 /// Event data parameters referenced by event records.
65 event_data: Vec<EventData>,
66 /// Sound event definitions.
67 event_records: Vec<EventRecord>,
68 /// Ambience sound mappings.
69 ambience_map: Vec<AmbienceMap>,
70 /// Unknown data section 3.
71 uk_3: Vec<Uk3>,
72 /// Movie audio configurations.
73 movies: Vec<Movie>,
74 /// Unknown data section 9.
75 uk_9: Vec<Uk9>,
76}
77
78/// A sound category definition.
79///
80/// Categories group related sounds together for volume control and management.
81#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
82#[getset(get = "pub", get_mut = "pub", set = "pub")]
83pub struct Category {
84 /// Name of the category.
85 name: String,
86 /// Unknown parameter (possibly volume or priority).
87 uk_1: f32,
88}
89
90/// Unknown data structure 1.
91#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
92#[getset(get = "pub", get_mut = "pub", set = "pub")]
93pub struct Uk1 {
94 /// Unknown value.
95 uk_1: i32,
96}
97
98/// Unknown data structure 4.
99#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
100#[getset(get = "pub", get_mut = "pub", set = "pub")]
101pub struct Uk4 {
102 /// Unknown value 1.
103 uk_1: i32,
104 /// Unknown value 2.
105 uk_2: i32,
106}
107
108/// Unknown data structure 5 with float parameters.
109#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
110#[getset(get = "pub", get_mut = "pub", set = "pub")]
111pub struct Uk5 {
112 /// Unknown float 1.
113 uk_1: f32,
114 /// Unknown float 2.
115 uk_2: f32,
116 /// Unknown float 3.
117 uk_3: f32,
118 /// Unknown float 4.
119 uk_4: f32,
120 /// Unknown float 5.
121 uk_5: f32,
122 /// Unknown float 6.
123 uk_6: f32,
124 /// Unknown float 7.
125 uk_7: f32,
126 /// Unknown float 8.
127 uk_8: f32,
128}
129
130/// Unknown data structure 8.
131#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
132#[getset(get = "pub", get_mut = "pub", set = "pub")]
133pub struct Uk8 {
134 /// Unknown value.
135 uk_1: u32,
136}
137
138/// Event data parameters.
139///
140/// Contains a large set of float parameters that define audio playback characteristics.
141/// The exact meaning of each parameter is not fully understood.
142#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
143#[getset(get = "pub", get_mut = "pub", set = "pub")]
144pub struct EventData {
145 /// Unknown parameter 1.
146 uk_1: f32,
147 /// Unknown parameter 2.
148 uk_2: f32,
149 /// Unknown parameter 3.
150 uk_3: f32,
151 /// Unknown parameter 4.
152 uk_4: f32,
153 /// Unknown parameter 5.
154 uk_5: f32,
155 /// Unknown parameter 6.
156 uk_6: f32,
157 /// Unknown parameter 7.
158 uk_7: f32,
159 /// Unknown parameter 8.
160 uk_8: f32,
161 /// Unknown parameter 9.
162 uk_9: f32,
163 /// Unknown parameter 10.
164 uk_10: f32,
165 /// Unknown parameter 11.
166 uk_11: f32,
167 /// Unknown parameter 12.
168 uk_12: f32,
169 /// Unknown parameter 13.
170 uk_13: f32,
171 /// Unknown parameter 14.
172 uk_14: f32,
173 /// Unknown parameter 15.
174 uk_15: f32,
175 /// Unknown parameter 16.
176 uk_16: f32,
177 /// Unknown parameter 17.
178 uk_17: f32,
179 /// Unknown parameter 18.
180 uk_18: f32,
181 /// Unknown parameter 19.
182 uk_19: f32,
183 /// Unknown parameter 20.
184 uk_20: f32,
185 /// Unknown parameter 21.
186 uk_21: f32,
187 /// Unknown parameter 22.
188 uk_22: f32,
189 /// Unknown parameter 23.
190 uk_23: f32,
191 /// Unknown parameter 24.
192 uk_24: f32,
193 /// Unknown parameter 25.
194 uk_25: f32,
195 /// Unknown parameter 26.
196 uk_26: f32,
197 /// Unknown parameter 27.
198 uk_27: f32,
199 /// Unknown parameter 28.
200 uk_28: f32,
201 /// Unknown parameter 29.
202 uk_29: f32,
203 /// Unknown parameter 30.
204 uk_30: f32,
205 /// Unknown parameter 31.
206 uk_31: f32,
207 /// Unknown parameter 32.
208 uk_32: f32,
209 /// Unknown parameter 33.
210 uk_33: f32,
211 /// Unknown parameter 34.
212 uk_34: f32,
213 /// Unknown parameter 35.
214 uk_35: f32,
215 /// Unknown parameter 36.
216 uk_36: f32,
217 /// Unknown parameter 37.
218 uk_37: f32,
219 /// Unknown parameter 38.
220 uk_38: f32,
221 /// Unknown parameter 39.
222 uk_39: f32,
223 /// Unknown parameter 40.
224 uk_40: f32,
225 /// Unknown parameter 41.
226 uk_41: f32,
227 /// Unknown parameter 42.
228 uk_42: f32,
229 /// Unknown parameter 43.
230 uk_43: f32,
231 /// Unknown parameter 44.
232 uk_44: f32,
233 /// Unknown parameter 45.
234 uk_45: f32,
235 /// Unknown parameter 46.
236 uk_46: f32,
237 /// Unknown parameter 47.
238 uk_47: f32,
239}
240
241/// A sound event record.
242///
243/// Defines a triggerable sound event that references sound files and event data parameters.
244#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
245#[getset(get = "pub", get_mut = "pub", set = "pub")]
246pub struct EventRecord {
247 /// Index of the category this event belongs to.
248 category: u32,
249 /// Optional name of the event.
250 name: Option<String>,
251 /// Unknown value 1.
252 uk_1: u32,
253 /// Unknown value 2.
254 uk_2: i32,
255 /// Unknown value 3.
256 uk_3: i32,
257 /// Index into the event_data array for this event's parameters.
258 event_data_index: u32,
259 /// Unknown value 4.
260 uk_4: u8,
261 /// List of sound file paths associated with this event.
262 sounds: Vec<String>,
263}
264
265/// An ambience map definition.
266///
267/// Maps ambience names to collections of ambience records for environmental audio.
268#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
269#[getset(get = "pub", get_mut = "pub", set = "pub")]
270pub struct AmbienceMap {
271 /// Name of the ambience map.
272 name: String,
273 /// Ambience records within this map.
274 records: Vec<AmbienceRecord>,
275}
276
277/// An ambience record within an ambience map.
278///
279/// Links to an event and contains spatial/volume parameters for ambient sounds.
280#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
281#[getset(get = "pub", get_mut = "pub", set = "pub")]
282pub struct AmbienceRecord {
283 /// Unknown value 1.
284 uk_1: u32,
285 /// Index into the event_records array.
286 event_index: u32,
287 /// Unknown float 3.
288 uk_3: f32,
289 /// Unknown float 4.
290 uk_4: f32,
291 /// Unknown float 5.
292 uk_5: f32,
293 /// Unknown float 6.
294 uk_6: f32,
295 /// Unknown float 7.
296 uk_7: f32,
297 /// Unknown float 8.
298 uk_8: f32,
299}
300
301/// Unknown data structure 3.
302#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
303#[getset(get = "pub", get_mut = "pub", set = "pub")]
304pub struct Uk3 {
305 /// Unknown value.
306 uk_1: i32,
307}
308
309/// Movie audio configuration.
310///
311/// Associates a movie file with its audio volume setting.
312#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
313#[getset(get = "pub", get_mut = "pub", set = "pub")]
314pub struct Movie {
315 /// Path to the movie file.
316 file: String,
317 /// Volume level for the movie's audio.
318 volume: f32,
319}
320
321/// Unknown data structure 9 with file reference.
322#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
323#[getset(get = "pub", get_mut = "pub", set = "pub")]
324pub struct Uk9 {
325 /// Path to a file.
326 file: String,
327 /// Unknown value.
328 uk_1: i32,
329}
330
331//---------------------------------------------------------------------------//
332// Implementations
333//---------------------------------------------------------------------------//
334
335impl Decodeable for SoundEvents {
336
337 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
338 let extra_data = extra_data.as_ref().ok_or(RLibError::DecodingMissingExtraData)?;
339 let game_info = extra_data.game_info.ok_or_else(|| RLibError::DecodingMissingExtraDataField("game_info".to_owned()))?;
340
341 let mut sound_events = Self::default();
342
343 match game_info.key() {
344 KEY_SHOGUN_2 => sound_events.read_sho2(data)?,
345 //KEY_NAPOLEON => {},
346 KEY_EMPIRE => sound_events.read_emp(data)?,
347 _ => return Err(RLibError::DecodingSoundPackedUnsupportedGame(game_info.key().to_string())),
348 }
349
350 // If we are not in the last byte, it means we didn't parse the entire file, which means this file is corrupt.
351 check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
352
353 Ok(sound_events)
354 }
355}
356
357impl Encodeable for SoundEvents {
358
359 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
360 let extra_data = extra_data.as_ref().ok_or(RLibError::EncodingMissingExtraData)?;
361 let game_info = extra_data.game_info.ok_or_else(|| RLibError::DecodingMissingExtraDataField("game_info".to_owned()))?;
362
363 match game_info.key() {
364 KEY_SHOGUN_2 => self.write_sho2(buffer),
365 //KEY_NAPOLEON => {},
366 KEY_EMPIRE => self.write_emp(buffer),
367 _ => Err(RLibError::EncodingSoundPackedUnsupportedGame(game_info.key().to_string())),
368 }
369 }
370}