Porytiles
Loading...
Searching...
No Matches
base_game_detector.cpp
Go to the documentation of this file.
2
3#include <filesystem>
4#include <fstream>
5#include <string>
6
7namespace porytiles {
8
10{
11 const std::filesystem::path global_fieldmap_path = project_root_ / "include" / "global.fieldmap.h";
12
13 if (!std::filesystem::exists(global_fieldmap_path)) {
14 return FormattableError{
15 "Base game detection failed: '{}' does not exist.",
16 FormatParam{global_fieldmap_path.string(), Style::bold}};
17 }
18
19 /*
20 * Simple text search for base-game-specific markers. We avoid CParserFacade::find_define() because it attempts
21 * to parse ALL defines in the file, including complex multiline macros that may fail to parse (e.g.,
22 * backslash-continuation lines).
23 *
24 * Decision tree based on 4 boolean markers:
25 * METATILE_ATTRIBUTE_BEHAVIOR -> pokefirered or pokeemerald-expansion (enum-based attributes)
26 * + METATILE_ATTR_BEHAVIOR_MASK -> pokeemerald-expansion (has both enum and #define attribute markers)
27 * - METATILE_ATTR_BEHAVIOR_MASK -> pokefirered
28 * METATILE_ATTR_BEHAVIOR_MASK -> emerald-family (#define-based)
29 * + MAPGRID_METATILE_ID_SHIFT -> emerald or expansion
30 * + swapPalettes -> pokeemerald-expansion
31 * - swapPalettes -> pokeemerald
32 * - MAPGRID_METATILE_ID_SHIFT -> pokeruby
33 */
34 std::ifstream file{global_fieldmap_path};
35 if (!file) {
36 return FormattableError{
37 "Failed to open '{}' for base game detection.", FormatParam{global_fieldmap_path.string(), Style::bold}};
38 }
39
40 bool has_metatile_attribute_behavior = false;
41 bool has_metatile_attr_behavior_mask = false;
42 bool has_mapgrid_metatile_id_shift = false;
43 bool has_swap_palettes = false;
44
45 std::string line;
46 while (std::getline(file, line)) {
47 if (line.find("METATILE_ATTRIBUTE_BEHAVIOR") != std::string::npos) {
48 has_metatile_attribute_behavior = true;
49 }
50 if (line.find("METATILE_ATTR_BEHAVIOR_MASK") != std::string::npos) {
51 has_metatile_attr_behavior_mask = true;
52 }
53 if (line.find("MAPGRID_METATILE_ID_SHIFT") != std::string::npos) {
54 has_mapgrid_metatile_id_shift = true;
55 }
56 if (line.find("swapPalettes") != std::string::npos) {
57 has_swap_palettes = true;
58 }
59 }
60
61 BaseGame detected;
62 std::string reason;
63
64 if (has_metatile_attribute_behavior) {
65 if (has_metatile_attr_behavior_mask) {
67 reason = "Found both METATILE_ATTRIBUTE_BEHAVIOR and METATILE_ATTR_BEHAVIOR_MASK";
68 }
69 else {
70 detected = BaseGame::pokefirered;
71 reason = "Found METATILE_ATTRIBUTE_BEHAVIOR";
72 }
73 }
74 else if (has_metatile_attr_behavior_mask) {
75 if (has_mapgrid_metatile_id_shift) {
76 if (has_swap_palettes) {
78 reason = "Found METATILE_ATTR_BEHAVIOR_MASK, MAPGRID_METATILE_ID_SHIFT, and swapPalettes";
79 }
80 else {
81 detected = BaseGame::pokeemerald;
82 reason = "Found METATILE_ATTR_BEHAVIOR_MASK and MAPGRID_METATILE_ID_SHIFT";
83 }
84 }
85 else {
86 detected = BaseGame::pokeruby;
87 reason = "Found METATILE_ATTR_BEHAVIOR_MASK but no MAPGRID_METATILE_ID_SHIFT";
88 }
89 }
90 else {
91 return FormattableError{
92 "Base game detection failed: no recognized markers found in '{}'.",
93 FormatParam{global_fieldmap_path.string(), Style::bold}};
94 }
95
96 constexpr auto tag = "base-game-detection";
97 diag_->remark(tag, format_->format("Detected base game '{}'.", FormatParam{to_string(detected), Style::bold}));
98 diag_->remark_note(
99 tag,
100 format_->format("{} in '{}'.", FormatParam{reason}, FormatParam{global_fieldmap_path.string(), Style::bold}));
101
102 return detected;
103}
104
105} // namespace porytiles
ChainableResult< BaseGame > detect() const
Detects the base game for the project.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
A text parameter with associated styling for formatted output.
General-purpose error implementation with formatted message support.
Definition error.hpp:63
static const Style bold
Bold text formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > &params) const
Formats a string with styled parameters using fmtlib syntax.
virtual void remark(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged remark message.
virtual void remark_note(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged note message associated with a remark.
BaseGame
Identifies the target base game for a decompilation project.
Definition base_game.hpp:20