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 #[allow(clippy::too_many_arguments)]
118 pub fn check(
119 pack_key: &str,
120 file: &RFile,
121 art_set_ids: &HashSet<String>,
122 variant_filenames: &HashSet<String>,
123 dependencies: &Dependencies,
124 global_ignored_diagnostics: &[String],
125 ignored_fields: &[String],
126 ignored_diagnostics: &HashSet<String>,
127 ignored_diagnostics_for_fields: &HashMap<String, Vec<String>>,
128 local_path_list: &HashMap<String, Vec<String>>,
129 ) -> Option<DiagnosticType> {
130 if let Ok(RFileDecoded::PortraitSettings(portrait_settings)) = file.decoded() {
131 let mut diagnostic = Self::new(file.path_in_container_raw(), pack_key);
132
133 for entry in portrait_settings.entries() {
140 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() {
141 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::InvalidArtSetId(entry.id().to_owned()));
142 diagnostic.results_mut().push(result);
143 }
144
145 for variant in entry.variants() {
146 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() {
147 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::InvalidVariantFilename(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader()));
148 diagnostic.results_mut().push(result);
149 }
150
151 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileDiffuseNotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
152 (
153 local_path_list.get(&variant.file_diffuse().to_lowercase()).is_none() &&
154 !dependencies.file_exists(variant.file_diffuse(), true, true, true)
155 ) && !variant.file_diffuse().is_empty() {
156 let result = PortraitSettingsDiagnosticReport::new(PortraitSettingsDiagnosticReportType::FileDiffuseNotFoundForVariant(entry.id().to_owned(), variant.filename().to_owned(), *variant.politician(), *variant.faction_leader(), variant.file_diffuse().to_owned()));
157 diagnostic.results_mut().push(result);
158 }
159
160 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileMask1NotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
161 (
162 local_path_list.get(&variant.file_mask_1().to_lowercase()).is_none() &&
163 !dependencies.file_exists(variant.file_mask_1(), true, true, true)
164 ) && !variant.file_mask_1().is_empty() {
165 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()));
166 diagnostic.results_mut().push(result);
167 }
168
169 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileMask2NotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
170 (
171 local_path_list.get(&variant.file_mask_2().to_lowercase()).is_none() &&
172 !dependencies.file_exists(variant.file_mask_2(), true, true, true)
173 ) && !variant.file_mask_2().is_empty() {
174 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()));
175 diagnostic.results_mut().push(result);
176 }
177
178 if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FileMask3NotFoundForVariant"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) &&
179 (
180 local_path_list.get(&variant.file_mask_3().to_lowercase()).is_none() &&
181 !dependencies.file_exists(variant.file_mask_3(), true, true, true)
182 ) && !variant.file_mask_3().is_empty() {
183 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()));
184 diagnostic.results_mut().push(result);
185 }
186 }
187 }
188
189 if !diagnostic.results().is_empty() {
190 Some(DiagnosticType::PortraitSettings(diagnostic))
191 } else { None }
192 } else { None }
193 }
194}