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;
72use std::collections::{HashMap, HashSet};
73use std::fs::File;
74use std::io::SeekFrom;
75
76use crate::binary::{ReadBytes, WriteBytes};
77use crate::error::{RLibError, Result};
78use crate::files::{Container, ContainerPath, DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable, FileType, table::{decode_table, DecodedData, local::TableInMemory, Table}, pack::Pack, RFileDecoded};
79use crate::schema::{Definition, DefinitionPatch, Field, Schema};
80use crate::utils::check_size_mismatch;
81
82const GUID_MARKER: &[u8] = &[253, 254, 252, 255];
84
85const VERSION_MARKER: &[u8] = &[252, 253, 254, 255];
87
88#[cfg(test)] mod db_test;
89
90#[derive(PartialEq, Clone, Debug, Getters, Serialize, Deserialize)]
144#[getset(get = "pub")]
145pub struct DB {
146
147 mysterious_byte: bool,
151
152 guid: String,
156
157 table: TableInMemory,
159}
160
161impl Decodeable for DB {
166
167 fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
168 let extra_data = extra_data.as_ref().ok_or(RLibError::DecodingMissingExtraData)?;
169 let schema = extra_data.schema.ok_or_else(|| RLibError::DecodingMissingExtraDataField("schema".to_owned()))?;
170 let table_name = extra_data.table_name.ok_or_else(|| RLibError::DecodingMissingExtraDataField("table_name".to_owned()))?;
171 let return_incomplete = extra_data.return_incomplete;
172
173 let (version, mysterious_byte, guid, entry_count) = Self::read_header(data)?;
174
175 let definitions = schema.definitions_by_table_name(table_name).ok_or({
177 if entry_count == 0 {
178 RLibError::DecodingDBNoDefinitionsFoundAndEmptyFile
179 } else {
180 RLibError::DecodingDBNoDefinitionsFound
181 }
182 })?;
183
184 let len = data.len()?;
186 let table = if version == 0 {
187 let mut altered = false;
188 let index_reset = data.stream_position()?;
189
190 let mut working_definition = Err(RLibError::DecodingDBNoDefinitionsFound);
192 for definition in definitions.iter().filter(|definition| *definition.version() < 1) {
193
194 data.seek(SeekFrom::Start(index_reset))?;
197 let db = decode_table(data, definition, Some(entry_count), return_incomplete, &mut altered);
198 if db.is_ok() && data.stream_position()? == len {
199 working_definition = Ok(definition);
200 break;
201 }
202 }
203
204 let definition = working_definition?;
205 let definition_patch = schema.patches_for_table(table_name).cloned().unwrap_or_default();
206
207 data.seek(SeekFrom::Start(index_reset))?;
209 TableInMemory::decode(data, definition, &definition_patch, Some(entry_count), return_incomplete, table_name)?
210 }
211
212 else {
214
215 let definition = definitions.iter()
216 .find(|definition| *definition.version() == version)
217 .ok_or(RLibError::DecodingDBNoDefinitionsFound)?;
218
219 let definition_patch = schema.patches_for_table(table_name).cloned().unwrap_or_default();
220 TableInMemory::decode(data, definition, &definition_patch, Some(entry_count), return_incomplete, table_name)?
221 };
222
223 check_size_mismatch(data.stream_position()? as usize, len as usize).map_err(|error| {
227 RLibError::DecodingTableIncomplete(error.to_string(), Box::new(table.clone()))
228 })?;
229
230 Ok(Self {
232 mysterious_byte,
233 guid,
234 table,
235 })
236 }
237}
238
239impl Encodeable for DB {
240
241 fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
242 let table_has_guid = if let Some (ref extra_data) = extra_data { extra_data.table_has_guid } else { false };
243 let regenerate_table_guid = if let Some (ref extra_data) = extra_data { extra_data.regenerate_table_guid } else { false };
244
245 if table_has_guid {
248 buffer.write_all(GUID_MARKER)?;
249 if regenerate_table_guid || self.guid.is_empty() {
250 buffer.write_sized_string_u16(&Uuid::new_v4().to_string())?;
251 } else {
252 buffer.write_sized_string_u16(&self.guid)?;
253 }
254 }
255
256 if *self.table.definition().version() > 0 {
258 buffer.write_all(VERSION_MARKER)?;
259 buffer.write_i32(*self.table.definition().version())?;
260 }
261
262 buffer.write_bool(self.mysterious_byte)?;
263 buffer.write_u32(self.table.len() as u32)?;
264
265 self.table.encode(buffer)
266 }
267}
268
269impl DB {
270
271 pub fn new(definition: &Definition, definition_patch: Option<&DefinitionPatch>, table_name: &str) -> Self {
297 let table = TableInMemory::new(definition, definition_patch, table_name);
298
299 Self {
300 mysterious_byte: true,
301 guid: String::new(),
302 table,
303 }
304 }
305
306 pub fn read_header<R: ReadBytes>(data: &mut R) -> Result<(i32, bool, String, u32)> {
341
342 if data.len()? < 5 {
345 return Err(RLibError::DecodingDBNotADBTable);
346 }
347
348 let guid = if data.read_slice(4, false)? == GUID_MARKER {
350 data.read_sized_string_u16()?
351 } else {
352 data.seek(SeekFrom::Current(-4))?;
353 String::new()
354 };
355
356 let version = if data.read_slice(4, false)? == VERSION_MARKER {
359 data.read_i32()?
360 } else {
361 data.seek(SeekFrom::Current(-4))?;
362 0
363 };
364
365 let mysterious_byte = data.read_bool()?;
367 let entry_count = data.read_u32()?;
368 Ok((version, mysterious_byte, guid, entry_count))
369 }
370
371 pub fn definition(&self) -> &Definition {
373 self.table.definition()
374 }
375
376 pub fn patches(&self) -> &DefinitionPatch {
378 self.table.patches()
379 }
380
381 pub fn table_name(&self) -> &str {
383 self.table.table_name()
384 }
385
386 pub fn table_name_without_tables(&self) -> String {
392
393 if self.table_name().ends_with("_tables") {
395 self.table_name().to_owned().drain(..self.table_name().len() - 7).collect()
396 } else {
397 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.")
398 }
399 }
400
401 pub fn data(&'_ self) -> Cow<'_, [Vec<DecodedData>]> {
403 self.table.data()
404 }
405
406 #[cfg(feature = "integration_sqlite")]
408 pub fn sql_to_db(&mut self, pool: &Pool<SqliteConnectionManager>, pack_name: &str, file_name: &str) -> Result<()> {
409 self.table.sql_to_db(pool, pack_name, file_name)
410 }
411
412 pub fn data_mut(&mut self) -> &mut Vec<Vec<DecodedData>> {
416 self.table.data_mut()
417 }
418
419 pub fn set_data(&mut self, data: &[Vec<DecodedData>]) -> Result<()> {
425 self.table.set_data(data)
426 }
427
428 pub fn set_guid(&mut self, guid: String) {
430 self.guid = guid;
431 }
432
433 pub fn new_row(&self) -> Vec<DecodedData> {
435 self.table().new_row()
436 }
437
438 pub fn column_position_by_name(&self, column_name: &str) -> Option<usize> {
440 self.table.column_position_by_name(column_name)
441 }
442
443 pub fn len(&self) -> usize {
445 self.table.len()
446 }
447
448 pub fn is_empty(&self) -> bool {
450 self.table.is_empty()
451 }
452
453 pub fn set_definition(&mut self, new_definition: &Definition) {
458 self.table.set_definition(new_definition);
459 }
460
461 pub fn update(&mut self, new_definition: &Definition) {
463 self.set_definition(new_definition)
464 }
465
466 pub fn cascade_edition(pack: &mut Pack, schema: &Schema, table_name: &str, field: &Field, definition: &Definition, value_before: &str, value_after: &str) -> Vec<ContainerPath> {
486
487 let mut edited_paths = vec![];
493
494 if value_before == value_after {
496 return vec![];
497 }
498
499 let mut definition = definition.clone();
501 let patches = Some(definition.patches().clone());
502 let mut field = field.clone();
503 let mut table_name = table_name.to_owned();
504 while let Some((ref_table, ref_column)) = field.is_reference(patches.as_ref()) {
505 let ref_table_name = format!("{ref_table}_tables");
506 let parent_files = pack.files_by_type_and_paths_mut(&[FileType::DB], &ContainerPath::db_table_folders(&ref_table_name), true);
507 if !parent_files.is_empty() {
508 if let Ok(RFileDecoded::DB(table)) = parent_files[0].decoded() {
509 if let Some(index) = table.definition().column_position_by_name(&ref_column) {
510 definition = table.definition().clone();
511 field = definition.fields_processed()[index].clone();
512 table_name = table.table_name().to_owned();
513 continue;
514 }
515 }
516 }
517
518 break;
519 }
520
521 let fields_processed = definition.fields_processed();
523 let fields_localised = definition.localised_fields();
524 let (mut ref_table_data, _) = schema.tables_and_columns_referencing_our_own(&table_name, field.name(), fields_processed, fields_localised);
525
526 ref_table_data.insert(table_name, vec![field.name().to_owned()]);
528
529 let container_paths = ref_table_data.keys().flat_map(|ref_table_name| ContainerPath::db_table_folders(ref_table_name)).collect::<Vec<_>>();
530 let mut files = pack.files_by_paths_mut(&container_paths, true);
531 let mut loc_keys: Vec<(String, String)> = vec![];
532
533 for file in files.iter_mut() {
534 let path = file.path_in_container();
535 if let Ok(RFileDecoded::DB(table)) = file.decoded_mut() {
536 let fields_processed = table.definition().fields_processed().to_vec();
537 let fields_localised = table.definition().localised_fields().to_vec();
538 let localised_order = table.definition().localised_key_order().to_vec();
539 let patches = table.definition().patches().clone();
540 let table_name = table.table_name().to_owned();
541 let table_name_no_tables = table.table_name_without_tables();
542 let table_data = table.data_mut();
543
544 let mut keys_edited = vec![];
545
546 let column_indexes = fields_processed.iter()
548 .enumerate()
549 .filter_map(|(index, field)| if ref_table_data[&table_name].iter().any(|name| name == field.name()) { Some(index) } else { None })
550 .collect::<Vec<usize>>();
551
552 for row in table_data.iter_mut() {
554 for column in &column_indexes {
555
556 let row_copy = row.to_vec();
558
559 if let Some(field_data) = row.get_mut(*column) {
560 match field_data {
561 DecodedData::StringU8(field_data) |
562 DecodedData::StringU16(field_data) |
563 DecodedData::OptionalStringU8(field_data) |
564 DecodedData::OptionalStringU16(field_data) => {
565
566 if field_data == value_before {
568 let mut locs_edited = vec![];
569
570 let is_key = fields_processed[*column].is_key(Some(&patches));
572 if is_key {
573 for loc_field in &fields_localised {
574 let loc_key = localised_order.iter().map(|pos| row_copy[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
575 locs_edited.push(format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key));
576 }
577 }
578
579 *field_data = value_after.to_owned();
580
581 if !locs_edited.is_empty() {
582 for (index, loc_field) in fields_localised.iter().enumerate() {
583 if let Some(key_old) = locs_edited.get(index) {
584 let loc_key = localised_order.iter().map(|pos| row[*pos as usize].data_to_string()).collect::<Vec<_>>().join("");
585 let key_new = format!("{}_{}_{}", table_name_no_tables, loc_field.name(), loc_key);
586 keys_edited.push((key_old.to_owned(), key_new.to_owned()))
587 }
588 }
589 }
590
591 if !edited_paths.contains(&path) {
592 edited_paths.push(path.clone());
593 }
594 }
595 }
596 _ => continue
597 }
598 }
599 }
600 }
601
602 if !keys_edited.is_empty() {
604 loc_keys.append(&mut keys_edited);
605 }
606 }
607 }
608
609 let mut loc_files = pack.files_by_type_mut(&[FileType::Loc]);
611 for file in &mut loc_files {
612 let path = file.path_in_container();
613 if let Ok(RFileDecoded::Loc(data)) = file.decoded_mut() {
614 let data = data.data_mut();
615 for row in data.iter_mut() {
616 if let Some(
617 DecodedData::StringU8(field_data) |
618 DecodedData::StringU16(field_data) |
619 DecodedData::OptionalStringU8(field_data) |
620 DecodedData::OptionalStringU16(field_data)
621 ) = row.get_mut(0) {
622 for (key_old, key_new) in &loc_keys {
623 if field_data == key_old {
624 *field_data = key_new.to_owned();
625
626 if !edited_paths.contains(&path) {
627 edited_paths.push(path.clone());
628 }
629 }
630 }
631 }
632 }
633 }
634 }
635
636 edited_paths
637 }
638
639 pub fn merge(sources: &[&Self]) -> Result<Self> {
651
652 let table_names = sources.iter().map(|file| file.table_name()).collect::<HashSet<_>>();
653 if table_names.len() > 1 {
654 return Err(RLibError::RFileMergeTablesDifferentNames);
655 }
656
657 if sources.len() < 2 {
658 return Err(RLibError::RFileMergeTablesNotEnoughTablesProvided);
659 }
660
661 let mut new_table = Self::new(sources[0].definition(), Some(sources[0].patches()), sources[0].table_name());
662 let sources = sources.par_iter()
663 .map(|table| {
664 let mut table = table.table().clone();
665 table.set_definition(new_table.definition());
666 table
667 })
668 .collect::<Vec<_>>();
669
670 let new_data = sources.par_iter()
671 .map(|table| table.data().to_vec())
672 .flatten()
673 .collect::<Vec<_>>();
674 new_table.set_data(&new_data)?;
675
676 Ok(new_table)
677 }
678
679 pub fn tsv_import(records: StringRecordsIter<File>, field_order: &HashMap<u32, String>, schema: &Schema, table_name: &str, table_version: i32) -> Result<Self> {
693 let definition = schema.definition_by_name_and_version(table_name, table_version).ok_or(RLibError::DecodingDBNoDefinitionsFound)?;
694 let definition_patch = schema.patches_for_table(table_name);
695 let table = TableInMemory::tsv_import(records, definition, field_order, table_name, definition_patch)?;
696 let db = DB::from(table);
697 Ok(db)
698 }
699
700 pub fn tsv_export(&self, writer: &mut Writer<File>, table_path: &str, keys_first: bool) -> Result<()> {
708 self.table.tsv_export(writer, table_path, keys_first)
709 }
710
711 pub fn altered(&self) -> bool {
713 *self.table.altered()
714 }
715
716 pub fn generate_twad_key_deletes_keys(&self, keys: &mut HashSet<String>) {
721 let definition = self.definition();
722 match self.table_name() {
723
724 "agent_to_agent_attributes_tables" => {
726 let key_pos_0 = definition.column_position_by_name("agent").unwrap_or_default();
727 let key_pos_1 = definition.column_position_by_name("attribute").unwrap_or_default();
728
729 keys.extend(self.data()
730 .iter()
731 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
732 .collect::<Vec<_>>()
733 );
734 }
735
736 "animation_set_prebattle_group_view_configurations_tables" => {
738 let key_pos_0 = definition.column_position_by_name("attacker").unwrap_or_default();
739 let key_pos_1 = definition.column_position_by_name("defender").unwrap_or_default();
740
741 keys.extend(self.data()
742 .iter()
743 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
744 .collect::<Vec<_>>()
745 );
746 }
747
748 "armory_item_variants_tables" => {
750 let key_pos_0 = definition.column_position_by_name("armory_item").unwrap_or_default();
751 let key_pos_1 = definition.column_position_by_name("variant").unwrap_or_default();
752
753 keys.extend(self.data()
754 .iter()
755 .map(|x| x[key_pos_0].data_to_string().to_string() + " | " + &x[key_pos_1].data_to_string())
756 .collect::<Vec<_>>()
757 );
758 }
759
760 "battle_currency_deployables_cost_values_tables" => {
762 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
763 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
764
765 keys.extend(self.data()
766 .iter()
767 .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())
768 .collect::<Vec<_>>()
769 );
770 }
771
772 "battle_currency_units_cost_values_tables" => {
774 let key_pos_0 = definition.column_position_by_name("item_type").unwrap_or_default();
775 let key_pos_1 = definition.column_position_by_name("currency_type").unwrap_or_default();
776
777 keys.extend(self.data()
778 .iter()
779 .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())
780 .collect::<Vec<_>>()
781 );
782 }
783
784 "battle_set_pieces_siege_items_tables" => {
786 let key_pos_0 = definition.column_position_by_name("army_name").unwrap_or_default();
787 let key_pos_1 = definition.column_position_by_name("siege_item").unwrap_or_default();
788
789 keys.extend(self.data()
790 .iter()
791 .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())
792 .collect::<Vec<_>>()
793 );
794 }
795
796 "cai_agent_type_distribution_profile_junctions_tables" => {
798 let key_pos_0 = definition.column_position_by_name("distribution_profile_key").unwrap_or_default();
799 let key_pos_1 = definition.column_position_by_name("agent_type_key").unwrap_or_default();
800
801 keys.extend(self.data()
802 .iter()
803 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
804 .collect::<Vec<_>>()
805 );
806 }
807
808 "cai_agent_type_recruitment_profile_junctions_tables" => {
810 let key_pos_0 = definition.column_position_by_name("recruitment_profile_key").unwrap_or_default();
811 let key_pos_1 = definition.column_position_by_name("agent_type_key").unwrap_or_default();
812
813 keys.extend(self.data()
814 .iter()
815 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
816 .collect::<Vec<_>>()
817 );
818 }
819
820 "cai_personalities_budget_allocation_policy_junctions_tables" => {
822 let key_pos_0 = definition.column_position_by_name("budget_allocation_key").unwrap_or_default();
823 let key_pos_1 = definition.column_position_by_name("budget_context_key").unwrap_or_default();
824 let key_pos_2 = definition.column_position_by_name("budget_policy_key").unwrap_or_default();
825
826 keys.extend(self.data()
827 .iter()
828 .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())
829 .collect::<Vec<_>>()
830 );
831 }
832
833 "cai_personalities_construction_preference_policy_building_junctions_tables" => {
835 let key_pos_0 = definition.column_position_by_name("building_key").unwrap_or_default();
836 let key_pos_1 = definition.column_position_by_name("policy_key").unwrap_or_default();
837
838 keys.extend(self.data()
839 .iter()
840 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
841 .collect::<Vec<_>>()
842 );
843 }
844
845 "cai_task_management_system_task_generator_variable_group_junctions_tables" => {
847 let key_pos_0 = definition.column_position_by_name("variable_group_key").unwrap_or_default();
848 let key_pos_1 = definition.column_position_by_name("variable_key").unwrap_or_default();
849
850 keys.extend(self.data()
851 .iter()
852 .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())
853 .collect::<Vec<_>>()
854 );
855 }
856
857 "campaign_ai_manager_behaviour_junctions_tables" => {
859 let key_pos_0 = definition.column_position_by_name("manager").unwrap_or_default();
860 let key_pos_1 = definition.column_position_by_name("behaviour").unwrap_or_default();
861
862 keys.extend(self.data()
863 .iter()
864 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
865 .collect::<Vec<_>>()
866 );
867 }
868
869 "campaign_bmd_layer_group_bmd_export_types_junctions_tables" => {
871 let key_pos_0 = definition.column_position_by_name("bmd_export_types").unwrap_or_default();
872 let key_pos_1 = definition.column_position_by_name("campaign_bmd_layer_group").unwrap_or_default();
873
874 keys.extend(self.data()
875 .iter()
876 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
877 .collect::<Vec<_>>()
878 );
879 }
880
881 "campaign_difficulty_handicap_effects_tables" => {
883 let key_pos_0 = definition.column_position_by_name("campaign_difficulty_handicap").unwrap_or_default();
884 let key_pos_1 = definition.column_position_by_name("human").unwrap_or_default();
885 let key_pos_2 = definition.column_position_by_name("effect").unwrap_or_default();
886 let key_pos_3 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
887
888 keys.extend(self.data()
889 .iter()
890 .map(|x| {
891 let human = if x[key_pos_1].data_to_string() == "true" { "1" } else { "0" };
892 x[key_pos_0].data_to_string().to_string() + "-" + human + "-" + &x[key_pos_2].data_to_string() + &x[key_pos_3].data_to_string()
893 })
894 .collect::<Vec<_>>()
895 );
896 }
897
898 "campaign_effect_scope_agent_junctions_tables" => {
900 let key_pos_0 = definition.column_position_by_name("agent_key").unwrap_or_default();
901 let key_pos_1 = definition.column_position_by_name("campaign_effect_scope_key").unwrap_or_default();
902
903 keys.extend(self.data()
904 .iter()
905 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
906 .collect::<Vec<_>>()
907 );
908 }
909
910 "campaign_features_tables" => {
912 let key_pos_0 = definition.column_position_by_name("feature").unwrap_or_default();
913 let key_pos_1 = definition.column_position_by_name("group").unwrap_or_default();
914
915 keys.extend(self.data()
916 .iter()
917 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
918 .collect::<Vec<_>>()
919 );
920 }
921
922 "campaign_markers_tables" => {
924 let key_pos_0 = definition.column_position_by_name("marker_type").unwrap_or_default();
925 let key_pos_1 = definition.column_position_by_name("group").unwrap_or_default();
926
927 keys.extend(self.data()
928 .iter()
929 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
930 .collect::<Vec<_>>()
931 );
932 }
933
934 "campaign_mercenary_unit_character_level_restrictions_tables" => {
936 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
937 let key_pos_1 = definition.column_position_by_name("faction_override").unwrap_or_default();
938
939 keys.extend(self.data()
940 .iter()
941 .map(|x| {
942 let fover = if x[key_pos_1].data_to_string().is_empty() {
943 "".to_owned()
944 } else {
945 "_".to_string() + &x[key_pos_1].data_to_string()
946 };
947 x[key_pos_0].data_to_string().to_string() + &fover
948 })
949 .collect::<Vec<_>>()
950 );
951 }
952
953 "campaign_movement_spline_materials_tables" => {
955 let key_pos_0 = definition.column_position_by_name("id").unwrap_or_default();
956
957 keys.extend(self.data()
958 .iter()
959 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_0].data_to_string())
960 .collect::<Vec<_>>()
961 );
962 }
963
964 "campaign_rogue_army_leaders_tables" => {
966 let key_pos_0 = definition.column_position_by_name("campaign");
967 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
968
969 keys.extend(self.data()
970 .iter()
971 .map(|x| {
972 let camp = if let Some(y) = key_pos_0 { x[y].data_to_string().to_string() } else { "".to_owned() };
973 camp + &x[key_pos_1].data_to_string()
974 })
975 .collect::<Vec<_>>()
976 );
977 }
978
979 "campaign_rogue_army_setups_tables" => {
981 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
982 let key_pos_1 = definition.column_position_by_name("difficulty_level").unwrap_or_default();
983
984 keys.extend(self.data()
985 .iter()
986 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
987 .collect::<Vec<_>>()
988 );
989 }
990
991 "campaigns_campaign_variables_junctions_tables" => {
993 let key_pos_0 = definition.column_position_by_name("variable_key").unwrap_or_default();
994 let key_pos_1 = definition.column_position_by_name("campaign_name").unwrap_or_default();
995 let key_pos_2 = definition.column_position_by_name("difficulty").unwrap_or_default();
996 let key_pos_3 = definition.column_position_by_name("campaign_type").unwrap_or_default();
997
998 keys.extend(self.data()
999 .iter()
1000 .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())
1001 .collect::<Vec<_>>()
1002 );
1003 }
1004
1005 "campaign_tree_type_cultures_tables" => {
1007 let key_pos_0 = definition.column_position_by_name("tree_type").unwrap_or_default();
1008 let key_pos_1 = definition.column_position_by_name("culture").unwrap_or_default();
1009
1010 keys.extend(self.data()
1011 .iter()
1012 .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())
1013 .collect::<Vec<_>>()
1014 );
1015 }
1016
1017 "cdir_events_mission_issuer_junctions_tables" => {
1019 let key_pos_0 = definition.column_position_by_name("issuer_key").unwrap_or_default();
1020 let key_pos_1 = definition.column_position_by_name("mission_key").unwrap_or_default();
1021
1022 keys.extend(self.data()
1023 .iter()
1024 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1025 .collect::<Vec<_>>()
1026 );
1027 }
1028
1029 "character_experience_skill_tiers_tables" => {
1031 let key_pos_0 = definition.column_position_by_name("for_army").unwrap_or_default();
1032 let key_pos_1 = definition.column_position_by_name("for_navy").unwrap_or_default();
1033 let key_pos_2 = definition.column_position_by_name("agent_key").unwrap_or_default();
1034 let key_pos_3 = definition.column_position_by_name("skill_rank").unwrap_or_default();
1035 let key_pos_4 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1036
1037 keys.extend(self.data()
1038 .iter()
1039 .map(|x| {
1040 let mut ckey = String::new();
1041 if x[key_pos_0].data_to_string() == "true" {
1042 if x[key_pos_1].data_to_string() == "true" {
1043 ckey.push_str("navy");
1044 } else {
1045 ckey.push_str("army");
1046 }
1047 } else {
1048 ckey.push_str(&x[key_pos_2].data_to_string());
1049 }
1050
1051 ckey + &x[key_pos_3].data_to_string() + &x[key_pos_4].data_to_string()
1052 })
1053 .collect::<Vec<_>>()
1054 );
1055 }
1056
1057 "culture_to_battle_animation_tables_tables" => {
1059 let key_pos_0 = definition.column_position_by_name("battle_animations_table").unwrap_or_default();
1060 let key_pos_1 = definition.column_position_by_name("culture_pack").unwrap_or_default();
1061
1062 keys.extend(self.data()
1063 .iter()
1064 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1065 .collect::<Vec<_>>()
1066 );
1067 }
1068
1069 "effect_bonus_value_id_action_results_additional_outcomes_junctions_tables" => {
1071 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1072 let key_pos_1 = definition.column_position_by_name("action_results_additional_outcome_record").unwrap_or_default();
1073 let key_pos_2 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1074
1075 keys.extend(self.data()
1076 .iter()
1077 .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())
1078 .collect::<Vec<_>>()
1079 );
1080 }
1081
1082 "effect_bonus_value_projectile_junctions_tables" => {
1084 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1085 let key_pos_1 = definition.column_position_by_name("bonus_value").unwrap_or_default();
1086 let key_pos_2 = definition.column_position_by_name("projectile").unwrap_or_default();
1087
1088 keys.extend(self.data()
1089 .iter()
1090 .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())
1091 .collect::<Vec<_>>()
1092 );
1093 }
1094
1095 "effect_bonus_value_unit_attribute_junctions_tables" => {
1097 let key_pos_0 = definition.column_position_by_name("effect").unwrap_or_default();
1098 let key_pos_1 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1099 let key_pos_2 = definition.column_position_by_name("unit_attribute").unwrap_or_default();
1100
1101 keys.extend(self.data()
1102 .iter()
1103 .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())
1104 .collect::<Vec<_>>()
1105 );
1106 }
1107
1108 "effect_bonus_value_unit_record_junctions_tables" => {
1110 let key_pos_0 = definition.column_position_by_name("bonus_value_id").unwrap_or_default();
1111 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1112 let key_pos_2 = definition.column_position_by_name("unit_record_key").unwrap_or_default();
1113
1114 keys.extend(self.data()
1115 .iter()
1116 .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())
1117 .collect::<Vec<_>>()
1118 );
1119 }
1120
1121 "ground_type_to_stat_effects_tables" => {
1123 let key_pos_0 = definition.column_position_by_name("ground_type").unwrap_or_default();
1124 let key_pos_1 = definition.column_position_by_name("affected_stat").unwrap_or_default();
1125 let key_pos_2 = definition.column_position_by_name("affected_group").unwrap_or_default();
1126
1127 keys.extend(self.data()
1128 .iter()
1129 .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())
1130 .collect::<Vec<_>>()
1131 );
1132 }
1133
1134 "land_units_to_unit_abilites_junctions_tables" => {
1136 let key_pos_0 = definition.column_position_by_name("land_unit").unwrap_or_default();
1137 let key_pos_1 = definition.column_position_by_name("ability").unwrap_or_default();
1138
1139 keys.extend(self.data()
1140 .iter()
1141 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1142 .collect::<Vec<_>>()
1143 );
1144 }
1145
1146 "loading_screen_quotes_to_campaigns_tables" => {
1148 let key_pos_0 = definition.column_position_by_name("loading_quote").unwrap_or_default();
1149 let key_pos_1 = definition.column_position_by_name("campaign").unwrap_or_default();
1150
1151 keys.extend(self.data()
1152 .iter()
1153 .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())
1154 .collect::<Vec<_>>()
1155 );
1156 }
1157
1158 "message_event_strings_tables" => {
1160 let key_pos_0 = definition.column_position_by_name("event").unwrap_or_default();
1161 let key_pos_1 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1162 let key_pos_2 = definition.column_position_by_name("culture").unwrap_or_default();
1163 let key_pos_3 = definition.column_position_by_name("optional_subculture").unwrap_or_default();
1164
1165 keys.extend(self.data()
1166 .iter()
1167 .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())
1168 .collect::<Vec<_>>()
1169 );
1170 }
1171
1172 "mp_force_gen_template_junctions_tables" => {
1174 let key_pos_0 = definition.column_position_by_name("template_key").unwrap_or_default();
1175 let key_pos_1 = definition.column_position_by_name("battle_type").unwrap_or_default();
1176 let key_pos_2 = definition.column_position_by_name("is_defender").unwrap_or_default();
1177
1178 keys.extend(self.data()
1179 .iter()
1180 .map(|x| {
1181 let is_defender = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1182 x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string() + is_defender
1183 })
1184 .collect::<Vec<_>>()
1185 );
1186 }
1187
1188 "provincial_initiative_strength_levels_tables" => {
1190 let key_pos_0 = definition.column_position_by_name("initiative_record").unwrap_or_default();
1191 let key_pos_1 = definition.column_position_by_name("strength").unwrap_or_default();
1192
1193 keys.extend(self.data()
1194 .iter()
1195 .map(|x| x[key_pos_0].data_to_string().to_string() + ";" + &x[key_pos_1].data_to_string())
1196 .collect::<Vec<_>>()
1197 );
1198 }
1199
1200 "region_to_province_junctions_tables" => {
1202 let key_pos_0 = definition.column_position_by_name("province").unwrap_or_default();
1203 let key_pos_1 = definition.column_position_by_name("region").unwrap_or_default();
1204
1205 keys.extend(self.data()
1206 .iter()
1207 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1208 .collect::<Vec<_>>()
1209 );
1210 }
1211
1212 "ritual_payload_change_agent_capacities_tables" => {
1214 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1215 let key_pos_1 = definition.column_position_by_name("agent_record").unwrap_or_default();
1216
1217 keys.extend(self.data()
1218 .iter()
1219 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1220 .collect::<Vec<_>>()
1221 );
1222 }
1223
1224 "ritual_payload_change_unit_capacities_tables" => {
1226 let key_pos_0 = definition.column_position_by_name("payload").unwrap_or_default();
1227 let key_pos_1 = definition.column_position_by_name("unit_record").unwrap_or_default();
1228
1229 keys.extend(self.data()
1230 .iter()
1231 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1232 .collect::<Vec<_>>()
1233 );
1234 }
1235
1236 "slot_set_type_feature_junctions_tables" => {
1238 let key_pos_0 = definition.column_position_by_name("slot_set_type").unwrap_or_default();
1239 let key_pos_1 = definition.column_position_by_name("feature").unwrap_or_default();
1240
1241 keys.extend(self.data()
1242 .iter()
1243 .map(|x| x[key_pos_0].data_to_string().to_string() + "|" + &x[key_pos_1].data_to_string())
1244 .collect::<Vec<_>>()
1245 );
1246 }
1247
1248 "special_ability_to_special_ability_phase_junctions_tables" => {
1250 let key_pos_0 = definition.column_position_by_name("special_ability").unwrap_or_default();
1251 let key_pos_1 = definition.column_position_by_name("phase").unwrap_or_default();
1252 let key_pos_2 = definition.column_position_by_name("order").unwrap_or_default();
1253
1254 keys.extend(self.data()
1255 .iter()
1256 .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())
1257 .collect::<Vec<_>>()
1258 );
1259 }
1260
1261 "start_pos_region_slot_templates_tables" => {
1263 let key_pos_0 = definition.column_position_by_name("campaign").unwrap_or_default();
1264 let key_pos_1 = definition.column_position_by_name("id").unwrap_or_default();
1265 let key_pos_2 = definition.column_position_by_name("region").unwrap_or_default();
1266 let key_pos_3 = definition.column_position_by_name("slot_template").unwrap_or_default();
1267 let key_pos_4 = definition.column_position_by_name("slot_type").unwrap_or_default();
1268
1269 keys.extend(self.data()
1270 .iter()
1271 .map(|x|
1272 x[key_pos_0].data_to_string().to_string() +
1273 &x[key_pos_1].data_to_string() +
1274 &x[key_pos_2].data_to_string() +
1275 &x[key_pos_3].data_to_string() +
1276 &x[key_pos_4].data_to_string()
1277 )
1278 .collect::<Vec<_>>()
1279 );
1280 }
1281
1282 "start_pos_technologies_tables" => {
1284 let key_pos_0 = definition.column_position_by_name("faction").unwrap_or_default();
1285 let key_pos_1 = definition.column_position_by_name("technology").unwrap_or_default();
1286
1287 keys.extend(self.data()
1288 .iter()
1289 .map(|x| x[key_pos_0].data_to_string().to_string() + &x[key_pos_1].data_to_string())
1290 .collect::<Vec<_>>()
1291 );
1292 }
1293
1294 "taxes_effects_jct_tables" => {
1296 let key_pos_0 = definition.column_position_by_name("tax_name").unwrap_or_default();
1297 let key_pos_1 = definition.column_position_by_name("effect").unwrap_or_default();
1298 let key_pos_2 = definition.column_position_by_name("optional_campaign_key").unwrap_or_default();
1299 let key_pos_3 = definition.column_position_by_name("optional_difficulty_level").unwrap_or_default();
1300 let key_pos_4 = definition.column_position_by_name("ai_only").unwrap_or_default();
1301
1302 keys.extend(self.data()
1303 .iter()
1304 .map(|x| {
1305 let ai_only = if x[key_pos_4].data_to_string() == "true" { "1" } else { "0" };
1306 x[key_pos_0].data_to_string().to_string() + ";" +
1307 &x[key_pos_1].data_to_string() + ";" +
1308 &x[key_pos_2].data_to_string() + ";" +
1309 &x[key_pos_3].data_to_string() + ai_only
1310 })
1311 .collect::<Vec<_>>()
1312 );
1313 }
1314
1315 "ui_purchasable_effects_to_hex_ids_tables" => {
1317 let key_pos_0 = definition.column_position_by_name("hex_id").unwrap_or_default();
1318 let key_pos_1 = definition.column_position_by_name("category").unwrap_or_default();
1319
1320 keys.extend(self.data()
1321 .iter()
1322 .map(|x| x[key_pos_0].data_to_string().to_string() + "_" + &x[key_pos_1].data_to_string())
1323 .collect::<Vec<_>>()
1324 );
1325 }
1326
1327 "units_custom_battle_permissions_tables" => {
1329 let key_pos_0 = definition.column_position_by_name("unit").unwrap_or_default();
1330 let key_pos_1 = definition.column_position_by_name("faction").unwrap_or_default();
1331 let key_pos_2 = definition.column_position_by_name("general_unit").unwrap_or_default();
1332
1333 keys.extend(self.data()
1334 .iter()
1335 .map(|x| {
1336 let general_unit = if x[key_pos_2].data_to_string() == "true" { "1" } else { "0" };
1337 x[key_pos_0].data_to_string().to_string() + ":" + &x[key_pos_1].data_to_string() + ":" + general_unit
1338 })
1339 .collect::<Vec<_>>()
1340 );
1341 }
1342
1343 "workshop_categories_progress_levels_tables" => {
1345 let key_pos_0 = definition.column_position_by_name("category").unwrap_or_default();
1346 let key_pos_1 = definition.column_position_by_name("level_to_unlock").unwrap_or_default();
1347
1348 keys.extend(self.data()
1349 .iter()
1350 .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())
1351 .collect::<Vec<_>>()
1352 );
1353 }
1354
1355 _ => {
1357 let key_cols = definition.key_column_positions_by_ca_order();
1358 keys.extend(self.data()
1359 .iter()
1360 .map(|x| key_cols.iter()
1361 .map(|y| x[*y].data_to_string())
1362 .join("")
1363 )
1364 .collect::<Vec<_>>()
1365 );
1366 }
1367 }
1368 }
1369}
1370
1371impl From<TableInMemory> for DB {
1373 fn from(table: TableInMemory) -> Self {
1374 Self {
1375 mysterious_byte: true,
1376 guid: Uuid::new_v4().to_string(),
1377 table,
1378 }
1379 }
1380}