1use csv::{StringRecordsIter, Writer};
63use getset::Getters;
64use itertools::Itertools;
65#[cfg(feature = "integration_sqlite")]use r2d2::Pool;
66#[cfg(feature = "integration_sqlite")]use r2d2_sqlite::SqliteConnectionManager;
67use rayon::prelude::*;
68use serde_derive::{Serialize, Deserialize};
69use uuid::Uuid;
70
71use std::borrow::Cow;
72#[cfg(test)] use std::collections::BTreeMap;
73use std::collections::{HashMap, HashSet};
74use std::fs::File;
75use std::io::SeekFrom;
76
77use crate::binary::{ReadBytes, WriteBytes};
78use crate::error::{RLibError, Result};
79use crate::files::{Container, ContainerPath, DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable, FileType, table::{decode_table, DecodedData, local::TableInMemory, Table}, pack::Pack, RFileDecoded};
80#[cfg(test)] use crate::schema::FieldType;
81use crate::schema::{Definition, DefinitionPatch, Field, Schema};
82use crate::utils::check_size_mismatch;
83
84const GUID_MARKER: &[u8] = &[253, 254, 252, 255];
86
87const VERSION_MARKER: &[u8] = &[252, 253, 254, 255];
89
90#[cfg(test)] mod db_test;
91
92#[derive(PartialEq, Clone, Debug, Getters, Serialize, Deserialize)]
146#[getset(get = "pub")]
147pub struct DB {
148
149 mysterious_byte: bool,
153
154 guid: String,
158
159 table: TableInMemory,
161}
162
163impl Decodeable for DB {
168
169 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
170 let extra_data = extra_data.as_ref().ok_or(RLibError::DecodingMissingExtraData)?;
171 let schema = extra_data.schema.ok_or_else(|| RLibError::DecodingMissingExtraDataField("schema".to_owned()))?;
172 let table_name = extra_data.table_name.ok_or_else(|| RLibError::DecodingMissingExtraDataField("table_name".to_owned()))?;
173 let return_incomplete = extra_data.return_incomplete;
174
175 let (version, mysterious_byte, guid, entry_count) = Self::read_header(data)?;
176
177 let definitions = schema.definitions_by_table_name(table_name).ok_or({
179 if entry_count == 0 {
180 RLibError::DecodingDBNoDefinitionsFoundAndEmptyFile
181 } else {
182 RLibError::DecodingDBNoDefinitionsFound
183 }
184 })?;
185
186 let len = data.len()?;
188 let table = if version == 0 {
189 let mut altered = false;
190 let index_reset = data.stream_position()?;
191
192 let mut working_definition = Err(RLibError::DecodingDBNoDefinitionsFound);
194 for definition in definitions.iter().filter(|definition| *definition.version() < 1) {
195
196 data.seek(SeekFrom::Start(index_reset))?;
199 let db = decode_table(data, definition, Some(entry_count), return_incomplete, &mut altered);
200 if db.is_ok() && data.stream_position()? == len {
201 working_definition = Ok(definition);
202 break;
203 }
204 }
205
206 let definition = working_definition?;
207 let definition_patch = schema.patches_for_table(table_name).cloned().unwrap_or_default();
208
209 data.seek(SeekFrom::Start(index_reset))?;
211 TableInMemory::decode(data, definition, &definition_patch, Some(entry_count), return_incomplete, table_name)?
212 }
213
214 else {
216
217 let definition = definitions.iter()
218 .find(|definition| *definition.version() == version)
219 .ok_or(RLibError::DecodingDBNoDefinitionsFound)?;
220
221 let definition_patch = schema.patches_for_table(table_name).cloned().unwrap_or_default();
222 TableInMemory::decode(data, definition, &definition_patch, Some(entry_count), return_incomplete, table_name)?
223 };
224
225 check_size_mismatch(data.stream_position()? as usize, len as usize).map_err(|error| {
229 RLibError::DecodingTableIncomplete(error.to_string(), Box::new(table.clone()))
230 })?;
231
232 Ok(Self {
234 mysterious_byte,
235 guid,
236 table,
237 })
238 }
239}
240
241impl Encodeable for DB {
242
243 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
244 let table_has_guid = if let Some (ref extra_data) = extra_data { extra_data.table_has_guid } else { false };
245 let regenerate_table_guid = if let Some (ref extra_data) = extra_data { extra_data.regenerate_table_guid } else { false };
246
247 if table_has_guid {
250 buffer.write_all(GUID_MARKER)?;
251 if regenerate_table_guid || self.guid.is_empty() {
252 buffer.write_sized_string_u16(&Uuid::new_v4().to_string())?;
253 } else {
254 buffer.write_sized_string_u16(&self.guid)?;
255 }
256 }
257
258 if *self.table.definition().version() > 0 {
260 buffer.write_all(VERSION_MARKER)?;
261 buffer.write_i32(*self.table.definition().version())?;
262 }
263
264 buffer.write_bool(self.mysterious_byte)?;
265 buffer.write_u32(self.table.len() as u32)?;
266
267 self.table.encode(buffer)
268 }
269}
270
271impl DB {
272
273 pub fn new(definition: &Definition, definition_patch: Option<&DefinitionPatch>, table_name: &str) -> Self {
299 let table = TableInMemory::new(definition, definition_patch, table_name);
300
301 Self {
302 mysterious_byte: true,
303 guid: String::new(),
304 table,
305 }
306 }
307
308 pub fn read_header<R: ReadBytes>(data: &mut R) -> Result<(i32, bool, String, u32)> {
343
344 if data.len()? < 5 {
347 return Err(RLibError::DecodingDBNotADBTable);
348 }
349
350 let guid = if data.read_slice(4, false)? == GUID_MARKER {
352 data.read_sized_string_u16()?
353 } else {
354 data.seek(SeekFrom::Current(-4))?;
355 String::new()
356 };
357
358 let version = if data.read_slice(4, false)? == VERSION_MARKER {
361 data.read_i32()?
362 } else {
363 data.seek(SeekFrom::Current(-4))?;
364 0
365 };
366
367 let mysterious_byte = data.read_bool()?;
369 let entry_count = data.read_u32()?;
370 Ok((version, mysterious_byte, guid, entry_count))
371 }
372
373 pub fn definition(&self) -> &Definition {
375 self.table.definition()
376 }
377
378 pub fn patches(&self) -> &DefinitionPatch {
380 self.table.patches()
381 }
382
383 pub fn table_name(&self) -> &str {
385 self.table.table_name()
386 }
387
388 pub fn table_name_without_tables(&self) -> String {
394
395 if self.table_name().ends_with("_tables") {
397 self.table_name().to_owned().drain(..self.table_name().len() - 7).collect()
398 } else {
399 panic!("Either the code is broken, or someone with a few loose screws has renamed the fucking table folder. Crash for now, may return an error in the future.")
400 }
401 }
402
403 pub fn data(&'_ self) -> Cow<'_, [Vec<DecodedData>]> {
405 self.table.data()
406 }
407
408 #[cfg(feature = "integration_sqlite")]
410 pub fn sql_to_db(&mut self, pool: &Pool<SqliteConnectionManager>, pack_name: &str, file_name: &str) -> Result<()> {
411 self.table.sql_to_db(pool, pack_name, file_name)
412 }
413
414 pub fn data_mut(&mut self) -> &mut Vec<Vec<DecodedData>> {
418 self.table.data_mut()
419 }
420
421 pub fn set_data(&mut self, data: &[Vec<DecodedData>]) -> Result<()> {
427 self.table.set_data(data)
428 }
429
430 pub fn new_row(&self) -> Vec<DecodedData> {
432 self.table().new_row()
433 }
434
435 #[cfg(test)]
437 pub fn test_definition() -> Definition {
438 let mut definition = Definition::new(-100, None);
439 let mut fields = vec![];
440
441 fields.push(Field { name: "bool".to_owned(), field_type: FieldType::Boolean, default_value: Some("true".to_string()), ..Default::default() });
442 fields.push(Field { name: "f32".to_owned(), field_type: FieldType::F32, default_value: Some("1.0".to_string()), ..Default::default() });
443 fields.push(Field { name: "f64".to_owned(), field_type: FieldType::F64, default_value: Some("2.0".to_string()), ..Default::default() });
444 fields.push(Field { name: "i16".to_owned(), field_type: FieldType::I16, default_value: Some("3".to_string()), ..Default::default() });
445 fields.push(Field { name: "i32".to_owned(), field_type: FieldType::I32, default_value: Some("4".to_string()), ..Default::default() });
446 fields.push(Field { name: "i64".to_owned(), field_type: FieldType::I64, default_value: Some("5".to_string()), ..Default::default() });
447 fields.push(Field { name: "colour".to_owned(), field_type: FieldType::ColourRGB, default_value: Some("ABCDEF".to_string()), ..Default::default() });
448 fields.push(Field { name: "stringu8".to_owned(), field_type: FieldType::StringU8, default_value: Some("AAAA".to_string()), ..Default::default() });
449 fields.push(Field { name: "stringu16".to_owned(), field_type: FieldType::StringU16, default_value: Some("BBBB".to_string()), ..Default::default() });
450 fields.push(Field { name: "optionali16".to_owned(), field_type: FieldType::OptionalI16, default_value: Some("3".to_string()), ..Default::default() });
451 fields.push(Field { name: "optionali32".to_owned(), field_type: FieldType::OptionalI32, default_value: Some("4".to_string()), ..Default::default() });
452 fields.push(Field { name: "optionali64".to_owned(), field_type: FieldType::OptionalI64, default_value: Some("5".to_string()), ..Default::default() });
453 fields.push(Field { name: "optionalstringu8".to_owned(), field_type: FieldType::OptionalStringU8, default_value: Some("Opt".to_string()), ..Default::default() });
454 fields.push(Field { name: "optionalstringu16".to_owned(), field_type: FieldType::OptionalStringU16, default_value: Some("Opt".to_string()), ..Default::default() });
455 fields.push(Field { name: "sequenceu16".to_owned(), field_type: FieldType::SequenceU16(Box::new(Definition::new(-100, None))), ..Default::default() });
456 fields.push(Field { name: "sequenceu32".to_owned(), field_type: FieldType::SequenceU32(Box::new(Definition::new(-100, None))), ..Default::default() });
457
458 fields.push(Field {
460 name: "merged_colours_1_r".to_owned(),
461 field_type: FieldType::I32,
462 default_value: Some("AB".to_string()),
463 is_part_of_colour: Some(0),
464 ..Default::default()
465 });
466 fields.push(Field {
467 name: "merged_colours_1_g".to_owned(),
468 field_type: FieldType::I32,
469 default_value: Some("CD".to_string()),
470 is_part_of_colour: Some(0),
471 ..Default::default()
472 });
473 fields.push(Field {
474 name: "merged_colours_1_b".to_owned(),
475 field_type: FieldType::I32,
476 default_value: Some("EF".to_string()),
477 is_part_of_colour: Some(0),
478 ..Default::default()
479 });
480 fields.push(Field {
481 name: "bitwise_values".to_owned(),
482 field_type: FieldType::I32,
483 default_value: Some("4".to_string()),
484 is_bitwise: 5,
485 ..Default::default()
486 });
487 fields.push(Field {
488 name: "enum_values".to_owned(),
489 field_type: FieldType::I32,
490 default_value: Some("8".to_string()),
491 enum_values: {
492 let mut bt = BTreeMap::new();
493 bt.insert(0, "test0".to_owned());
494 bt.insert(1, "test1".to_owned());
495 bt.insert(2, "test2".to_owned());
496 bt.insert(3, "test3".to_owned());
497 bt
498 },
499 ..Default::default()
500 });
501
502 fields.push(Field {
503 name: "merged_colours_2_r".to_owned(),
504 field_type: FieldType::I32,
505 default_value: Some("AB".to_string()),
506 is_part_of_colour: Some(1),
507 ..Default::default()
508 });
509 fields.push(Field {
510 name: "merged_colours_2_g".to_owned(),
511 field_type: FieldType::I32,
512 default_value: Some("CD".to_string()),
513 is_part_of_colour: Some(1),
514 ..Default::default()
515 });
516 fields.push(Field {
517 name: "merged_colours_2_b".to_owned(),
518 field_type: FieldType::I32,
519 default_value: Some("EF".to_string()),
520 is_part_of_colour: Some(1),
521 ..Default::default()
522 });
523
524 definition.set_fields(fields);
527 definition
528 }
529
530 pub fn column_position_by_name(&self, column_name: &str) -> Option<usize> {
532 self.table.column_position_by_name(column_name)
533 }
534
535 pub fn len(&self) -> usize {
537 self.table.len()
538 }
539
540 pub fn is_empty(&self) -> bool {
542 self.table.is_empty()
543 }
544
545 pub fn set_definition(&mut self, new_definition: &Definition) {
550 self.table.set_definition(new_definition);
551 }
552
553 pub fn update(&mut self, new_definition: &Definition) {
555 self.set_definition(new_definition)
556 }
557
558 pub fn cascade_edition(pack: &mut Pack, schema: &Schema, table_name: &str, field: &Field, definition: &Definition, value_before: &str, value_after: &str) -> Vec<ContainerPath> {
578
579 let mut edited_paths = vec![];
585
586 if value_before == value_after {
588 return vec![];
589 }
590
591 let mut definition = definition.clone();
593 let patches = Some(definition.patches().clone());
594 let mut field = field.clone();
595 let mut table_name = table_name.to_owned();
596 while let Some((ref_table, ref_column)) = field.is_reference(patches.as_ref()) {
597 let ref_table_name = format!("{ref_table}_tables");
598 let table_folder = format!("db/{ref_table_name}");
599 let parent_files = pack.files_by_type_and_paths_mut(&[FileType::DB], &[ContainerPath::Folder(table_folder.to_owned())], true);
600 if !parent_files.is_empty() {
601 if let Ok(RFileDecoded::DB(table)) = parent_files[0].decoded() {
602 if let Some(index) = table.definition().column_position_by_name(&ref_column) {
603 definition = table.definition().clone();
604 field = definition.fields_processed()[index].clone();
605 table_name = table.table_name().to_owned();
606 continue;
607 }
608 }
609 }
610
611 break;
612 }
613
614 let fields_processed = definition.fields_processed();
616 let fields_localised = definition.localised_fields();
617 let (mut ref_table_data, _) = schema.tables_and_columns_referencing_our_own(&table_name, field.name(), &fields_processed, fields_localised);
618
619 ref_table_data.insert(table_name, vec![field.name().to_owned()]);
621
622 let container_paths = ref_table_data.keys().map(|ref_table_name| ContainerPath::Folder("db/".to_owned() + ref_table_name)).collect::<Vec<_>>();
623 let mut files = pack.files_by_paths_mut(&container_paths, true);
624 let mut loc_keys: Vec<(String, String)> = vec![];
625
626 for file in files.iter_mut() {
627 let path = file.path_in_container();
628 if let Ok(RFileDecoded::DB(table)) = file.decoded_mut() {
629 let fields_processed = table.definition().fields_processed();
630 let fields_localised = table.definition().localised_fields().to_vec();
631 let localised_order = table.definition().localised_key_order().to_vec();
632 let patches = table.definition().patches().clone();
633 let table_name = table.table_name().to_owned();
634 let table_name_no_tables = table.table_name_without_tables();
635 let table_data = table.data_mut();
636
637 let mut keys_edited = vec![];
638
639 let column_indexes = fields_processed.iter()
641 .enumerate()
642 .filter_map(|(index, field)| if ref_table_data[&table_name].iter().any(|name| name == field.name()) { Some(index) } else { None })
643 .collect::<Vec<usize>>();
644
645 for row in table_data.iter_mut() {
647 for column in &column_indexes {
648
649 let row_copy = row.to_vec();
651
652 if let Some(field_data) = row.get_mut(*column) {
653 match field_data {
654 DecodedData::StringU8(field_data) |
655 DecodedData::StringU16(field_data) |
656 DecodedData::OptionalStringU8(field_data) |
657 DecodedData::OptionalStringU16(field_data) => {
658
659 if field_data == value_before {
661 let mut locs_edited = vec![];
662
663 let is_key = fields_processed[*column].is_key(Some(&patches));
665 if is_key {
666 for loc_field in &fields_localised {
667 let loc_key = localised_order.iter().map(|pos| row_copy[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
668 locs_edited.push(format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key));
669 }
670 }
671
672 *field_data = value_after.to_owned();
673
674 if !locs_edited.is_empty() {
675 for (index, loc_field) in fields_localised.iter().enumerate() {
676 if let Some(key_old) = locs_edited.get(index) {
677 let loc_key = localised_order.iter().map(|pos| row[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
678 let key_new = format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key);
679 keys_edited.push((key_old.to_owned(), key_new.to_owned()))
680 }
681 }
682 }
683
684 if !edited_paths.contains(&path) {
685 edited_paths.push(path.clone());
686 }
687 }
688 }
689 _ => continue
690 }
691 }
692 }
693 }
694
695 if !keys_edited.is_empty() {
697 loc_keys.append(&mut keys_edited);
698 }
699 }
700 }
701
702 let mut loc_files = pack.files_by_type_mut(&[FileType::Loc]);
704 for file in &mut loc_files {
705 let path = file.path_in_container();
706 if let Ok(RFileDecoded::Loc(data)) = file.decoded_mut() {
707 let data = data.data_mut();
708 for row in data.iter_mut() {
709 if let Some(
710 DecodedData::StringU8(field_data) |
711 DecodedData::StringU16(field_data) |
712 DecodedData::OptionalStringU8(field_data) |
713 DecodedData::OptionalStringU16(field_data)
714 ) = row.get_mut(0) {
715 for (key_old, key_new) in &loc_keys {
716 if field_data == key_old {
717 *field_data = key_new.to_owned();
718
719 if !edited_paths.contains(&path) {
720 edited_paths.push(path.clone());
721 }
722 }
723 }
724 }
725 }
726 }
727 }
728
729 edited_paths
730 }
731
732 pub fn merge(sources: &[&Self]) -> Result<Self> {
744
745 let table_names = sources.iter().map(|file| file.table_name()).collect::<HashSet<_>>();
746 if table_names.len() > 1 {
747 return Err(RLibError::RFileMergeTablesDifferentNames);
748 }
749
750 if sources.len() < 2 {
751 return Err(RLibError::RFileMergeTablesNotEnoughTablesProvided);
752 }
753
754 let mut new_table = Self::new(sources[0].definition(), Some(sources[0].patches()), sources[0].table_name());
755 let sources = sources.par_iter()
756 .map(|table| {
757 let mut table = table.table().clone();
758 table.set_definition(new_table.definition());
759 table
760 })
761 .collect::<Vec<_>>();
762
763 let new_data = sources.par_iter()
764 .map(|table| table.data().to_vec())
765 .flatten()
766 .collect::<Vec<_>>();
767 new_table.set_data(&new_data)?;
768
769 Ok(new_table)
770 }
771
772 pub fn tsv_import(records: StringRecordsIter<File>, field_order: &HashMap<u32, String>, schema: &Schema, table_name: &str, table_version: i32) -> Result<Self> {
786 let definition = schema.definition_by_name_and_version(table_name, table_version).ok_or(RLibError::DecodingDBNoDefinitionsFound)?;
787 let definition_patch = schema.patches_for_table(table_name);
788 let table = TableInMemory::tsv_import(records, definition, field_order, table_name, definition_patch)?;
789 let db = DB::from(table);
790 Ok(db)
791 }
792
793 pub fn tsv_export(&self, writer: &mut Writer<File>, table_path: &str, keys_first: bool) -> Result<()> {
801 self.table.tsv_export(writer, table_path, keys_first)
802 }
803
804 pub fn altered(&self) -> bool {
806 *self.table.altered()
807 }
808
809 pub fn generate_twad_key_deletes_keys(&self, keys: &mut HashSet<String>) {
814 let definition = self.definition();
815 match self.table_name() {
816
817 "agent_to_agent_attributes_tables" => {
819 let key_pos_0 = definition.column_position_by_name("agent").unwrap_or_default();
820 let key_pos_1 = definition.column_position_by_name("attribute").unwrap_or_default();
821
822 keys.extend(self.data()
823 .iter()
824 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
825 .collect::<Vec<_>>()
826 );
827 }
828
829 "animation_set_prebattle_group_view_configurations_tables" => {
831 let key_pos_0 = definition.column_position_by_name("attacker").unwrap_or_default();
832 let key_pos_1 = definition.column_position_by_name("defender").unwrap_or_default();
833
834 keys.extend(self.data()
835 .iter()
836 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
837 .collect::<Vec<_>>()
838 );
839 }
840
841 "armory_item_variants_tables" => {
843 let key_pos_0 = definition.column_position_by_name("armory_item").unwrap_or_default();
844 let key_pos_1 = definition.column_position_by_name("variant").unwrap_or_default();
845
846 keys.extend(self.data()
847 .iter()
848 .map(|x| x[key_pos_0].data_to_string().to_string() + " | " + &x[key_pos_1].data_to_string())
849 .collect::<Vec<_>>()
850 );
851 }
852
853 "battle_currency_deployables_cost_values_tables" => {
855 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
856 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
857
858 keys.extend(self.data()
859 .iter()
860 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_0].data_to_string())
861 .collect::<Vec<_>>()
862 );
863 }
864
865 "battle_currency_units_cost_values_tables" => {
867 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
868 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
869
870 keys.extend(self.data()
871 .iter()
872 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_0].data_to_string())
873 .collect::<Vec<_>>()
874 );
875 }
876
877 "battle_set_pieces_siege_items_tables" => {
879 let key_pos_0 = definition.column_position_by_name("army_name").unwrap_or_default();
880 let key_pos_1 = definition.column_position_by_name("siege_item").unwrap_or_default();
881
882 keys.extend(self.data()
883 .iter()
884 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_0].data_to_string())
885 .collect::<Vec<_>>()
886 );
887 }
888
889 "cai_agent_type_distribution_profile_junctions_tables" => {
891 let key_pos_0 = definition.column_position_by_name("distribution_profile_key").unwrap_or_default();
892 let key_pos_1 = definition.column_position_by_name("agent_type_key").unwrap_or_default();
893
894 keys.extend(self.data()
895 .iter()
896 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
897 .collect::<Vec<_>>()
898 );
899 }
900
901 "cai_agent_type_recruitment_profile_junctions_tables" => {
903 let key_pos_0 = definition.column_position_by_name("recruitment_profile_key").unwrap_or_default();
904 let key_pos_1 = definition.column_position_by_name("agent_type_key").unwrap_or_default();
905
906 keys.extend(self.data()
907 .iter()
908 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
909 .collect::<Vec<_>>()
910 );
911 }
912
913 "cai_personalities_budget_allocation_policy_junctions_tables" => {
915 let key_pos_0 = definition.column_position_by_name("budget_allocation_key").unwrap_or_default();
916 let key_pos_1 = definition.column_position_by_name("budget_context_key").unwrap_or_default();
917 let key_pos_2 = definition.column_position_by_name("budget_policy_key").unwrap_or_default();
918
919 keys.extend(self.data()
920 .iter()
921 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string() + ";" + &x[key_pos_2].data_to_string())
922 .collect::<Vec<_>>()
923 );
924 }
925
926 "cai_personalities_construction_preference_policy_building_junctions_tables" => {
928 let key_pos_0 = definition.column_position_by_name("building_key").unwrap_or_default();
929 let key_pos_1 = definition.column_position_by_name("policy_key").unwrap_or_default();
930
931 keys.extend(self.data()
932 .iter()
933 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
934 .collect::<Vec<_>>()
935 );
936 }
937
938 "cai_task_management_system_task_generator_variable_group_junctions_tables" => {
940 let key_pos_0 = definition.column_position_by_name("variable_group_key").unwrap_or_default();
941 let key_pos_1 = definition.column_position_by_name("variable_key").unwrap_or_default();
942
943 keys.extend(self.data()
944 .iter()
945 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_0].data_to_string())
946 .collect::<Vec<_>>()
947 );
948 }
949
950 "campaign_ai_manager_behaviour_junctions_tables" => {
952 let key_pos_0 = definition.column_position_by_name("manager").unwrap_or_default();
953 let key_pos_1 = definition.column_position_by_name("behaviour").unwrap_or_default();
954
955 keys.extend(self.data()
956 .iter()
957 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
958 .collect::<Vec<_>>()
959 );
960 }
961
962 "campaign_bmd_layer_group_bmd_export_types_junctions_tables" => {
964 let key_pos_0 = definition.column_position_by_name("bmd_export_types").unwrap_or_default();
965 let key_pos_1 = definition.column_position_by_name("campaign_bmd_layer_group").unwrap_or_default();
966
967 keys.extend(self.data()
968 .iter()
969 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
970 .collect::<Vec<_>>()
971 );
972 }
973
974 "campaign_difficulty_handicap_effects_tables" => {
976 let key_pos_0 = definition.column_position_by_name("campaign_difficulty_handicap").unwrap_or_default();
977 let key_pos_1 = definition.column_position_by_name("human").unwrap_or_default();
978 let key_pos_2 = definition.column_position_by_name("effect").unwrap_or_default();
979 let key_pos_3 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
980
981 keys.extend(self.data()
982 .iter()
983 .map(|x| {
984 let human = if x[key_pos_1].data_to_string() == "true" { "1" } else { "0" };
985 x[key_pos_0].data_to_string().to_string() + "-" + human + "-" + &x[key_pos_2].data_to_string() + &x[key_pos_3].data_to_string()
986 })
987 .collect::<Vec<_>>()
988 );
989 }
990
991 "campaign_effect_scope_agent_junctions_tables" => {
993 let key_pos_0 = definition.column_position_by_name("agent_key").unwrap_or_default();
994 let key_pos_1 = definition.column_position_by_name("campaign_effect_scope_key").unwrap_or_default();
995
996 keys.extend(self.data()
997 .iter()
998 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
999 .collect::<Vec<_>>()
1000 );
1001 }
1002
1003 "campaign_features_tables" => {
1005 let key_pos_0 = definition.column_position_by_name("feature").unwrap_or_default();
1006 let key_pos_1 = definition.column_position_by_name("group").unwrap_or_default();
1007
1008 keys.extend(self.data()
1009 .iter()
1010 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1011 .collect::<Vec<_>>()
1012 );
1013 }
1014
1015 "campaign_markers_tables" => {
1017 let key_pos_0 = definition.column_position_by_name("marker_type").unwrap_or_default();
1018 let key_pos_1 = definition.column_position_by_name("group").unwrap_or_default();
1019
1020 keys.extend(self.data()
1021 .iter()
1022 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1023 .collect::<Vec<_>>()
1024 );
1025 }
1026
1027 "campaign_mercenary_unit_character_level_restrictions_tables" => {
1029 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
1030 let key_pos_1 = definition.column_position_by_name("faction_override").unwrap_or_default();
1031
1032 keys.extend(self.data()
1033 .iter()
1034 .map(|x| {
1035 let fover = if x[key_pos_1].data_to_string().is_empty() {
1036 "".to_owned()
1037 } else {
1038 "_".to_string() + &x[key_pos_1].data_to_string()
1039 };
1040 x[key_pos_0].data_to_string().to_string() + &fover
1041 })
1042 .collect::<Vec<_>>()
1043 );
1044 }
1045
1046 "campaign_movement_spline_materials_tables" => {
1048 let key_pos_0 = definition.column_position_by_name("id").unwrap_or_default();
1049
1050 keys.extend(self.data()
1051 .iter()
1052 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_0].data_to_string())
1053 .collect::<Vec<_>>()
1054 );
1055 }
1056
1057 "campaign_rogue_army_leaders_tables" => {
1059 let key_pos_0 = definition.column_position_by_name("campaign");
1060 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1061
1062 keys.extend(self.data()
1063 .iter()
1064 .map(|x| {
1065 let camp = if let Some(y) = key_pos_0 { x[y].data_to_string().to_string() } else { "".to_owned() };
1066 camp + &x[key_pos_1].data_to_string()
1067 })
1068 .collect::<Vec<_>>()
1069 );
1070 }
1071
1072 "campaign_rogue_army_setups_tables" => {
1074 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1075 let key_pos_1 = definition.column_position_by_name("difficulty_level").unwrap_or_default();
1076
1077 keys.extend(self.data()
1078 .iter()
1079 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1080 .collect::<Vec<_>>()
1081 );
1082 }
1083
1084 "campaigns_campaign_variables_junctions_tables" => {
1086 let key_pos_0 = definition.column_position_by_name("variable_key").unwrap_or_default();
1087 let key_pos_1 = definition.column_position_by_name("campaign_name").unwrap_or_default();
1088 let key_pos_2 = definition.column_position_by_name("difficulty").unwrap_or_default();
1089 let key_pos_3 = definition.column_position_by_name("campaign_type").unwrap_or_default();
1090
1091 keys.extend(self.data()
1092 .iter()
1093 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_2].data_to_string() + &x[key_pos_3].data_to_string())
1094 .collect::<Vec<_>>()
1095 );
1096 }
1097
1098 "campaign_tree_type_cultures_tables" => {
1100 let key_pos_0 = definition.column_position_by_name("tree_type").unwrap_or_default();
1101 let key_pos_1 = definition.column_position_by_name("culture").unwrap_or_default();
1102
1103 keys.extend(self.data()
1104 .iter()
1105 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_0].data_to_string())
1106 .collect::<Vec<_>>()
1107 );
1108 }
1109
1110 "cdir_events_mission_issuer_junctions_tables" => {
1112 let key_pos_0 = definition.column_position_by_name("issuer_key").unwrap_or_default();
1113 let key_pos_1 = definition.column_position_by_name("mission_key").unwrap_or_default();
1114
1115 keys.extend(self.data()
1116 .iter()
1117 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1118 .collect::<Vec<_>>()
1119 );
1120 }
1121
1122 "character_experience_skill_tiers_tables" => {
1124 let key_pos_0 = definition.column_position_by_name("for_army").unwrap_or_default();
1125 let key_pos_1 = definition.column_position_by_name("for_navy").unwrap_or_default();
1126 let key_pos_2 = definition.column_position_by_name("agent_key").unwrap_or_default();
1127 let key_pos_3 = definition.column_position_by_name("skill_rank").unwrap_or_default();
1128 let key_pos_4 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1129
1130 keys.extend(self.data()
1131 .iter()
1132 .map(|x| {
1133 let mut ckey = String::new();
1134 if x[key_pos_0].data_to_string() == "true" {
1135 if x[key_pos_1].data_to_string() == "true" {
1136 ckey.push_str("navy");
1137 } else {
1138 ckey.push_str("army");
1139 }
1140 } else {
1141 ckey.push_str(&x[key_pos_2].data_to_string());
1142 }
1143
1144 ckey + &x[key_pos_3].data_to_string() + &x[key_pos_4].data_to_string()
1145 })
1146 .collect::<Vec<_>>()
1147 );
1148 }
1149
1150 "culture_to_battle_animation_tables_tables" => {
1152 let key_pos_0 = definition.column_position_by_name("battle_animations_table").unwrap_or_default();
1153 let key_pos_1 = definition.column_position_by_name("culture_pack").unwrap_or_default();
1154
1155 keys.extend(self.data()
1156 .iter()
1157 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1158 .collect::<Vec<_>>()
1159 );
1160 }
1161
1162 "effect_bonus_value_id_action_results_additional_outcomes_junctions_tables" => {
1164 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1165 let key_pos_1 = definition.column_position_by_name("action_results_additional_outcome_record").unwrap_or_default();
1166 let key_pos_2 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1167
1168 keys.extend(self.data()
1169 .iter()
1170 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_2].data_to_string())
1171 .collect::<Vec<_>>()
1172 );
1173 }
1174
1175 "effect_bonus_value_projectile_junctions_tables" => {
1177 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1178 let key_pos_1 = definition.column_position_by_name("bonus_value").unwrap_or_default();
1179 let key_pos_2 = definition.column_position_by_name("projectile").unwrap_or_default();
1180
1181 keys.extend(self.data()
1182 .iter()
1183 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_2].data_to_string())
1184 .collect::<Vec<_>>()
1185 );
1186 }
1187
1188 "effect_bonus_value_unit_attribute_junctions_tables" => {
1190 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1191 let key_pos_1 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1192 let key_pos_2 = definition.column_position_by_name("unit_attribute").unwrap_or_default();
1193
1194 keys.extend(self.data()
1195 .iter()
1196 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string() + ";" + &x[key_pos_2].data_to_string())
1197 .collect::<Vec<_>>()
1198 );
1199 }
1200
1201 "effect_bonus_value_unit_record_junctions_tables" => {
1203 let key_pos_0 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1204 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1205 let key_pos_2 = definition.column_position_by_name("unit_record_key").unwrap_or_default();
1206
1207 keys.extend(self.data()
1208 .iter()
1209 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_2].data_to_string())
1210 .collect::<Vec<_>>()
1211 );
1212 }
1213
1214 "ground_type_to_stat_effects_tables" => {
1216 let key_pos_0 = definition.column_position_by_name("ground_type").unwrap_or_default();
1217 let key_pos_1 = definition.column_position_by_name("affected_stat").unwrap_or_default();
1218 let key_pos_2 = definition.column_position_by_name("affected_group").unwrap_or_default();
1219
1220 keys.extend(self.data()
1221 .iter()
1222 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_2].data_to_string() + &x[key_pos_1].data_to_string())
1223 .collect::<Vec<_>>()
1224 );
1225 }
1226
1227 "land_units_to_unit_abilites_junctions_tables" => {
1229 let key_pos_0 = definition.column_position_by_name("ability").unwrap_or_default();
1230 let key_pos_1 = definition.column_position_by_name("land_unit").unwrap_or_default();
1231
1232 keys.extend(self.data()
1233 .iter()
1234 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1235 .collect::<Vec<_>>()
1236 );
1237 }
1238
1239 "loading_screen_quotes_to_campaigns_tables" => {
1241 let key_pos_0 = definition.column_position_by_name("loading_quote").unwrap_or_default();
1242 let key_pos_1 = definition.column_position_by_name("campaign").unwrap_or_default();
1243
1244 keys.extend(self.data()
1245 .iter()
1246 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_1].data_to_string())
1247 .collect::<Vec<_>>()
1248 );
1249 }
1250
1251 "message_event_strings_tables" => {
1253 let key_pos_0 = definition.column_position_by_name("event").unwrap_or_default();
1254 let key_pos_1 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1255 let key_pos_2 = definition.column_position_by_name("culture").unwrap_or_default();
1256 let key_pos_3 = definition.column_position_by_name("optional_subculture").unwrap_or_default();
1257
1258 keys.extend(self.data()
1259 .iter()
1260 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_2].data_to_string() + &x[key_pos_3].data_to_string())
1261 .collect::<Vec<_>>()
1262 );
1263 }
1264
1265 "mp_force_gen_template_junctions_tables" => {
1267 let key_pos_0 = definition.column_position_by_name("template_key").unwrap_or_default();
1268 let key_pos_1 = definition.column_position_by_name("battle_type").unwrap_or_default();
1269 let key_pos_2 = definition.column_position_by_name("is_defender").unwrap_or_default();
1270
1271 keys.extend(self.data()
1272 .iter()
1273 .map(|x| {
1274 let is_defender = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1275 x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + is_defender
1276 })
1277 .collect::<Vec<_>>()
1278 );
1279 }
1280
1281 "provincial_initiative_strength_levels_tables" => {
1283 let key_pos_0 = definition.column_position_by_name("initiative_record").unwrap_or_default();
1284 let key_pos_1 = definition.column_position_by_name("strength").unwrap_or_default();
1285
1286 keys.extend(self.data()
1287 .iter()
1288 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1289 .collect::<Vec<_>>()
1290 );
1291 }
1292
1293 "region_to_province_junctions_tables" => {
1295 let key_pos_0 = definition.column_position_by_name("province").unwrap_or_default();
1296 let key_pos_1 = definition.column_position_by_name("region").unwrap_or_default();
1297
1298 keys.extend(self.data()
1299 .iter()
1300 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1301 .collect::<Vec<_>>()
1302 );
1303 }
1304
1305 "ritual_payload_change_agent_capacities_tables" => {
1307 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1308 let key_pos_1 = definition.column_position_by_name("agent_record").unwrap_or_default();
1309
1310 keys.extend(self.data()
1311 .iter()
1312 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1313 .collect::<Vec<_>>()
1314 );
1315 }
1316
1317 "ritual_payload_change_unit_capacities_tables" => {
1319 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1320 let key_pos_1 = definition.column_position_by_name("unit_record").unwrap_or_default();
1321
1322 keys.extend(self.data()
1323 .iter()
1324 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1325 .collect::<Vec<_>>()
1326 );
1327 }
1328
1329 "slot_set_type_feature_junctions_tables" => {
1331 let key_pos_0 = definition.column_position_by_name("slot_set_type").unwrap_or_default();
1332 let key_pos_1 = definition.column_position_by_name("feature").unwrap_or_default();
1333
1334 keys.extend(self.data()
1335 .iter()
1336 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1337 .collect::<Vec<_>>()
1338 );
1339 }
1340
1341 "special_ability_to_special_ability_phase_junctions_tables" => {
1343 let key_pos_0 = definition.column_position_by_name("special_ability").unwrap_or_default();
1344 let key_pos_1 = definition.column_position_by_name("phase").unwrap_or_default();
1345 let key_pos_2 = definition.column_position_by_name("order").unwrap_or_default();
1346
1347 keys.extend(self.data()
1348 .iter()
1349 .map(|x| x[key_pos_0].data_to_string().to_string() + ":" + &x[key_pos_1].data_to_string() + ":" + &x[key_pos_2].data_to_string())
1350 .collect::<Vec<_>>()
1351 );
1352 }
1353
1354 "start_pos_region_slot_templates_tables" => {
1356 let key_pos_0 = definition.column_position_by_name("campaign").unwrap_or_default();
1357 let key_pos_1 = definition.column_position_by_name("id").unwrap_or_default();
1358 let key_pos_2 = definition.column_position_by_name("region").unwrap_or_default();
1359 let key_pos_3 = definition.column_position_by_name("slot_template").unwrap_or_default();
1360 let key_pos_4 = definition.column_position_by_name("slot_type").unwrap_or_default();
1361
1362 keys.extend(self.data()
1363 .iter()
1364 .map(|x|
1365 x[key_pos_0].data_to_string().to_string() +
1366 &x[key_pos_1].data_to_string() +
1367 &x[key_pos_2].data_to_string() +
1368 &x[key_pos_3].data_to_string() +
1369 &x[key_pos_4].data_to_string()
1370 )
1371 .collect::<Vec<_>>()
1372 );
1373 }
1374
1375 "start_pos_technologies_tables" => {
1377 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1378 let key_pos_1 = definition.column_position_by_name("technology").unwrap_or_default();
1379
1380 keys.extend(self.data()
1381 .iter()
1382 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1383 .collect::<Vec<_>>()
1384 );
1385 }
1386
1387 "taxes_effects_jct_tables" => {
1389 let key_pos_0 = definition.column_position_by_name("tax_name").unwrap_or_default();
1390 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1391 let key_pos_2 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1392 let key_pos_3 = definition.column_position_by_name("optional_difficulty_level").unwrap_or_default();
1393 let key_pos_4 = definition.column_position_by_name("ai_only").unwrap_or_default();
1394
1395 keys.extend(self.data()
1396 .iter()
1397 .map(|x| {
1398 let ai_only = if x[key_pos_4].data_to_string() == "true" { "1" } else { "0" };
1399 x[key_pos_0].data_to_string().to_string() + ";" +
1400 &x[key_pos_1].data_to_string() + ";" +
1401 &x[key_pos_2].data_to_string() + ";" +
1402 &x[key_pos_3].data_to_string() + ai_only
1403 })
1404 .collect::<Vec<_>>()
1405 );
1406 }
1407
1408 "ui_purchasable_effects_to_hex_ids_tables" => {
1410 let key_pos_0 = definition.column_position_by_name("hex_id").unwrap_or_default();
1411 let key_pos_1 = definition.column_position_by_name("category").unwrap_or_default();
1412
1413 keys.extend(self.data()
1414 .iter()
1415 .map(|x| x[key_pos_0].data_to_string().to_string() + "_" + &x[key_pos_1].data_to_string())
1416 .collect::<Vec<_>>()
1417 );
1418 }
1419
1420 "units_custom_battle_permissions_tables" => {
1422 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
1423 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1424 let key_pos_2 = definition.column_position_by_name("general_unit").unwrap_or_default();
1425
1426 keys.extend(self.data()
1427 .iter()
1428 .map(|x| {
1429 let general_unit = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1430 x[key_pos_0].data_to_string().to_string() + ":" + &x[key_pos_1].data_to_string() + ":" + general_unit
1431 })
1432 .collect::<Vec<_>>()
1433 );
1434 }
1435
1436 "workshop_categories_progress_levels_tables" => {
1438 let key_pos_0 = definition.column_position_by_name("category").unwrap_or_default();
1439 let key_pos_1 = definition.column_position_by_name("level_to_unlock").unwrap_or_default();
1440
1441 keys.extend(self.data()
1442 .iter()
1443 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + &x[key_pos_1].data_to_string())
1444 .collect::<Vec<_>>()
1445 );
1446 }
1447
1448 _ => {
1450 let key_cols = definition.key_column_positions_by_ca_order();
1451 keys.extend(self.data()
1452 .iter()
1453 .map(|x| key_cols.iter()
1454 .map(|y| x[*y].data_to_string())
1455 .join("")
1456 )
1457 .collect::<Vec<_>>()
1458 );
1459 }
1460 }
1461 }
1462}
1463
1464impl From<TableInMemory> for DB {
1466 fn from(table: TableInMemory) -> Self {
1467 Self {
1468 mysterious_byte: true,
1469 guid: Uuid::new_v4().to_string(),
1470 table,
1471 }
1472 }
1473}