Skip to main content

rpfm_extensions/diagnostics/
anim_fragment_battle.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Module with the structs and functions specific for `AnimFragmentBattle` diagnostics.
12
13use 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//-------------------------------------------------------------------------------//
25//                              Enums & Structs
26//-------------------------------------------------------------------------------//
27
28/// This struct contains the results of an anim fragment battle diagnostic.
29#[derive(Debug, Clone, Default, Getters, MutGetters, Serialize, Deserialize)]
30#[getset(get = "pub", get_mut = "pub")]
31pub struct AnimFragmentBattleDiagnostic {
32    path: String,
33    pack: String,
34    results: Vec<AnimFragmentBattleDiagnosticReport>
35}
36
37/// This struct defines an individual anim fragment battle diagnostic result.
38#[derive(Debug, Clone, Getters, MutGetters, Serialize, Deserialize)]
39#[getset(get = "pub", get_mut = "pub")]
40pub struct AnimFragmentBattleDiagnosticReport {
41    locomotion_graph: bool,
42    entry: Option<(usize, Option<(usize, bool, bool, bool)>)>,
43    report_type: AnimFragmentBattleDiagnosticReportType,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub enum AnimFragmentBattleDiagnosticReportType {
48    LocomotionGraphPathNotFound(String),
49    FilePathNotFound(String),
50    MetaFilePathNotFound(String),
51    SndFilePathNotFound(String),
52}
53
54//-------------------------------------------------------------------------------//
55//                             Implementations
56//-------------------------------------------------------------------------------//
57
58impl AnimFragmentBattleDiagnosticReport {
59    pub fn new(report_type: AnimFragmentBattleDiagnosticReportType, locomotion_graph: bool, entry: Option<(usize, Option<(usize, bool, bool, bool)>)>) -> Self {
60        Self {
61            locomotion_graph,
62            entry,
63            report_type
64        }
65    }
66}
67
68impl DiagnosticReport for AnimFragmentBattleDiagnosticReport {
69    fn message(&self) -> String {
70        match &self.report_type {
71            AnimFragmentBattleDiagnosticReportType::LocomotionGraphPathNotFound(path) => format!("Locomotion Graph file not found: {path}."),
72            AnimFragmentBattleDiagnosticReportType::FilePathNotFound(path) => format!("'File Path' file not found: {path}."),
73            AnimFragmentBattleDiagnosticReportType::MetaFilePathNotFound(path) => format!("'Meta File Path' file not found: {path}."),
74            AnimFragmentBattleDiagnosticReportType::SndFilePathNotFound(path) => format!("'Snd File Path' file not found: {path}."),
75        }
76    }
77
78    fn level(&self) -> DiagnosticLevel {
79        match self.report_type {
80            AnimFragmentBattleDiagnosticReportType::LocomotionGraphPathNotFound(_) => DiagnosticLevel::Warning,
81            AnimFragmentBattleDiagnosticReportType::FilePathNotFound(_) => DiagnosticLevel::Warning,
82            AnimFragmentBattleDiagnosticReportType::MetaFilePathNotFound(_) => DiagnosticLevel::Warning,
83            AnimFragmentBattleDiagnosticReportType::SndFilePathNotFound(_) => DiagnosticLevel::Warning,
84        }
85    }
86}
87
88impl Display for AnimFragmentBattleDiagnosticReportType {
89    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90        Display::fmt(match self {
91            Self::LocomotionGraphPathNotFound(_) => "LocomotionGraphPathNotFound",
92            Self::FilePathNotFound(_) => "FilePathNotFound",
93            Self::MetaFilePathNotFound(_) => "MetaFilePathNotFound",
94            Self::SndFilePathNotFound(_) => "SndFilePathNotFound",
95        }, f)
96    }
97}
98
99impl AnimFragmentBattleDiagnostic {
100    pub fn new(path: &str, pack: &str) -> Self {
101        Self {
102            path: path.to_owned(),
103            pack: pack.to_owned(),
104            results: vec![],
105        }
106    }
107
108    /// This function takes care of checking the loc tables of your mod for errors.
109    pub fn check(
110        pack_key: &str,
111        file: &RFile,
112        dependencies: &Dependencies,
113        global_ignored_diagnostics: &[String],
114        ignored_fields: &[String],
115        ignored_diagnostics: &HashSet<String>,
116        ignored_diagnostics_for_fields: &HashMap<String, Vec<String>>,
117        local_path_list: &HashMap<String, Vec<String>>,
118    ) ->Option<DiagnosticType> {
119        if let Ok(RFileDecoded::AnimFragmentBattle(fragment)) = file.decoded() {
120            let mut diagnostic = AnimFragmentBattleDiagnostic::new(file.path_in_container_raw(), pack_key);
121
122            if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("LocomotionGraphPathNotFound"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) && !fragment.locomotion_graph().is_empty() {
123                let path = fragment.locomotion_graph().replace('\\', "/");
124                let mut path_found = false;
125
126                if !path_found && local_path_list.get(&path.to_lowercase()).is_some() {
127                    path_found = true;
128                }
129
130                if !path_found && dependencies.file_exists(&path, true, true, true) {
131                    path_found = true;
132                }
133
134                if !path_found {
135                    let result = AnimFragmentBattleDiagnosticReport::new(AnimFragmentBattleDiagnosticReportType::LocomotionGraphPathNotFound(fragment.locomotion_graph().to_owned()), true, None);
136                    diagnostic.results_mut().push(result);
137                }
138            }
139
140            for (row, entry) in fragment.entries().iter().enumerate() {
141                for (subrow, anim_ref) in entry.anim_refs().iter().enumerate() {
142                    if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("FilePathNotFound"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) && !anim_ref.file_path().is_empty() {
143                        let path = anim_ref.file_path().replace('\\', "/");
144                        let mut path_found = false;
145
146                        if !path_found && local_path_list.get(&path.to_lowercase()).is_some() {
147                            path_found = true;
148                        }
149
150                        if !path_found && dependencies.file_exists(&path, true, true, true) {
151                            path_found = true;
152                        }
153
154                        if !path_found {
155                            let result = AnimFragmentBattleDiagnosticReport::new(AnimFragmentBattleDiagnosticReportType::FilePathNotFound(anim_ref.file_path().to_owned()), false, Some((row, Some((subrow, true, false, false)))));
156                            diagnostic.results_mut().push(result);
157                        }
158                    }
159
160                    if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("MetaFilePathNotFound"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) && !anim_ref.meta_file_path().is_empty() {
161                        let path = anim_ref.meta_file_path().replace('\\', "/");
162                        let mut path_found = false;
163
164                        if !path_found && local_path_list.get(&path.to_lowercase()).is_some() {
165                            path_found = true;
166                        }
167
168                        if !path_found && dependencies.file_exists(&path, true, true, true) {
169                            path_found = true;
170                        }
171
172                        if !path_found {
173                            let result = AnimFragmentBattleDiagnosticReport::new(AnimFragmentBattleDiagnosticReportType::MetaFilePathNotFound(anim_ref.meta_file_path().to_owned()), false, Some((row, Some((subrow, false, true, false)))));
174                            diagnostic.results_mut().push(result);
175                        }
176                    }
177
178                    if !Diagnostics::ignore_diagnostic(global_ignored_diagnostics, None, Some("SndFilePathNotFound"), ignored_fields, ignored_diagnostics, ignored_diagnostics_for_fields) && !anim_ref.snd_file_path().is_empty() {
179                        let path = anim_ref.snd_file_path().replace('\\', "/");
180                        let mut path_found = false;
181
182                        if !path_found && local_path_list.get(&path.to_lowercase()).is_some() {
183                            path_found = true;
184                        }
185
186                        if !path_found && dependencies.file_exists(&path, true, true, true) {
187                            path_found = true;
188                        }
189
190                        if !path_found {
191                            let result = AnimFragmentBattleDiagnosticReport::new(AnimFragmentBattleDiagnosticReportType::SndFilePathNotFound(anim_ref.snd_file_path().to_owned()), false, Some((row, Some((subrow, false, false, true)))));
192                            diagnostic.results_mut().push(result);
193                        }
194                    }
195                }
196            }
197
198            if !diagnostic.results().is_empty() {
199                Some(DiagnosticType::AnimFragmentBattle(diagnostic))
200            } else { None }
201        } else { None }
202    }
203}