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::new("bool".to_owned(), FieldType::Boolean, false, Some("true".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
442 fields.push(Field::new("f32".to_owned(), FieldType::F32, false, Some("1.0".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
443 fields.push(Field::new("f64".to_owned(), FieldType::F64, false, Some("2.0".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
444 fields.push(Field::new("i16".to_owned(), FieldType::I16, false, Some("3".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
445 fields.push(Field::new("i32".to_owned(), FieldType::I32, false, Some("4".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
446 fields.push(Field::new("i64".to_owned(), FieldType::I64, false, Some("5".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
447 fields.push(Field::new("colour".to_owned(), FieldType::ColourRGB, false, Some("ABCDEF".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
448 fields.push(Field::new("stringu8".to_owned(), FieldType::StringU8, false, Some("AAAA".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
449 fields.push(Field::new("stringu16".to_owned(), FieldType::StringU16, false, Some("BBBB".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
450 fields.push(Field::new("optionali16".to_owned(), FieldType::OptionalI16, false, Some("3".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
451 fields.push(Field::new("optionali32".to_owned(), FieldType::OptionalI32, false, Some("4".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
452 fields.push(Field::new("optionali64".to_owned(), FieldType::OptionalI64, false, Some("5".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
453 fields.push(Field::new("optionalstringu8".to_owned(), FieldType::OptionalStringU8, false, Some("Opt".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
454 fields.push(Field::new("optionalstringu16".to_owned(), FieldType::OptionalStringU16, false, Some("Opt".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
455 fields.push(Field::new("sequenceu16".to_owned(), FieldType::SequenceU16(Box::new(Definition::new(-100, None))), false, None, false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
456 fields.push(Field::new("sequenceu32".to_owned(), FieldType::SequenceU32(Box::new(Definition::new(-100, None))), false, None, false, None, None, None, String::new(), 0, 0, BTreeMap::new(), None));
457
458 fields.push(Field::new("merged_colours_1_r".to_owned(), FieldType::I32, false, Some("AB".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), Some(0)));
460 fields.push(Field::new("merged_colours_1_g".to_owned(), FieldType::I32, false, Some("CD".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), Some(0)));
461 fields.push(Field::new("merged_colours_1_b".to_owned(), FieldType::I32, false, Some("EF".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), Some(0)));
462 fields.push(Field::new("bitwise_values".to_owned(), FieldType::I32, false, Some("4".to_string()), false, None, None, None, String::new(), 0, 5, BTreeMap::new(), None));
463 fields.push(Field::new("enum_values".to_owned(), FieldType::I32, false, Some("8".to_string()), false, None, None, None, String::new(), 0, 0, {
464 let mut bt = BTreeMap::new();
465 bt.insert(0, "test0".to_owned());
466 bt.insert(1, "test1".to_owned());
467 bt.insert(2, "test2".to_owned());
468 bt.insert(3, "test3".to_owned());
469 bt
470 }, None));
471
472 fields.push(Field::new("merged_colours_2_r".to_owned(), FieldType::I32, false, Some("AB".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), Some(1)));
473 fields.push(Field::new("merged_colours_2_g".to_owned(), FieldType::I32, false, Some("CD".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), Some(1)));
474 fields.push(Field::new("merged_colours_2_b".to_owned(), FieldType::I32, false, Some("EF".to_string()), false, None, None, None, String::new(), 0, 0, BTreeMap::new(), Some(1)));
475
476 definition.set_fields(fields);
479 definition
480 }
481
482 pub fn column_position_by_name(&self, column_name: &str) -> Option<usize> {
484 self.table.column_position_by_name(column_name)
485 }
486
487 pub fn len(&self) -> usize {
489 self.table.len()
490 }
491
492 pub fn is_empty(&self) -> bool {
494 self.table.is_empty()
495 }
496
497 pub fn set_definition(&mut self, new_definition: &Definition) {
502 self.table.set_definition(new_definition);
503 }
504
505 pub fn update(&mut self, new_definition: &Definition) {
507 self.set_definition(new_definition)
508 }
509
510 pub fn cascade_edition(pack: &mut Pack, schema: &Schema, table_name: &str, field: &Field, definition: &Definition, value_before: &str, value_after: &str) -> Vec<ContainerPath> {
530
531 let mut edited_paths = vec![];
537
538 if value_before == value_after {
540 return vec![];
541 }
542
543 let mut definition = definition.clone();
545 let patches = Some(definition.patches().clone());
546 let mut field = field.clone();
547 let mut table_name = table_name.to_owned();
548 while let Some((ref_table, ref_column)) = field.is_reference(patches.as_ref()) {
549 let ref_table_name = format!("{ref_table}_tables");
550 let table_folder = format!("db/{ref_table_name}");
551 let parent_files = pack.files_by_type_and_paths_mut(&[FileType::DB], &[ContainerPath::Folder(table_folder.to_owned())], true);
552 if !parent_files.is_empty() {
553 if let Ok(RFileDecoded::DB(table)) = parent_files[0].decoded() {
554 if let Some(index) = table.definition().column_position_by_name(&ref_column) {
555 definition = table.definition().clone();
556 field = definition.fields_processed()[index].clone();
557 table_name = table.table_name().to_owned();
558 continue;
559 }
560 }
561 }
562
563 break;
564 }
565
566 let fields_processed = definition.fields_processed();
568 let fields_localised = definition.localised_fields();
569 let (mut ref_table_data, _) = schema.tables_and_columns_referencing_our_own(&table_name, field.name(), &fields_processed, fields_localised);
570
571 ref_table_data.insert(table_name, vec![field.name().to_owned()]);
573
574 let container_paths = ref_table_data.keys().map(|ref_table_name| ContainerPath::Folder("db/".to_owned() + ref_table_name)).collect::<Vec<_>>();
575 let mut files = pack.files_by_paths_mut(&container_paths, true);
576 let mut loc_keys: Vec<(String, String)> = vec![];
577
578 for file in files.iter_mut() {
579 let path = file.path_in_container();
580 if let Ok(RFileDecoded::DB(table)) = file.decoded_mut() {
581 let fields_processed = table.definition().fields_processed();
582 let fields_localised = table.definition().localised_fields().to_vec();
583 let localised_order = table.definition().localised_key_order().to_vec();
584 let patches = table.definition().patches().clone();
585 let table_name = table.table_name().to_owned();
586 let table_name_no_tables = table.table_name_without_tables();
587 let table_data = table.data_mut();
588
589 let mut keys_edited = vec![];
590
591 let column_indexes = fields_processed.iter()
593 .enumerate()
594 .filter_map(|(index, field)| if ref_table_data[&table_name].iter().any(|name| name == field.name()) { Some(index) } else { None })
595 .collect::<Vec<usize>>();
596
597 for row in table_data.iter_mut() {
599 for column in &column_indexes {
600
601 let row_copy = row.to_vec();
603
604 if let Some(field_data) = row.get_mut(*column) {
605 match field_data {
606 DecodedData::StringU8(field_data) |
607 DecodedData::StringU16(field_data) |
608 DecodedData::OptionalStringU8(field_data) |
609 DecodedData::OptionalStringU16(field_data) => {
610
611 if field_data == value_before {
613 let mut locs_edited = vec![];
614
615 let is_key = fields_processed[*column].is_key(Some(&patches));
617 if is_key {
618 for loc_field in &fields_localised {
619 let loc_key = localised_order.iter().map(|pos| row_copy[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
620 locs_edited.push(format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key));
621 }
622 }
623
624 *field_data = value_after.to_owned();
625
626 if !locs_edited.is_empty() {
627 for (index, loc_field) in fields_localised.iter().enumerate() {
628 if let Some(key_old) = locs_edited.get(index) {
629 let loc_key = localised_order.iter().map(|pos| row[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
630 let key_new = format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key);
631 keys_edited.push((key_old.to_owned(), key_new.to_owned()))
632 }
633 }
634 }
635
636 if !edited_paths.contains(&path) {
637 edited_paths.push(path.clone());
638 }
639 }
640 }
641 _ => continue
642 }
643 }
644 }
645 }
646
647 if !keys_edited.is_empty() {
649 loc_keys.append(&mut keys_edited);
650 }
651 }
652 }
653
654 let mut loc_files = pack.files_by_type_mut(&[FileType::Loc]);
656 for file in &mut loc_files {
657 let path = file.path_in_container();
658 if let Ok(RFileDecoded::Loc(data)) = file.decoded_mut() {
659 let data = data.data_mut();
660 for row in data.iter_mut() {
661 if let Some(
662 DecodedData::StringU8(field_data) |
663 DecodedData::StringU16(field_data) |
664 DecodedData::OptionalStringU8(field_data) |
665 DecodedData::OptionalStringU16(field_data)
666 ) = row.get_mut(0) {
667 for (key_old, key_new) in &loc_keys {
668 if field_data == key_old {
669 *field_data = key_new.to_owned();
670
671 if !edited_paths.contains(&path) {
672 edited_paths.push(path.clone());
673 }
674 }
675 }
676 }
677 }
678 }
679 }
680
681 edited_paths
682 }
683
684 pub fn merge(sources: &[&Self]) -> Result<Self> {
696
697 let table_names = sources.iter().map(|file| file.table_name()).collect::<HashSet<_>>();
698 if table_names.len() > 1 {
699 return Err(RLibError::RFileMergeTablesDifferentNames);
700 }
701
702 if sources.len() < 2 {
703 return Err(RLibError::RFileMergeTablesNotEnoughTablesProvided);
704 }
705
706 let mut new_table = Self::new(sources[0].definition(), Some(sources[0].patches()), sources[0].table_name());
707 let sources = sources.par_iter()
708 .map(|table| {
709 let mut table = table.table().clone();
710 table.set_definition(new_table.definition());
711 table
712 })
713 .collect::<Vec<_>>();
714
715 let new_data = sources.par_iter()
716 .map(|table| table.data().to_vec())
717 .flatten()
718 .collect::<Vec<_>>();
719 new_table.set_data(&new_data)?;
720
721 Ok(new_table)
722 }
723
724 pub fn tsv_import(records: StringRecordsIter<File>, field_order: &HashMap<u32, String>, schema: &Schema, table_name: &str, table_version: i32) -> Result<Self> {
738 let definition = schema.definition_by_name_and_version(table_name, table_version).ok_or(RLibError::DecodingDBNoDefinitionsFound)?;
739 let definition_patch = schema.patches_for_table(table_name);
740 let table = TableInMemory::tsv_import(records, definition, field_order, table_name, definition_patch)?;
741 let db = DB::from(table);
742 Ok(db)
743 }
744
745 pub fn tsv_export(&self, writer: &mut Writer<File>, table_path: &str, keys_first: bool) -> Result<()> {
753 self.table.tsv_export(writer, table_path, keys_first)
754 }
755
756 pub fn altered(&self) -> bool {
758 *self.table.altered()
759 }
760
761 pub fn generate_twad_key_deletes_keys(&self, keys: &mut HashSet<String>) {
766 let definition = self.definition();
767 match self.table_name() {
768
769 "agent_to_agent_attributes_tables" => {
771 let key_pos_0 = definition.column_position_by_name("agent").unwrap_or_default();
772 let key_pos_1 = definition.column_position_by_name("attribute").unwrap_or_default();
773
774 keys.extend(self.data()
775 .iter()
776 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
777 .collect::<Vec<_>>()
778 );
779 }
780
781 "animation_set_prebattle_group_view_configurations_tables" => {
783 let key_pos_0 = definition.column_position_by_name("attacker").unwrap_or_default();
784 let key_pos_1 = definition.column_position_by_name("defender").unwrap_or_default();
785
786 keys.extend(self.data()
787 .iter()
788 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
789 .collect::<Vec<_>>()
790 );
791 }
792
793 "armory_item_variants_tables" => {
795 let key_pos_0 = definition.column_position_by_name("armory_item").unwrap_or_default();
796 let key_pos_1 = definition.column_position_by_name("variant").unwrap_or_default();
797
798 keys.extend(self.data()
799 .iter()
800 .map(|x| x[key_pos_0].data_to_string().to_string() + " | " + &x[key_pos_1].data_to_string())
801 .collect::<Vec<_>>()
802 );
803 }
804
805 "battle_currency_deployables_cost_values_tables" => {
807 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
808 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
809
810 keys.extend(self.data()
811 .iter()
812 .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())
813 .collect::<Vec<_>>()
814 );
815 }
816
817 "battle_currency_units_cost_values_tables" => {
819 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
820 let key_pos_1 = definition.column_position_by_name("currency_type").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() + &x[key_pos_0].data_to_string())
825 .collect::<Vec<_>>()
826 );
827 }
828
829 "battle_set_pieces_siege_items_tables" => {
831 let key_pos_0 = definition.column_position_by_name("army_name").unwrap_or_default();
832 let key_pos_1 = definition.column_position_by_name("siege_item").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() + &x[key_pos_0].data_to_string())
837 .collect::<Vec<_>>()
838 );
839 }
840
841 "cai_agent_type_distribution_profile_junctions_tables" => {
843 let key_pos_0 = definition.column_position_by_name("distribution_profile_key").unwrap_or_default();
844 let key_pos_1 = definition.column_position_by_name("agent_type_key").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 "cai_agent_type_recruitment_profile_junctions_tables" => {
855 let key_pos_0 = definition.column_position_by_name("recruitment_profile_key").unwrap_or_default();
856 let key_pos_1 = definition.column_position_by_name("agent_type_key").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())
861 .collect::<Vec<_>>()
862 );
863 }
864
865 "cai_personalities_budget_allocation_policy_junctions_tables" => {
867 let key_pos_0 = definition.column_position_by_name("budget_allocation_key").unwrap_or_default();
868 let key_pos_1 = definition.column_position_by_name("budget_context_key").unwrap_or_default();
869 let key_pos_2 = definition.column_position_by_name("budget_policy_key").unwrap_or_default();
870
871 keys.extend(self.data()
872 .iter()
873 .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())
874 .collect::<Vec<_>>()
875 );
876 }
877
878 "cai_personalities_construction_preference_policy_building_junctions_tables" => {
880 let key_pos_0 = definition.column_position_by_name("building_key").unwrap_or_default();
881 let key_pos_1 = definition.column_position_by_name("policy_key").unwrap_or_default();
882
883 keys.extend(self.data()
884 .iter()
885 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
886 .collect::<Vec<_>>()
887 );
888 }
889
890 "cai_task_management_system_task_generator_variable_group_junctions_tables" => {
892 let key_pos_0 = definition.column_position_by_name("variable_group_key").unwrap_or_default();
893 let key_pos_1 = definition.column_position_by_name("variable_key").unwrap_or_default();
894
895 keys.extend(self.data()
896 .iter()
897 .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())
898 .collect::<Vec<_>>()
899 );
900 }
901
902 "campaign_ai_manager_behaviour_junctions_tables" => {
904 let key_pos_0 = definition.column_position_by_name("manager").unwrap_or_default();
905 let key_pos_1 = definition.column_position_by_name("behaviour").unwrap_or_default();
906
907 keys.extend(self.data()
908 .iter()
909 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
910 .collect::<Vec<_>>()
911 );
912 }
913
914 "campaign_bmd_layer_group_bmd_export_types_junctions_tables" => {
916 let key_pos_0 = definition.column_position_by_name("bmd_export_types").unwrap_or_default();
917 let key_pos_1 = definition.column_position_by_name("campaign_bmd_layer_group").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())
922 .collect::<Vec<_>>()
923 );
924 }
925
926 "campaign_difficulty_handicap_effects_tables" => {
928 let key_pos_0 = definition.column_position_by_name("campaign_difficulty_handicap").unwrap_or_default();
929 let key_pos_1 = definition.column_position_by_name("human").unwrap_or_default();
930 let key_pos_2 = definition.column_position_by_name("effect").unwrap_or_default();
931 let key_pos_3 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
932
933 keys.extend(self.data()
934 .iter()
935 .map(|x| {
936 let human = if x[key_pos_1].data_to_string() == "true" { "1" } else { "0" };
937 x[key_pos_0].data_to_string().to_string() + "-" + human + "-" + &x[key_pos_2].data_to_string() + &x[key_pos_3].data_to_string()
938 })
939 .collect::<Vec<_>>()
940 );
941 }
942
943 "campaign_effect_scope_agent_junctions_tables" => {
945 let key_pos_0 = definition.column_position_by_name("agent_key").unwrap_or_default();
946 let key_pos_1 = definition.column_position_by_name("campaign_effect_scope_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())
951 .collect::<Vec<_>>()
952 );
953 }
954
955 "campaign_features_tables" => {
957 let key_pos_0 = definition.column_position_by_name("feature").unwrap_or_default();
958 let key_pos_1 = definition.column_position_by_name("group").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_markers_tables" => {
969 let key_pos_0 = definition.column_position_by_name("marker_type").unwrap_or_default();
970 let key_pos_1 = definition.column_position_by_name("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_mercenary_unit_character_level_restrictions_tables" => {
981 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
982 let key_pos_1 = definition.column_position_by_name("faction_override").unwrap_or_default();
983
984 keys.extend(self.data()
985 .iter()
986 .map(|x| {
987 let fover = if x[key_pos_1].data_to_string().is_empty() {
988 "".to_owned()
989 } else {
990 "_".to_string() + &x[key_pos_1].data_to_string()
991 };
992 x[key_pos_0].data_to_string().to_string() + &fover
993 })
994 .collect::<Vec<_>>()
995 );
996 }
997
998 "campaign_movement_spline_materials_tables" => {
1000 let key_pos_0 = definition.column_position_by_name("id").unwrap_or_default();
1001
1002 keys.extend(self.data()
1003 .iter()
1004 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_0].data_to_string())
1005 .collect::<Vec<_>>()
1006 );
1007 }
1008
1009 "campaign_rogue_army_leaders_tables" => {
1011 let key_pos_0 = definition.column_position_by_name("campaign");
1012 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1013
1014 keys.extend(self.data()
1015 .iter()
1016 .map(|x| {
1017 let camp = if let Some(y) = key_pos_0 { x[y].data_to_string().to_string() } else { "".to_owned() };
1018 camp + &x[key_pos_1].data_to_string()
1019 })
1020 .collect::<Vec<_>>()
1021 );
1022 }
1023
1024 "campaign_rogue_army_setups_tables" => {
1026 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1027 let key_pos_1 = definition.column_position_by_name("difficulty_level").unwrap_or_default();
1028
1029 keys.extend(self.data()
1030 .iter()
1031 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1032 .collect::<Vec<_>>()
1033 );
1034 }
1035
1036 "campaigns_campaign_variables_junctions_tables" => {
1038 let key_pos_0 = definition.column_position_by_name("variable_key").unwrap_or_default();
1039 let key_pos_1 = definition.column_position_by_name("campaign_name").unwrap_or_default();
1040 let key_pos_2 = definition.column_position_by_name("difficulty").unwrap_or_default();
1041 let key_pos_3 = definition.column_position_by_name("campaign_type").unwrap_or_default();
1042
1043 keys.extend(self.data()
1044 .iter()
1045 .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())
1046 .collect::<Vec<_>>()
1047 );
1048 }
1049
1050 "campaign_tree_type_cultures_tables" => {
1052 let key_pos_0 = definition.column_position_by_name("tree_type").unwrap_or_default();
1053 let key_pos_1 = definition.column_position_by_name("culture").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_1].data_to_string() + &x[key_pos_0].data_to_string())
1058 .collect::<Vec<_>>()
1059 );
1060 }
1061
1062 "cdir_events_mission_issuer_junctions_tables" => {
1064 let key_pos_0 = definition.column_position_by_name("issuer_key").unwrap_or_default();
1065 let key_pos_1 = definition.column_position_by_name("mission_key").unwrap_or_default();
1066
1067 keys.extend(self.data()
1068 .iter()
1069 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1070 .collect::<Vec<_>>()
1071 );
1072 }
1073
1074 "character_experience_skill_tiers_tables" => {
1076 let key_pos_0 = definition.column_position_by_name("for_army").unwrap_or_default();
1077 let key_pos_1 = definition.column_position_by_name("for_navy").unwrap_or_default();
1078 let key_pos_2 = definition.column_position_by_name("agent_key").unwrap_or_default();
1079 let key_pos_3 = definition.column_position_by_name("skill_rank").unwrap_or_default();
1080 let key_pos_4 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1081
1082 keys.extend(self.data()
1083 .iter()
1084 .map(|x| {
1085 let mut ckey = String::new();
1086 if x[key_pos_0].data_to_string() == "true" {
1087 if x[key_pos_1].data_to_string() == "true" {
1088 ckey.push_str("navy");
1089 } else {
1090 ckey.push_str("army");
1091 }
1092 } else {
1093 ckey.push_str(&x[key_pos_2].data_to_string());
1094 }
1095
1096 ckey + &x[key_pos_3].data_to_string() + &x[key_pos_4].data_to_string()
1097 })
1098 .collect::<Vec<_>>()
1099 );
1100 }
1101
1102 "culture_to_battle_animation_tables_tables" => {
1104 let key_pos_0 = definition.column_position_by_name("battle_animations_table").unwrap_or_default();
1105 let key_pos_1 = definition.column_position_by_name("culture_pack").unwrap_or_default();
1106
1107 keys.extend(self.data()
1108 .iter()
1109 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1110 .collect::<Vec<_>>()
1111 );
1112 }
1113
1114 "effect_bonus_value_id_action_results_additional_outcomes_junctions_tables" => {
1116 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1117 let key_pos_1 = definition.column_position_by_name("action_results_additional_outcome_record").unwrap_or_default();
1118 let key_pos_2 = definition.column_position_by_name("bonus_value_id").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() + &x[key_pos_2].data_to_string())
1123 .collect::<Vec<_>>()
1124 );
1125 }
1126
1127 "effect_bonus_value_projectile_junctions_tables" => {
1129 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1130 let key_pos_1 = definition.column_position_by_name("bonus_value").unwrap_or_default();
1131 let key_pos_2 = definition.column_position_by_name("projectile").unwrap_or_default();
1132
1133 keys.extend(self.data()
1134 .iter()
1135 .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())
1136 .collect::<Vec<_>>()
1137 );
1138 }
1139
1140 "effect_bonus_value_unit_attribute_junctions_tables" => {
1142 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1143 let key_pos_1 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1144 let key_pos_2 = definition.column_position_by_name("unit_attribute").unwrap_or_default();
1145
1146 keys.extend(self.data()
1147 .iter()
1148 .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())
1149 .collect::<Vec<_>>()
1150 );
1151 }
1152
1153 "effect_bonus_value_unit_record_junctions_tables" => {
1155 let key_pos_0 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1156 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1157 let key_pos_2 = definition.column_position_by_name("unit_record_key").unwrap_or_default();
1158
1159 keys.extend(self.data()
1160 .iter()
1161 .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())
1162 .collect::<Vec<_>>()
1163 );
1164 }
1165
1166 "ground_type_to_stat_effects_tables" => {
1168 let key_pos_0 = definition.column_position_by_name("ground_type").unwrap_or_default();
1169 let key_pos_1 = definition.column_position_by_name("affected_stat").unwrap_or_default();
1170 let key_pos_2 = definition.column_position_by_name("affected_group").unwrap_or_default();
1171
1172 keys.extend(self.data()
1173 .iter()
1174 .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())
1175 .collect::<Vec<_>>()
1176 );
1177 }
1178
1179 "land_units_to_unit_abilites_junctions_tables" => {
1181 let key_pos_0 = definition.column_position_by_name("ability").unwrap_or_default();
1182 let key_pos_1 = definition.column_position_by_name("land_unit").unwrap_or_default();
1183
1184 keys.extend(self.data()
1185 .iter()
1186 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1187 .collect::<Vec<_>>()
1188 );
1189 }
1190
1191 "loading_screen_quotes_to_campaigns_tables" => {
1193 let key_pos_0 = definition.column_position_by_name("loading_quote").unwrap_or_default();
1194 let key_pos_1 = definition.column_position_by_name("campaign").unwrap_or_default();
1195
1196 keys.extend(self.data()
1197 .iter()
1198 .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())
1199 .collect::<Vec<_>>()
1200 );
1201 }
1202
1203 "message_event_strings_tables" => {
1205 let key_pos_0 = definition.column_position_by_name("event").unwrap_or_default();
1206 let key_pos_1 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1207 let key_pos_2 = definition.column_position_by_name("culture").unwrap_or_default();
1208 let key_pos_3 = definition.column_position_by_name("optional_subculture").unwrap_or_default();
1209
1210 keys.extend(self.data()
1211 .iter()
1212 .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())
1213 .collect::<Vec<_>>()
1214 );
1215 }
1216
1217 "mp_force_gen_template_junctions_tables" => {
1219 let key_pos_0 = definition.column_position_by_name("template_key").unwrap_or_default();
1220 let key_pos_1 = definition.column_position_by_name("battle_type").unwrap_or_default();
1221 let key_pos_2 = definition.column_position_by_name("is_defender").unwrap_or_default();
1222
1223 keys.extend(self.data()
1224 .iter()
1225 .map(|x| {
1226 let is_defender = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1227 x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + is_defender
1228 })
1229 .collect::<Vec<_>>()
1230 );
1231 }
1232
1233 "provincial_initiative_strength_levels_tables" => {
1235 let key_pos_0 = definition.column_position_by_name("initiative_record").unwrap_or_default();
1236 let key_pos_1 = definition.column_position_by_name("strength").unwrap_or_default();
1237
1238 keys.extend(self.data()
1239 .iter()
1240 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1241 .collect::<Vec<_>>()
1242 );
1243 }
1244
1245 "region_to_province_junctions_tables" => {
1247 let key_pos_0 = definition.column_position_by_name("province").unwrap_or_default();
1248 let key_pos_1 = definition.column_position_by_name("region").unwrap_or_default();
1249
1250 keys.extend(self.data()
1251 .iter()
1252 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1253 .collect::<Vec<_>>()
1254 );
1255 }
1256
1257 "ritual_payload_change_agent_capacities_tables" => {
1259 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1260 let key_pos_1 = definition.column_position_by_name("agent_record").unwrap_or_default();
1261
1262 keys.extend(self.data()
1263 .iter()
1264 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1265 .collect::<Vec<_>>()
1266 );
1267 }
1268
1269 "ritual_payload_change_unit_capacities_tables" => {
1271 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1272 let key_pos_1 = definition.column_position_by_name("unit_record").unwrap_or_default();
1273
1274 keys.extend(self.data()
1275 .iter()
1276 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1277 .collect::<Vec<_>>()
1278 );
1279 }
1280
1281 "slot_set_type_feature_junctions_tables" => {
1283 let key_pos_0 = definition.column_position_by_name("slot_set_type").unwrap_or_default();
1284 let key_pos_1 = definition.column_position_by_name("feature").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 "special_ability_to_special_ability_phase_junctions_tables" => {
1295 let key_pos_0 = definition.column_position_by_name("special_ability").unwrap_or_default();
1296 let key_pos_1 = definition.column_position_by_name("phase").unwrap_or_default();
1297 let key_pos_2 = definition.column_position_by_name("order").unwrap_or_default();
1298
1299 keys.extend(self.data()
1300 .iter()
1301 .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())
1302 .collect::<Vec<_>>()
1303 );
1304 }
1305
1306 "start_pos_region_slot_templates_tables" => {
1308 let key_pos_0 = definition.column_position_by_name("campaign").unwrap_or_default();
1309 let key_pos_1 = definition.column_position_by_name("id").unwrap_or_default();
1310 let key_pos_2 = definition.column_position_by_name("region").unwrap_or_default();
1311 let key_pos_3 = definition.column_position_by_name("slot_template").unwrap_or_default();
1312 let key_pos_4 = definition.column_position_by_name("slot_type").unwrap_or_default();
1313
1314 keys.extend(self.data()
1315 .iter()
1316 .map(|x|
1317 x[key_pos_0].data_to_string().to_string() +
1318 &x[key_pos_1].data_to_string() +
1319 &x[key_pos_2].data_to_string() +
1320 &x[key_pos_3].data_to_string() +
1321 &x[key_pos_4].data_to_string()
1322 )
1323 .collect::<Vec<_>>()
1324 );
1325 }
1326
1327 "start_pos_technologies_tables" => {
1329 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1330 let key_pos_1 = definition.column_position_by_name("technology").unwrap_or_default();
1331
1332 keys.extend(self.data()
1333 .iter()
1334 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1335 .collect::<Vec<_>>()
1336 );
1337 }
1338
1339 "taxes_effects_jct_tables" => {
1341 let key_pos_0 = definition.column_position_by_name("tax_name").unwrap_or_default();
1342 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1343 let key_pos_2 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1344 let key_pos_3 = definition.column_position_by_name("optional_difficulty_level").unwrap_or_default();
1345 let key_pos_4 = definition.column_position_by_name("ai_only").unwrap_or_default();
1346
1347 keys.extend(self.data()
1348 .iter()
1349 .map(|x| {
1350 let ai_only = if x[key_pos_4].data_to_string() == "true" { "1" } else { "0" };
1351 x[key_pos_0].data_to_string().to_string() + ";" +
1352 &x[key_pos_1].data_to_string() + ";" +
1353 &x[key_pos_2].data_to_string() + ";" +
1354 &x[key_pos_3].data_to_string() + ai_only
1355 })
1356 .collect::<Vec<_>>()
1357 );
1358 }
1359
1360 "ui_purchasable_effects_to_hex_ids_tables" => {
1362 let key_pos_0 = definition.column_position_by_name("hex_id").unwrap_or_default();
1363 let key_pos_1 = definition.column_position_by_name("category").unwrap_or_default();
1364
1365 keys.extend(self.data()
1366 .iter()
1367 .map(|x| x[key_pos_0].data_to_string().to_string() + "_" + &x[key_pos_1].data_to_string())
1368 .collect::<Vec<_>>()
1369 );
1370 }
1371
1372 "units_custom_battle_permissions_tables" => {
1374 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
1375 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1376 let key_pos_2 = definition.column_position_by_name("general_unit").unwrap_or_default();
1377
1378 keys.extend(self.data()
1379 .iter()
1380 .map(|x| {
1381 let general_unit = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1382 x[key_pos_0].data_to_string().to_string() + ":" + &x[key_pos_1].data_to_string() + ":" + general_unit
1383 })
1384 .collect::<Vec<_>>()
1385 );
1386 }
1387
1388 "workshop_categories_progress_levels_tables" => {
1390 let key_pos_0 = definition.column_position_by_name("category").unwrap_or_default();
1391 let key_pos_1 = definition.column_position_by_name("level_to_unlock").unwrap_or_default();
1392
1393 keys.extend(self.data()
1394 .iter()
1395 .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())
1396 .collect::<Vec<_>>()
1397 );
1398 }
1399
1400 _ => {
1402 let key_cols = definition.key_column_positions_by_ca_order();
1403 keys.extend(self.data()
1404 .iter()
1405 .map(|x| key_cols.iter()
1406 .map(|y| x[*y].data_to_string())
1407 .join("")
1408 )
1409 .collect::<Vec<_>>()
1410 );
1411 }
1412 }
1413 }
1414}
1415
1416impl From<TableInMemory> for DB {
1418 fn from(table: TableInMemory) -> Self {
1419 Self {
1420 mysterious_byte: true,
1421 guid: Uuid::new_v4().to_string(),
1422 table,
1423 }
1424 }
1425}