paramdex_rs/lib.rs
1
2//! Utilities for handling and deserializing a Paramdex for modifying Souls games.
3//!
4//! Entry points for the library include:
5//! - [`Paramdex::deserialize_all`] - For deserializing an entire Paramdex
6//! - [`deserialize::deserialize_def`] - For deserializing a single Paramdef from a Paramdex
7//! - [`Paramdex::empty`] - For starting with an empty Paramdex to insert defs into.
8
9
10/// Utilities for deserializing [ParamDef]s from XML. Input should be from
11/// [soulsmods/Paramdex](https://github.com/soulsmods/Paramdex).
12pub mod deserialize;
13
14use std::collections::HashMap;
15use crate::deserialize::ParamdefDeserializeError;
16
17/// A simple mapping from param type to a [ParamDef]
18pub struct Paramdex {
19 /// internal backing map for [ParamDef]s
20 definitions: HashMap<String, ParamDef>,
21}
22
23impl Paramdex {
24 /// Insert a new [ParamDef] into the Paramdex
25 pub fn insert(&mut self, paramdef: ParamDef) -> Option<ParamDef> {
26 self.definitions.insert(paramdef.param_type.clone(), paramdef)
27 }
28
29 /// Retrieve a [ParamDef] based on a param type (encoded into params)
30 /// The relevant definition must first be inserted into the paramdex by using [`Paramdex::insert`]
31 /// or by deserializing the Paramdex.
32 ///
33 /// # See also
34 /// [`Paramdex::deserialize_all`]
35 pub fn get_param_def(&self, key: &str) -> Option<&ParamDef> {
36 self.definitions.get(key)
37 }
38
39 /// Deserialize a whole Paramdex from an iterator of &str
40 pub fn deserialize_all<I: IntoIterator<Item = S>, S: AsRef<str>>(input_iter: I) -> Result<Paramdex, ParamdefDeserializeError> {
41 let mut paramdex = Paramdex { definitions: HashMap::new() };
42
43 for input in input_iter {
44 let input = input.as_ref();
45 paramdex.insert(deserialize::deserialize_def(input)?);
46 }
47 Ok(paramdex)
48 }
49
50 /// Creates an empty Paramdex.
51 pub fn empty() -> Paramdex { Paramdex { definitions: HashMap::new() } }
52}
53
54/// The text format for descriptions in the [ParamDef]
55pub enum ParamdefFormat {
56 UTF16,
57 ShiftJIS,
58}
59
60/// The endianness of the specific [ParamDef]
61pub enum ParamdefEndian {
62 Little,
63 Big,
64}
65
66/// A definition for the format of a param file
67pub struct ParamDef {
68 /// The internal type key for the parameter
69 pub param_type: String,
70
71 /// The data version declared for the param
72 pub data_version: u32,
73
74 /// The endianness declared for the param
75 pub endian: ParamdefEndian,
76
77 /// The string encoding declared for the param
78 pub string_format: ParamdefFormat,
79
80 /// The version of the format for the XML
81 pub format_version: u32,
82
83 /// The fields present in the param. Ordered.
84 pub fields: Vec<ParamField>
85}
86
87/// The data type definition for a parameter field
88#[derive(Debug)]
89pub struct ParamFieldDef {
90 pub field_type: ParamFieldType,
91 pub name: String,
92 pub default_value: Option<f64>,
93}
94
95/// Declared metadata about fields in a param
96pub struct ParamField {
97 /// The definition of the field, including type and internal name, among others.
98 pub field_def: ParamFieldDef,
99
100 /// A user-friends display name.
101 pub display_name: Option<String>,
102
103 /// A type of enum declared by a paramdex that can be applied to this field. Unused.
104 pub enum_tdf: Option<String>,
105
106 /// A user-friendly description
107 pub description: Option<String>,
108
109 /// A printf(3) compatible format string for printing the data in this field. Unused.
110 pub printf_format: Option<String>,
111
112 /// Flags that inform a potential editor how to handle this field. Unused.
113 pub edit_flags: Option<EditFlags>,
114
115 /// Minimum value allowed to be input in an editor. Unused.
116 pub minimum: Option<f64>,
117
118 /// Maximum value allowed to be input in an editor. Unused.
119 pub maximum: Option<f64>,
120
121 /// Increment value allowed to be input in an editor. Unused.
122 pub increment: Option<f64>,
123
124 /// Declares sorting for a potential editor. Unused.
125 pub sort_id: Option<usize>,
126}
127
128/// Flags used in editors to control user input behavior
129pub struct EditFlags {
130 pub wrap: bool,
131 pub lock: bool,
132}
133
134/// Type of field present in the param
135///
136/// \[su\]\(8\|16\|32\) are integer types, signed and unsigned respectively, with the
137/// appropriate bit sizes.
138#[allow(non_camel_case_types)]
139#[derive(PartialEq, Debug)]
140pub enum ParamFieldType {
141 /// Signed integer with size of 8 bits
142 s8,
143
144 /// Unsigned integer with size of 8 bits
145 u8 {
146 /// Optionally limited to number of bits to be read
147 bit_size: Option<u8>
148 },
149
150 /// Signed integer with size of 16 bits
151 s16,
152
153 /// Unsigned integer with size of 16 bits
154 u16 {
155 /// Optionally limited to number of bits to be read
156 bit_size: Option<u8>
157 },
158
159 /// Signed integer with size of 32 bits
160 s32,
161
162 /// Unsigned integer with size of 32 bits
163 u32 {
164 /// Optionally limited to number of bits to be read
165 bit_size: Option<u8>
166 },
167
168 /// Boolean value represented with 32 bits. 0 == `false`, !0 == `true`.
169 b32,
170
171 /// Single-precision floating point
172 f32,
173
174 /// Single-precision floating point, but this time references an angle. No real difference to [`ParamFieldType::f32`]
175 a32,
176
177 /// Double-precision floating point
178 f64,
179
180 /// Fixed-length string encoded in ShiftJIS.
181 fixstr {
182 /// Length of fixed-length string
183 length: usize,
184 },
185
186 /// Fixed-length string encoded in UTF16.
187 fixstrW {
188 /// Length of fixed-length string
189 length: usize,
190 },
191
192 /// Unused or unknown bytes or bits, likely used for padding
193 dummy8 {
194 /// Length of dummy data. 1 byte if `None`.
195 length: Option<DummyType>
196 },
197}
198
199/// Enum for type of dummy data
200#[derive(PartialEq, Debug)]
201pub enum DummyType {
202 /// Dummy data is in bytes, with a defined length
203 Bytes(usize),
204
205 /// Dummy data is in bits, with a defined length
206 Bits(u8),
207}
208
209impl ParamFieldType {
210 /// Sets the bit size of a field type, on field types that support variable bit lengths.
211 ///
212 /// # Panics
213 /// Panics when the field type does not support bit size definitions. See [`ParamFieldType::supports_bit_size`]
214 pub fn set_bit_size(&mut self, new_bit_size: u8) {
215 match self {
216 Self::u8 {bit_size} | Self::u16 {bit_size} | Self::u32 {bit_size} => {
217 bit_size.replace(new_bit_size)
218 }
219 _ => panic!("Bit size not supported"),
220 };
221 }
222
223 /// Whether the given field type supports bit size definitions
224 pub fn supports_bit_size(&self) -> bool {
225 match self {
226 Self::u8 {..} | Self::u16 {..} | Self::u32 {..} => true,
227 _ => false,
228 }
229 }
230}