1use getset::{Getters, MutGetters};
14use serde_derive::{Serialize, Deserialize};
15
16use std::collections::{HashMap, HashSet};
17use std::{fmt, fmt::Display};
18
19use rpfm_lib::files::{RFile, RFileDecoded};
20
21use crate::dependencies::Dependencies;
22use crate::diagnostics::*;
23
24#[derive(Debug, Clone, Default, Getters, MutGetters, Serialize, Deserialize)]
30#[getset(get = "pub", get_mut = "pub")]
31pub struct PortraitSettingsDiagnostic {
32 path: String,
33 pack: String,
34 results: Vec<PortraitSettingsDiagnosticReport>
35}
36
37#[derive(Debug, Clone, Getters, MutGetters, Serialize, Deserialize)]
39#[getset(get = "pub", get_mut = "pub")]
40pub struct PortraitSettingsDiagnosticReport {
41 report_type: PortraitSettingsDiagnosticReportType,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub enum PortraitSettingsDiagnosticReportType {
46 DatacoredPortraitSettings,
47 InvalidArtSetId(String),
48 InvalidVariantFilename(String, String, bool, bool),
49 FileDiffuseNotFoundForVariant(String, String, bool, bool, String),
50 FileMask1NotFoundForVariant(String, String, bool, bool, String),
51 FileMask2NotFoundForVariant(String, String, bool, bool, String),
52 FileMask3NotFoundForVariant(String, String, bool, bool, String),
53}
54
55impl PortraitSettingsDiagnosticReport {
60 pub fn new(report_type: PortraitSettingsDiagnosticReportType) -> Self {
61 Self {
62 report_type
63 }
64 }
65}
66
67impl DiagnosticReport for PortraitSettingsDiagnosticReport {
68 fn message(&self) -> String {
69 match &self.report_type {
70 PortraitSettingsDiagnosticReportType::DatacoredPortraitSettings => "Datacored Portrait Settings file.".to_string(),
71 PortraitSettingsDiagnosticReportType::InvalidArtSetId(art_set_id) => format!("Invalid Art Set Id '{art_set_id}' in Portrait Settings file."),
72 PortraitSettingsDiagnosticReportType::InvalidVariantFilename(art_set_id, variant_filename, _, _) => format!("Invalid Variant Filename '{variant_filename}' for Art Set Id '{art_set_id}'. "),
73 PortraitSettingsDiagnosticReportType::FileDiffuseNotFoundForVariant(art_set_id, variant_filename, _, _, path) => format!("File not found for Art Set Id '{art_set_id}', Variant Filename '{variant_filename}', File Diffuse '{path}'."),
74 PortraitSettingsDiagnosticReportType::FileMask1NotFoundForVariant(art_set_id, variant_filename, _, _, path) => format!("File not found for Art Set Id '{art_set_id}', Variant Filename '{variant_filename}', File Mask 1 '{path}'."),
75 PortraitSettingsDiagnosticReportType::FileMask2NotFoundForVariant(art_set_id, variant_filename, _, _, path) => format!("File not found for Art Set Id '{art_set_id}', Variant Filename '{variant_filename}', File Mask 2 '{path}'."),
76 PortraitSettingsDiagnosticReportType::FileMask3NotFoundForVariant(art_set_id, variant_filename, _, _, path) => format!("File not found for Art Set Id '{art_set_id}', Variant Filename '{variant_filename}', File Mask 3 '{path}'."),
77 }
78 }
79
80 fn level(&self) -> DiagnosticLevel {
81 match self.report_type {
82 PortraitSettingsDiagnosticReportType::DatacoredPortraitSettings => DiagnosticLevel::Warning,
83 PortraitSettingsDiagnosticReportType::InvalidArtSetId(_) => DiagnosticLevel::Warning,
84 PortraitSettingsDiagnosticReportType::InvalidVariantFilename(_, _, _, _) => DiagnosticLevel::Warning,
85 PortraitSettingsDiagnosticReportType::FileDiffuseNotFoundForVariant(_, _, _, _, _) => DiagnosticLevel::Warning,
86 PortraitSettingsDiagnosticReportType::FileMask1NotFoundForVariant(_, _, _, _, _) => DiagnosticLevel::Warning,
87 PortraitSettingsDiagnosticReportType::FileMask2NotFoundForVariant(_, _, _, _, _) => DiagnosticLevel::Warning,
88 PortraitSettingsDiagnosticReportType::FileMask3NotFoundForVariant(_, _, _, _, _) => DiagnosticLevel::Warning,
89 }
90 }
91}
92
93impl Display for PortraitSettingsDiagnosticReportType {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 Display::fmt(match self {
96 Self::DatacoredPortraitSettings => "DatacoredPortraitSettings",
97 Self::InvalidArtSetId(_) => "InvalidArtSetId",
98 Self::InvalidVariantFilename(_, _, _, _) => "InvalidVariantFilename",
99 Self::FileDiffuseNotFoundForVariant(_, _, _, _, _) => "FileDiffuseNotFoundForVariant",
100 Self::FileMask1NotFoundForVariant(_, _, _, _, _) => "FileMask1NotFoundForVariant",
101 Self::FileMask2NotFoundForVariant(_, _, _, _, _) => "FileMask2NotFoundForVariant",
102 Self::FileMask3NotFoundForVariant(_, _, _, _, _) => "FileMask3NotFoundForVariant",
103 }, f)
104 }
105}
106
107impl PortraitSettingsDiagnostic {
108 pub fn new(path: &str, pack: &str) -> Self {
109 Self {
110 path: path.to_owned(),
111 pack: pack.to_owned(),
112 results: vec![],
113 }
114 }
115
116 pub fn check(
118 pack_key: &str,
119 file: &RFile,
120 art_set_ids: &HashSet<String>,
121 variant_filenames: &HashSet<String>,
122 dependencies: &Dependencies,
123 global_ignored_diagnostics: &[String],
124 ignored_fields: &[String],
125 ignored_diagnostics: &HashSet<String>,
126 ignored_diagnostics_for_fields: &HashMap<String, Vec<String>>,
127 local_path_list: &HashMap<String, Vec<String>>,
128 ) -> Option<DiagnosticType> {
129 if let Ok(RFileDecoded::PortraitSettings(portrait_settings)) = file.decoded() {
130 let mut diagnostic = Self::new(file.path_in_container_raw(), pack_key);
131
132 for entry in portrait_settings.entries() {
139 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("InvalidArtSetId"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) && art_set_ids.get(entry.id()).is_none() {
140 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::InvalidArtSetId(entry.id().to_owned()));
141 diagnostic.results_mut().push(result);
142 }
143
144 for variant in entry.variants() {
145 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("InvalidVariantFilename"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) && variant_filenames.get(variant.filename()).is_none() {
146 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::InvalidVariantFilename(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader()));
147 diagnostic.results_mut().push(result);
148 }
149
150 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileDiffuseNotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
151 (
152 local_path_list.get(&variant.file_diffuse().to_lowercase()).is_none() &&
153 !dependencies.file_exists(variant.file_diffuse(), true, true, true)
154 ) && !variant.file_diffuse().is_empty() {
155 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::FileDiffuseNotFoundForVariant(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader(), variant.file_diffuse().to_owned()));
156 diagnostic.results_mut().push(result);
157 }
158
159 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileMask1NotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
160 (
161 local_path_list.get(&variant.file_mask_1().to_lowercase()).is_none() &&
162 !dependencies.file_exists(variant.file_mask_1(), true, true, true)
163 ) && !variant.file_mask_1().is_empty() {
164 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::FileMask1NotFoundForVariant(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader(), variant.file_mask_1().to_owned()));
165 diagnostic.results_mut().push(result);
166 }
167
168 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileMask2NotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
169 (
170 local_path_list.get(&variant.file_mask_2().to_lowercase()).is_none() &&
171 !dependencies.file_exists(variant.file_mask_2(), true, true, true)
172 ) && !variant.file_mask_2().is_empty() {
173 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::FileMask2NotFoundForVariant(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader(), variant.file_mask_2().to_owned()));
174 diagnostic.results_mut().push(result);
175 }
176
177 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileMask3NotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
178 (
179 local_path_list.get(&variant.file_mask_3().to_lowercase()).is_none() &&
180 !dependencies.file_exists(variant.file_mask_3(), true, true, true)
181 ) && !variant.file_mask_3().is_empty() {
182 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::FileMask3NotFoundForVariant(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader(), variant.file_mask_3().to_owned()));
183 diagnostic.results_mut().push(result);
184 }
185 }
186 }
187
188 if !diagnostic.results().is_empty() {
189 Some(DiagnosticType::PortraitSettings(diagnostic))
190 } else { None }
191 } else { None }
192 }
193}