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 set_guid(&mut self, guid: String) {
432 self.guid = guid;
433 }
434
435 pub fn new_row(&self) -> Vec<DecodedData> {
437 self.table().new_row()
438 }
439
440 #[cfg(test)]
442 pub fn test_definition() -> Definition {
443 let mut definition = Definition::new(-100, None);
444 let mut fields = vec![];
445
446 fields.push(Field { name: "bool".to_owned(), field_type: FieldType::Boolean, default_value: Some("true".to_string()), ..Default::default() });
447 fields.push(Field { name: "f32".to_owned(), field_type: FieldType::F32, default_value: Some("1.0".to_string()), ..Default::default() });
448 fields.push(Field { name: "f64".to_owned(), field_type: FieldType::F64, default_value: Some("2.0".to_string()), ..Default::default() });
449 fields.push(Field { name: "i16".to_owned(), field_type: FieldType::I16, default_value: Some("3".to_string()), ..Default::default() });
450 fields.push(Field { name: "i32".to_owned(), field_type: FieldType::I32, default_value: Some("4".to_string()), ..Default::default() });
451 fields.push(Field { name: "i64".to_owned(), field_type: FieldType::I64, default_value: Some("5".to_string()), ..Default::default() });
452 fields.push(Field { name: "colour".to_owned(), field_type: FieldType::ColourRGB, default_value: Some("ABCDEF".to_string()), ..Default::default() });
453 fields.push(Field { name: "stringu8".to_owned(), field_type: FieldType::StringU8, default_value: Some("AAAA".to_string()), ..Default::default() });
454 fields.push(Field { name: "stringu16".to_owned(), field_type: FieldType::StringU16, default_value: Some("BBBB".to_string()), ..Default::default() });
455 fields.push(Field { name: "optionali16".to_owned(), field_type: FieldType::OptionalI16, default_value: Some("3".to_string()), ..Default::default() });
456 fields.push(Field { name: "optionali32".to_owned(), field_type: FieldType::OptionalI32, default_value: Some("4".to_string()), ..Default::default() });
457 fields.push(Field { name: "optionali64".to_owned(), field_type: FieldType::OptionalI64, default_value: Some("5".to_string()), ..Default::default() });
458 fields.push(Field { name: "optionalstringu8".to_owned(), field_type: FieldType::OptionalStringU8, default_value: Some("Opt".to_string()), ..Default::default() });
459 fields.push(Field { name: "optionalstringu16".to_owned(), field_type: FieldType::OptionalStringU16, default_value: Some("Opt".to_string()), ..Default::default() });
460 fields.push(Field { name: "sequenceu16".to_owned(), field_type: FieldType::SequenceU16(Box::new(Definition::new(-100, None))), ..Default::default() });
461 fields.push(Field { name: "sequenceu32".to_owned(), field_type: FieldType::SequenceU32(Box::new(Definition::new(-100, None))), ..Default::default() });
462
463 fields.push(Field {
465 name: "merged_colours_1_r".to_owned(),
466 field_type: FieldType::I32,
467 default_value: Some("AB".to_string()),
468 is_part_of_colour: Some(0),
469 ..Default::default()
470 });
471 fields.push(Field {
472 name: "merged_colours_1_g".to_owned(),
473 field_type: FieldType::I32,
474 default_value: Some("CD".to_string()),
475 is_part_of_colour: Some(0),
476 ..Default::default()
477 });
478 fields.push(Field {
479 name: "merged_colours_1_b".to_owned(),
480 field_type: FieldType::I32,
481 default_value: Some("EF".to_string()),
482 is_part_of_colour: Some(0),
483 ..Default::default()
484 });
485 fields.push(Field {
486 name: "bitwise_values".to_owned(),
487 field_type: FieldType::I32,
488 default_value: Some("4".to_string()),
489 is_bitwise: 5,
490 ..Default::default()
491 });
492 fields.push(Field {
493 name: "enum_values".to_owned(),
494 field_type: FieldType::I32,
495 default_value: Some("8".to_string()),
496 enum_values: {
497 let mut bt = BTreeMap::new();
498 bt.insert(0, "test0".to_owned());
499 bt.insert(1, "test1".to_owned());
500 bt.insert(2, "test2".to_owned());
501 bt.insert(3, "test3".to_owned());
502 bt
503 },
504 ..Default::default()
505 });
506
507 fields.push(Field {
508 name: "merged_colours_2_r".to_owned(),
509 field_type: FieldType::I32,
510 default_value: Some("AB".to_string()),
511 is_part_of_colour: Some(1),
512 ..Default::default()
513 });
514 fields.push(Field {
515 name: "merged_colours_2_g".to_owned(),
516 field_type: FieldType::I32,
517 default_value: Some("CD".to_string()),
518 is_part_of_colour: Some(1),
519 ..Default::default()
520 });
521 fields.push(Field {
522 name: "merged_colours_2_b".to_owned(),
523 field_type: FieldType::I32,
524 default_value: Some("EF".to_string()),
525 is_part_of_colour: Some(1),
526 ..Default::default()
527 });
528
529 definition.set_fields(fields);
532 definition
533 }
534
535 pub fn column_position_by_name(&self, column_name: &str) -> Option<usize> {
537 self.table.column_position_by_name(column_name)
538 }
539
540 pub fn len(&self) -> usize {
542 self.table.len()
543 }
544
545 pub fn is_empty(&self) -> bool {
547 self.table.is_empty()
548 }
549
550 pub fn set_definition(&mut self, new_definition: &Definition) {
555 self.table.set_definition(new_definition);
556 }
557
558 pub fn update(&mut self, new_definition: &Definition) {
560 self.set_definition(new_definition)
561 }
562
563 pub fn cascade_edition(pack: &mut Pack, schema: &Schema, table_name: &str, field: &Field, definition: &Definition, value_before: &str, value_after: &str) -> Vec<ContainerPath> {
583
584 let mut edited_paths = vec![];
590
591 if value_before == value_after {
593 return vec![];
594 }
595
596 let mut definition = definition.clone();
598 let patches = Some(definition.patches().clone());
599 let mut field = field.clone();
600 let mut table_name = table_name.to_owned();
601 while let Some((ref_table, ref_column)) = field.is_reference(patches.as_ref()) {
602 let ref_table_name = format!("{ref_table}_tables");
603 let table_folder = format!("db/{ref_table_name}");
604 let parent_files = pack.files_by_type_and_paths_mut(&[FileType::DB], &[ContainerPath::Folder(table_folder.to_owned())], true);
605 if !parent_files.is_empty() {
606 if let Ok(RFileDecoded::DB(table)) = parent_files[0].decoded() {
607 if let Some(index) = table.definition().column_position_by_name(&ref_column) {
608 definition = table.definition().clone();
609 field = definition.fields_processed()[index].clone();
610 table_name = table.table_name().to_owned();
611 continue;
612 }
613 }
614 }
615
616 break;
617 }
618
619 let fields_processed = definition.fields_processed();
621 let fields_localised = definition.localised_fields();
622 let (mut ref_table_data, _) = schema.tables_and_columns_referencing_our_own(&table_name, field.name(), &fields_processed, fields_localised);
623
624 ref_table_data.insert(table_name, vec![field.name().to_owned()]);
626
627 let container_paths = ref_table_data.keys().map(|ref_table_name| ContainerPath::Folder("db/".to_owned() + ref_table_name)).collect::<Vec<_>>();
628 let mut files = pack.files_by_paths_mut(&container_paths, true);
629 let mut loc_keys: Vec<(String, String)> = vec![];
630
631 for file in files.iter_mut() {
632 let path = file.path_in_container();
633 if let Ok(RFileDecoded::DB(table)) = file.decoded_mut() {
634 let fields_processed = table.definition().fields_processed();
635 let fields_localised = table.definition().localised_fields().to_vec();
636 let localised_order = table.definition().localised_key_order().to_vec();
637 let patches = table.definition().patches().clone();
638 let table_name = table.table_name().to_owned();
639 let table_name_no_tables = table.table_name_without_tables();
640 let table_data = table.data_mut();
641
642 let mut keys_edited = vec![];
643
644 let column_indexes = fields_processed.iter()
646 .enumerate()
647 .filter_map(|(index, field)| if ref_table_data[&table_name].iter().any(|name| name == field.name()) { Some(index) } else { None })
648 .collect::<Vec<usize>>();
649
650 for row in table_data.iter_mut() {
652 for column in &column_indexes {
653
654 let row_copy = row.to_vec();
656
657 if let Some(field_data) = row.get_mut(*column) {
658 match field_data {
659 DecodedData::StringU8(field_data) |
660 DecodedData::StringU16(field_data) |
661 DecodedData::OptionalStringU8(field_data) |
662 DecodedData::OptionalStringU16(field_data) => {
663
664 if field_data == value_before {
666 let mut locs_edited = vec![];
667
668 let is_key = fields_processed[*column].is_key(Some(&patches));
670 if is_key {
671 for loc_field in &fields_localised {
672 let loc_key = localised_order.iter().map(|pos| row_copy[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
673 locs_edited.push(format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key));
674 }
675 }
676
677 *field_data = value_after.to_owned();
678
679 if !locs_edited.is_empty() {
680 for (index, loc_field) in fields_localised.iter().enumerate() {
681 if let Some(key_old) = locs_edited.get(index) {
682 let loc_key = localised_order.iter().map(|pos| row[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
683 let key_new = format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key);
684 keys_edited.push((key_old.to_owned(), key_new.to_owned()))
685 }
686 }
687 }
688
689 if !edited_paths.contains(&path) {
690 edited_paths.push(path.clone());
691 }
692 }
693 }
694 _ => continue
695 }
696 }
697 }
698 }
699
700 if !keys_edited.is_empty() {
702 loc_keys.append(&mut keys_edited);
703 }
704 }
705 }
706
707 let mut loc_files = pack.files_by_type_mut(&[FileType::Loc]);
709 for file in &mut loc_files {
710 let path = file.path_in_container();
711 if let Ok(RFileDecoded::Loc(data)) = file.decoded_mut() {
712 let data = data.data_mut();
713 for row in data.iter_mut() {
714 if let Some(
715 DecodedData::StringU8(field_data) |
716 DecodedData::StringU16(field_data) |
717 DecodedData::OptionalStringU8(field_data) |
718 DecodedData::OptionalStringU16(field_data)
719 ) = row.get_mut(0) {
720 for (key_old, key_new) in &loc_keys {
721 if field_data == key_old {
722 *field_data = key_new.to_owned();
723
724 if !edited_paths.contains(&path) {
725 edited_paths.push(path.clone());
726 }
727 }
728 }
729 }
730 }
731 }
732 }
733
734 edited_paths
735 }
736
737 pub fn merge(sources: &[&Self]) -> Result<Self> {
749
750 let table_names = sources.iter().map(|file| file.table_name()).collect::<HashSet<_>>();
751 if table_names.len() > 1 {
752 return Err(RLibError::RFileMergeTablesDifferentNames);
753 }
754
755 if sources.len() < 2 {
756 return Err(RLibError::RFileMergeTablesNotEnoughTablesProvided);
757 }
758
759 let mut new_table = Self::new(sources[0].definition(), Some(sources[0].patches()), sources[0].table_name());
760 let sources = sources.par_iter()
761 .map(|table| {
762 let mut table = table.table().clone();
763 table.set_definition(new_table.definition());
764 table
765 })
766 .collect::<Vec<_>>();
767
768 let new_data = sources.par_iter()
769 .map(|table| table.data().to_vec())
770 .flatten()
771 .collect::<Vec<_>>();
772 new_table.set_data(&new_data)?;
773
774 Ok(new_table)
775 }
776
777 pub fn tsv_import(records: StringRecordsIter<File>, field_order: &HashMap<u32, String>, schema: &Schema, table_name: &str, table_version: i32) -> Result<Self> {
791 let definition = schema.definition_by_name_and_version(table_name, table_version).ok_or(RLibError::DecodingDBNoDefinitionsFound)?;
792 let definition_patch = schema.patches_for_table(table_name);
793 let table = TableInMemory::tsv_import(records, definition, field_order, table_name, definition_patch)?;
794 let db = DB::from(table);
795 Ok(db)
796 }
797
798 pub fn tsv_export(&self, writer: &mut Writer<File>, table_path: &str, keys_first: bool) -> Result<()> {
806 self.table.tsv_export(writer, table_path, keys_first)
807 }
808
809 pub fn altered(&self) -> bool {
811 *self.table.altered()
812 }
813
814 pub fn generate_twad_key_deletes_keys(&self, keys: &mut HashSet<String>) {
819 let definition = self.definition();
820 match self.table_name() {
821
822 "agent_to_agent_attributes_tables" => {
824 let key_pos_0 = definition.column_position_by_name("agent").unwrap_or_default();
825 let key_pos_1 = definition.column_position_by_name("attribute").unwrap_or_default();
826
827 keys.extend(self.data()
828 .iter()
829 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
830 .collect::<Vec<_>>()
831 );
832 }
833
834 "animation_set_prebattle_group_view_configurations_tables" => {
836 let key_pos_0 = definition.column_position_by_name("attacker").unwrap_or_default();
837 let key_pos_1 = definition.column_position_by_name("defender").unwrap_or_default();
838
839 keys.extend(self.data()
840 .iter()
841 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
842 .collect::<Vec<_>>()
843 );
844 }
845
846 "armory_item_variants_tables" => {
848 let key_pos_0 = definition.column_position_by_name("armory_item").unwrap_or_default();
849 let key_pos_1 = definition.column_position_by_name("variant").unwrap_or_default();
850
851 keys.extend(self.data()
852 .iter()
853 .map(|x| x[key_pos_0].data_to_string().to_string() + " | " + &x[key_pos_1].data_to_string())
854 .collect::<Vec<_>>()
855 );
856 }
857
858 "battle_currency_deployables_cost_values_tables" => {
860 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
861 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
862
863 keys.extend(self.data()
864 .iter()
865 .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())
866 .collect::<Vec<_>>()
867 );
868 }
869
870 "battle_currency_units_cost_values_tables" => {
872 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
873 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
874
875 keys.extend(self.data()
876 .iter()
877 .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())
878 .collect::<Vec<_>>()
879 );
880 }
881
882 "battle_set_pieces_siege_items_tables" => {
884 let key_pos_0 = definition.column_position_by_name("army_name").unwrap_or_default();
885 let key_pos_1 = definition.column_position_by_name("siege_item").unwrap_or_default();
886
887 keys.extend(self.data()
888 .iter()
889 .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())
890 .collect::<Vec<_>>()
891 );
892 }
893
894 "cai_agent_type_distribution_profile_junctions_tables" => {
896 let key_pos_0 = definition.column_position_by_name("distribution_profile_key").unwrap_or_default();
897 let key_pos_1 = definition.column_position_by_name("agent_type_key").unwrap_or_default();
898
899 keys.extend(self.data()
900 .iter()
901 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
902 .collect::<Vec<_>>()
903 );
904 }
905
906 "cai_agent_type_recruitment_profile_junctions_tables" => {
908 let key_pos_0 = definition.column_position_by_name("recruitment_profile_key").unwrap_or_default();
909 let key_pos_1 = definition.column_position_by_name("agent_type_key").unwrap_or_default();
910
911 keys.extend(self.data()
912 .iter()
913 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
914 .collect::<Vec<_>>()
915 );
916 }
917
918 "cai_personalities_budget_allocation_policy_junctions_tables" => {
920 let key_pos_0 = definition.column_position_by_name("budget_allocation_key").unwrap_or_default();
921 let key_pos_1 = definition.column_position_by_name("budget_context_key").unwrap_or_default();
922 let key_pos_2 = definition.column_position_by_name("budget_policy_key").unwrap_or_default();
923
924 keys.extend(self.data()
925 .iter()
926 .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())
927 .collect::<Vec<_>>()
928 );
929 }
930
931 "cai_personalities_construction_preference_policy_building_junctions_tables" => {
933 let key_pos_0 = definition.column_position_by_name("building_key").unwrap_or_default();
934 let key_pos_1 = definition.column_position_by_name("policy_key").unwrap_or_default();
935
936 keys.extend(self.data()
937 .iter()
938 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
939 .collect::<Vec<_>>()
940 );
941 }
942
943 "cai_task_management_system_task_generator_variable_group_junctions_tables" => {
945 let key_pos_0 = definition.column_position_by_name("variable_group_key").unwrap_or_default();
946 let key_pos_1 = definition.column_position_by_name("variable_key").unwrap_or_default();
947
948 keys.extend(self.data()
949 .iter()
950 .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())
951 .collect::<Vec<_>>()
952 );
953 }
954
955 "campaign_ai_manager_behaviour_junctions_tables" => {
957 let key_pos_0 = definition.column_position_by_name("manager").unwrap_or_default();
958 let key_pos_1 = definition.column_position_by_name("behaviour").unwrap_or_default();
959
960 keys.extend(self.data()
961 .iter()
962 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
963 .collect::<Vec<_>>()
964 );
965 }
966
967 "campaign_bmd_layer_group_bmd_export_types_junctions_tables" => {
969 let key_pos_0 = definition.column_position_by_name("bmd_export_types").unwrap_or_default();
970 let key_pos_1 = definition.column_position_by_name("campaign_bmd_layer_group").unwrap_or_default();
971
972 keys.extend(self.data()
973 .iter()
974 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
975 .collect::<Vec<_>>()
976 );
977 }
978
979 "campaign_difficulty_handicap_effects_tables" => {
981 let key_pos_0 = definition.column_position_by_name("campaign_difficulty_handicap").unwrap_or_default();
982 let key_pos_1 = definition.column_position_by_name("human").unwrap_or_default();
983 let key_pos_2 = definition.column_position_by_name("effect").unwrap_or_default();
984 let key_pos_3 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
985
986 keys.extend(self.data()
987 .iter()
988 .map(|x| {
989 let human = if x[key_pos_1].data_to_string() == "true" { "1" } else { "0" };
990 x[key_pos_0].data_to_string().to_string() + "-" + human + "-" + &x[key_pos_2].data_to_string() + &x[key_pos_3].data_to_string()
991 })
992 .collect::<Vec<_>>()
993 );
994 }
995
996 "campaign_effect_scope_agent_junctions_tables" => {
998 let key_pos_0 = definition.column_position_by_name("agent_key").unwrap_or_default();
999 let key_pos_1 = definition.column_position_by_name("campaign_effect_scope_key").unwrap_or_default();
1000
1001 keys.extend(self.data()
1002 .iter()
1003 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1004 .collect::<Vec<_>>()
1005 );
1006 }
1007
1008 "campaign_features_tables" => {
1010 let key_pos_0 = definition.column_position_by_name("feature").unwrap_or_default();
1011 let key_pos_1 = definition.column_position_by_name("group").unwrap_or_default();
1012
1013 keys.extend(self.data()
1014 .iter()
1015 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1016 .collect::<Vec<_>>()
1017 );
1018 }
1019
1020 "campaign_markers_tables" => {
1022 let key_pos_0 = definition.column_position_by_name("marker_type").unwrap_or_default();
1023 let key_pos_1 = definition.column_position_by_name("group").unwrap_or_default();
1024
1025 keys.extend(self.data()
1026 .iter()
1027 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1028 .collect::<Vec<_>>()
1029 );
1030 }
1031
1032 "campaign_mercenary_unit_character_level_restrictions_tables" => {
1034 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
1035 let key_pos_1 = definition.column_position_by_name("faction_override").unwrap_or_default();
1036
1037 keys.extend(self.data()
1038 .iter()
1039 .map(|x| {
1040 let fover = if x[key_pos_1].data_to_string().is_empty() {
1041 "".to_owned()
1042 } else {
1043 "_".to_string() + &x[key_pos_1].data_to_string()
1044 };
1045 x[key_pos_0].data_to_string().to_string() + &fover
1046 })
1047 .collect::<Vec<_>>()
1048 );
1049 }
1050
1051 "campaign_movement_spline_materials_tables" => {
1053 let key_pos_0 = definition.column_position_by_name("id").unwrap_or_default();
1054
1055 keys.extend(self.data()
1056 .iter()
1057 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_0].data_to_string())
1058 .collect::<Vec<_>>()
1059 );
1060 }
1061
1062 "campaign_rogue_army_leaders_tables" => {
1064 let key_pos_0 = definition.column_position_by_name("campaign");
1065 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1066
1067 keys.extend(self.data()
1068 .iter()
1069 .map(|x| {
1070 let camp = if let Some(y) = key_pos_0 { x[y].data_to_string().to_string() } else { "".to_owned() };
1071 camp + &x[key_pos_1].data_to_string()
1072 })
1073 .collect::<Vec<_>>()
1074 );
1075 }
1076
1077 "campaign_rogue_army_setups_tables" => {
1079 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1080 let key_pos_1 = definition.column_position_by_name("difficulty_level").unwrap_or_default();
1081
1082 keys.extend(self.data()
1083 .iter()
1084 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1085 .collect::<Vec<_>>()
1086 );
1087 }
1088
1089 "campaigns_campaign_variables_junctions_tables" => {
1091 let key_pos_0 = definition.column_position_by_name("variable_key").unwrap_or_default();
1092 let key_pos_1 = definition.column_position_by_name("campaign_name").unwrap_or_default();
1093 let key_pos_2 = definition.column_position_by_name("difficulty").unwrap_or_default();
1094 let key_pos_3 = definition.column_position_by_name("campaign_type").unwrap_or_default();
1095
1096 keys.extend(self.data()
1097 .iter()
1098 .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())
1099 .collect::<Vec<_>>()
1100 );
1101 }
1102
1103 "campaign_tree_type_cultures_tables" => {
1105 let key_pos_0 = definition.column_position_by_name("tree_type").unwrap_or_default();
1106 let key_pos_1 = definition.column_position_by_name("culture").unwrap_or_default();
1107
1108 keys.extend(self.data()
1109 .iter()
1110 .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())
1111 .collect::<Vec<_>>()
1112 );
1113 }
1114
1115 "cdir_events_mission_issuer_junctions_tables" => {
1117 let key_pos_0 = definition.column_position_by_name("issuer_key").unwrap_or_default();
1118 let key_pos_1 = definition.column_position_by_name("mission_key").unwrap_or_default();
1119
1120 keys.extend(self.data()
1121 .iter()
1122 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1123 .collect::<Vec<_>>()
1124 );
1125 }
1126
1127 "character_experience_skill_tiers_tables" => {
1129 let key_pos_0 = definition.column_position_by_name("for_army").unwrap_or_default();
1130 let key_pos_1 = definition.column_position_by_name("for_navy").unwrap_or_default();
1131 let key_pos_2 = definition.column_position_by_name("agent_key").unwrap_or_default();
1132 let key_pos_3 = definition.column_position_by_name("skill_rank").unwrap_or_default();
1133 let key_pos_4 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1134
1135 keys.extend(self.data()
1136 .iter()
1137 .map(|x| {
1138 let mut ckey = String::new();
1139 if x[key_pos_0].data_to_string() == "true" {
1140 if x[key_pos_1].data_to_string() == "true" {
1141 ckey.push_str("navy");
1142 } else {
1143 ckey.push_str("army");
1144 }
1145 } else {
1146 ckey.push_str(&x[key_pos_2].data_to_string());
1147 }
1148
1149 ckey + &x[key_pos_3].data_to_string() + &x[key_pos_4].data_to_string()
1150 })
1151 .collect::<Vec<_>>()
1152 );
1153 }
1154
1155 "culture_to_battle_animation_tables_tables" => {
1157 let key_pos_0 = definition.column_position_by_name("battle_animations_table").unwrap_or_default();
1158 let key_pos_1 = definition.column_position_by_name("culture_pack").unwrap_or_default();
1159
1160 keys.extend(self.data()
1161 .iter()
1162 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1163 .collect::<Vec<_>>()
1164 );
1165 }
1166
1167 "effect_bonus_value_id_action_results_additional_outcomes_junctions_tables" => {
1169 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1170 let key_pos_1 = definition.column_position_by_name("action_results_additional_outcome_record").unwrap_or_default();
1171 let key_pos_2 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1172
1173 keys.extend(self.data()
1174 .iter()
1175 .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())
1176 .collect::<Vec<_>>()
1177 );
1178 }
1179
1180 "effect_bonus_value_projectile_junctions_tables" => {
1182 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1183 let key_pos_1 = definition.column_position_by_name("bonus_value").unwrap_or_default();
1184 let key_pos_2 = definition.column_position_by_name("projectile").unwrap_or_default();
1185
1186 keys.extend(self.data()
1187 .iter()
1188 .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())
1189 .collect::<Vec<_>>()
1190 );
1191 }
1192
1193 "effect_bonus_value_unit_attribute_junctions_tables" => {
1195 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1196 let key_pos_1 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1197 let key_pos_2 = definition.column_position_by_name("unit_attribute").unwrap_or_default();
1198
1199 keys.extend(self.data()
1200 .iter()
1201 .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())
1202 .collect::<Vec<_>>()
1203 );
1204 }
1205
1206 "effect_bonus_value_unit_record_junctions_tables" => {
1208 let key_pos_0 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1209 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1210 let key_pos_2 = definition.column_position_by_name("unit_record_key").unwrap_or_default();
1211
1212 keys.extend(self.data()
1213 .iter()
1214 .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())
1215 .collect::<Vec<_>>()
1216 );
1217 }
1218
1219 "ground_type_to_stat_effects_tables" => {
1221 let key_pos_0 = definition.column_position_by_name("ground_type").unwrap_or_default();
1222 let key_pos_1 = definition.column_position_by_name("affected_stat").unwrap_or_default();
1223 let key_pos_2 = definition.column_position_by_name("affected_group").unwrap_or_default();
1224
1225 keys.extend(self.data()
1226 .iter()
1227 .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())
1228 .collect::<Vec<_>>()
1229 );
1230 }
1231
1232 "land_units_to_unit_abilites_junctions_tables" => {
1234 let key_pos_0 = definition.column_position_by_name("ability").unwrap_or_default();
1235 let key_pos_1 = definition.column_position_by_name("land_unit").unwrap_or_default();
1236
1237 keys.extend(self.data()
1238 .iter()
1239 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1240 .collect::<Vec<_>>()
1241 );
1242 }
1243
1244 "loading_screen_quotes_to_campaigns_tables" => {
1246 let key_pos_0 = definition.column_position_by_name("loading_quote").unwrap_or_default();
1247 let key_pos_1 = definition.column_position_by_name("campaign").unwrap_or_default();
1248
1249 keys.extend(self.data()
1250 .iter()
1251 .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())
1252 .collect::<Vec<_>>()
1253 );
1254 }
1255
1256 "message_event_strings_tables" => {
1258 let key_pos_0 = definition.column_position_by_name("event").unwrap_or_default();
1259 let key_pos_1 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1260 let key_pos_2 = definition.column_position_by_name("culture").unwrap_or_default();
1261 let key_pos_3 = definition.column_position_by_name("optional_subculture").unwrap_or_default();
1262
1263 keys.extend(self.data()
1264 .iter()
1265 .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())
1266 .collect::<Vec<_>>()
1267 );
1268 }
1269
1270 "mp_force_gen_template_junctions_tables" => {
1272 let key_pos_0 = definition.column_position_by_name("template_key").unwrap_or_default();
1273 let key_pos_1 = definition.column_position_by_name("battle_type").unwrap_or_default();
1274 let key_pos_2 = definition.column_position_by_name("is_defender").unwrap_or_default();
1275
1276 keys.extend(self.data()
1277 .iter()
1278 .map(|x| {
1279 let is_defender = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1280 x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + is_defender
1281 })
1282 .collect::<Vec<_>>()
1283 );
1284 }
1285
1286 "provincial_initiative_strength_levels_tables" => {
1288 let key_pos_0 = definition.column_position_by_name("initiative_record").unwrap_or_default();
1289 let key_pos_1 = definition.column_position_by_name("strength").unwrap_or_default();
1290
1291 keys.extend(self.data()
1292 .iter()
1293 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1294 .collect::<Vec<_>>()
1295 );
1296 }
1297
1298 "region_to_province_junctions_tables" => {
1300 let key_pos_0 = definition.column_position_by_name("province").unwrap_or_default();
1301 let key_pos_1 = definition.column_position_by_name("region").unwrap_or_default();
1302
1303 keys.extend(self.data()
1304 .iter()
1305 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1306 .collect::<Vec<_>>()
1307 );
1308 }
1309
1310 "ritual_payload_change_agent_capacities_tables" => {
1312 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1313 let key_pos_1 = definition.column_position_by_name("agent_record").unwrap_or_default();
1314
1315 keys.extend(self.data()
1316 .iter()
1317 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1318 .collect::<Vec<_>>()
1319 );
1320 }
1321
1322 "ritual_payload_change_unit_capacities_tables" => {
1324 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1325 let key_pos_1 = definition.column_position_by_name("unit_record").unwrap_or_default();
1326
1327 keys.extend(self.data()
1328 .iter()
1329 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1330 .collect::<Vec<_>>()
1331 );
1332 }
1333
1334 "slot_set_type_feature_junctions_tables" => {
1336 let key_pos_0 = definition.column_position_by_name("slot_set_type").unwrap_or_default();
1337 let key_pos_1 = definition.column_position_by_name("feature").unwrap_or_default();
1338
1339 keys.extend(self.data()
1340 .iter()
1341 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1342 .collect::<Vec<_>>()
1343 );
1344 }
1345
1346 "special_ability_to_special_ability_phase_junctions_tables" => {
1348 let key_pos_0 = definition.column_position_by_name("special_ability").unwrap_or_default();
1349 let key_pos_1 = definition.column_position_by_name("phase").unwrap_or_default();
1350 let key_pos_2 = definition.column_position_by_name("order").unwrap_or_default();
1351
1352 keys.extend(self.data()
1353 .iter()
1354 .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())
1355 .collect::<Vec<_>>()
1356 );
1357 }
1358
1359 "start_pos_region_slot_templates_tables" => {
1361 let key_pos_0 = definition.column_position_by_name("campaign").unwrap_or_default();
1362 let key_pos_1 = definition.column_position_by_name("id").unwrap_or_default();
1363 let key_pos_2 = definition.column_position_by_name("region").unwrap_or_default();
1364 let key_pos_3 = definition.column_position_by_name("slot_template").unwrap_or_default();
1365 let key_pos_4 = definition.column_position_by_name("slot_type").unwrap_or_default();
1366
1367 keys.extend(self.data()
1368 .iter()
1369 .map(|x|
1370 x[key_pos_0].data_to_string().to_string() +
1371 &x[key_pos_1].data_to_string() +
1372 &x[key_pos_2].data_to_string() +
1373 &x[key_pos_3].data_to_string() +
1374 &x[key_pos_4].data_to_string()
1375 )
1376 .collect::<Vec<_>>()
1377 );
1378 }
1379
1380 "start_pos_technologies_tables" => {
1382 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1383 let key_pos_1 = definition.column_position_by_name("technology").unwrap_or_default();
1384
1385 keys.extend(self.data()
1386 .iter()
1387 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1388 .collect::<Vec<_>>()
1389 );
1390 }
1391
1392 "taxes_effects_jct_tables" => {
1394 let key_pos_0 = definition.column_position_by_name("tax_name").unwrap_or_default();
1395 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1396 let key_pos_2 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1397 let key_pos_3 = definition.column_position_by_name("optional_difficulty_level").unwrap_or_default();
1398 let key_pos_4 = definition.column_position_by_name("ai_only").unwrap_or_default();
1399
1400 keys.extend(self.data()
1401 .iter()
1402 .map(|x| {
1403 let ai_only = if x[key_pos_4].data_to_string() == "true" { "1" } else { "0" };
1404 x[key_pos_0].data_to_string().to_string() + ";" +
1405 &x[key_pos_1].data_to_string() + ";" +
1406 &x[key_pos_2].data_to_string() + ";" +
1407 &x[key_pos_3].data_to_string() + ai_only
1408 })
1409 .collect::<Vec<_>>()
1410 );
1411 }
1412
1413 "ui_purchasable_effects_to_hex_ids_tables" => {
1415 let key_pos_0 = definition.column_position_by_name("hex_id").unwrap_or_default();
1416 let key_pos_1 = definition.column_position_by_name("category").unwrap_or_default();
1417
1418 keys.extend(self.data()
1419 .iter()
1420 .map(|x| x[key_pos_0].data_to_string().to_string() + "_" + &x[key_pos_1].data_to_string())
1421 .collect::<Vec<_>>()
1422 );
1423 }
1424
1425 "units_custom_battle_permissions_tables" => {
1427 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
1428 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1429 let key_pos_2 = definition.column_position_by_name("general_unit").unwrap_or_default();
1430
1431 keys.extend(self.data()
1432 .iter()
1433 .map(|x| {
1434 let general_unit = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1435 x[key_pos_0].data_to_string().to_string() + ":" + &x[key_pos_1].data_to_string() + ":" + general_unit
1436 })
1437 .collect::<Vec<_>>()
1438 );
1439 }
1440
1441 "workshop_categories_progress_levels_tables" => {
1443 let key_pos_0 = definition.column_position_by_name("category").unwrap_or_default();
1444 let key_pos_1 = definition.column_position_by_name("level_to_unlock").unwrap_or_default();
1445
1446 keys.extend(self.data()
1447 .iter()
1448 .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())
1449 .collect::<Vec<_>>()
1450 );
1451 }
1452
1453 _ => {
1455 let key_cols = definition.key_column_positions_by_ca_order();
1456 keys.extend(self.data()
1457 .iter()
1458 .map(|x| key_cols.iter()
1459 .map(|y| x[*y].data_to_string())
1460 .join("")
1461 )
1462 .collect::<Vec<_>>()
1463 );
1464 }
1465 }
1466 }
1467}
1468
1469impl From<TableInMemory> for DB {
1471 fn from(table: TableInMemory) -> Self {
1472 Self {
1473 mysterious_byte: true,
1474 guid: Uuid::new_v4().to_string(),
1475 table,
1476 }
1477 }
1478}