Porytiles
Loading...
Searching...
No Matches
secondary_tileset_helpers.cpp
Go to the documentation of this file.
2
3#include <memory>
4#include <ranges>
5#include <set>
6#include <string>
7
11
12namespace porytiles {
13
15 const std::string &tileset_name,
16 const ConfigValue<PrimaryPairingMode> &pairing_mode,
17 const ConfigValue<std::vector<std::string>> &partners,
18 const TilesetRepo *tileset_repo,
19 const TilesetMetadataProvider *metadata_provider,
20 const LayoutMetadataProvider *layout_metadata_provider,
21 const PorytilesTilesetManager *tileset_manager,
22 const UserDiagnostics *diag)
23{
24 std::string partner_name{};
25
26 switch (pairing_mode.value()) {
28 if (!partners.value().empty()) {
29 diag->warning(
30 "pairing-partners-ignored",
31 std::vector<std::string>{
32 diag->formatter().format(
33 "Primary pairing mode is 'off' but '{}' has non-empty pairing partners list.",
34 FormatParam{tileset_name, Style::bold}),
35 "Partners will be ignored."});
36 }
37 return std::unique_ptr<Tileset>{nullptr};
38 }
39
41 if (partners.value().empty()) {
42 std::vector<std::string> err_msg{};
43 err_msg.emplace_back(diag->formatter().format(
44 "Primary pairing mode is 'manual' but no partner primaries configured for '{}'.",
45 FormatParam{tileset_name, Style::bold}));
46 err_msg.append_range(format_config_note_with_separator(diag->formatter(), pairing_mode));
47 err_msg.append_range(format_config_note_with_separator(diag->formatter(), partners));
48 return FormattableError{err_msg};
49 }
50 partner_name = partners.value().at(0);
51 break;
52 }
53
55 if (!partners.value().empty()) {
56 constexpr auto warn_tag = "pairing-partners-ignored";
57 diag->warning(
58 warn_tag,
59 std::vector<std::string>{
60 diag->formatter().format(
61 "Primary pairing mode is 'automatic' but '{}' has non-empty pairing partners list.",
62 FormatParam{tileset_name, Style::bold}),
63 "Partners will be ignored."});
64 std::vector<std::string> note_lines{};
65 note_lines.append_range(format_config_note(diag->formatter(), pairing_mode));
66 note_lines.append_range(format_config_note_with_separator(diag->formatter(), partners));
67 diag->warning_note(warn_tag, note_lines);
68 }
69
71 layout_names,
72 layout_metadata_provider->layout_names(),
73 std::unique_ptr<Tileset>,
74 "Failed to enumerate layouts for automatic primary pairing.");
75
76 std::set<std::string> found_primaries{};
77 for (const auto &layout_name : layout_names) {
78 auto secondary_result = layout_metadata_provider->secondary_tileset(layout_name);
79 if (!secondary_result.has_value()) {
80 continue;
81 }
82 if (secondary_result.value() == tileset_name) {
83 auto primary_result = layout_metadata_provider->primary_tileset(layout_name);
84 if (primary_result.has_value()) {
85 found_primaries.insert(primary_result.value());
86 }
87 }
88 }
89
90 if (found_primaries.empty()) {
91 return FormattableError{
92 "Automatic primary pairing found no layouts using secondary tileset '{}'.",
93 FormatParam{tileset_name, Style::bold}};
94 }
95
96 if (found_primaries.size() > 1) {
97 std::vector<std::string> warn_lines{};
98 warn_lines.push_back(diag->formatter().format(
99 "Multiple distinct partner primaries found for '{}' via layout data.",
100 FormatParam{tileset_name, Style::bold}));
101 warn_lines.push_back(diag->formatter().format(
102 "Using first found: '{}'.", FormatParam{*found_primaries.begin(), Style::bold}));
103 warn_lines.emplace_back("Other partners:");
104 for (const auto &name : found_primaries | std::views::drop(1)) {
105 warn_lines.push_back(diag->formatter().format(" '{}'", FormatParam{name, Style::bold}));
106 }
107 diag->warning("multiple-partner-primaries", warn_lines);
108 }
109
110 partner_name = *found_primaries.begin();
111 break;
112 }
113 }
114
115 if (!metadata_provider->exists(partner_name)) {
116 std::vector<std::string> err_msg{};
117 err_msg.emplace_back(diag->formatter().format(
118 "Resolved partner primary '{}' for secondary '{}' does not exist.",
119 FormatParam{partner_name, Style::bold},
120 FormatParam{tileset_name, Style::bold}));
121 err_msg.emplace_back("Create it first or pair with a different tileset.");
122 err_msg.append_range(format_config_note_with_separator(diag->formatter(), pairing_mode));
123 err_msg.append_range(format_config_note_with_separator(diag->formatter(), partners));
124 return FormattableError{err_msg};
125 }
126 if (!tileset_manager->is_porytiles_managed(partner_name)) {
127 std::vector<std::string> err_msg{};
128 err_msg.emplace_back(diag->formatter().format(
129 "Secondary compilation requires a Porytiles-managed primary, but '{}' is not Porytiles-managed.",
130 FormatParam{partner_name, Style::bold}));
131 err_msg.emplace_back("Import it first or pair with a different tileset.");
132 err_msg.append_range(format_config_note_with_separator(diag->formatter(), pairing_mode));
133 err_msg.append_range(format_config_note_with_separator(diag->formatter(), partners));
134 return FormattableError{err_msg};
135 }
136
137 constexpr auto tag = "resolve-partner-primary";
138 diag->remark(
139 tag,
140 "Resolved partner primary '{}' for secondary '{}'.",
141 FormatParam{partner_name, Style::bold},
142 FormatParam{tileset_name, Style::bold});
143 std::vector<std::string> note_lines{};
144 note_lines.append_range(format_config_note(diag->formatter(), pairing_mode));
145 note_lines.append_range(format_config_note_with_separator(diag->formatter(), partners));
146 diag->remark_note(tag, note_lines);
147
149 primary_tileset,
150 tileset_repo->load(partner_name),
151 std::unique_ptr<Tileset>,
152 "Failed to load partner primary '{}' for secondary '{}'.",
153 FormatParam{partner_name, Style::bold},
154 FormatParam{tileset_name, Style::bold});
155
156 return primary_tileset;
157}
158
159} // namespace porytiles
#define PT_TRY_ASSIGN_CHAIN_ERR(var, expr, return_type,...)
Unwraps a ChainableResult, chaining a new error message on failure.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
A container that wraps a configuration value with its name and source information.
const T & value() const &
A text parameter with associated styling for formatted output.
General-purpose error implementation with formatted message support.
Definition error.hpp:63
Abstract interface for querying layout metadata by name.
virtual ChainableResult< std::string > secondary_tileset(const std::string &layout_name_or_id) const =0
Determines the given layout's secondary tileset.
virtual ChainableResult< std::set< std::string > > layout_names() const =0
Returns all layout names known to this provider.
virtual ChainableResult< std::string > primary_tileset(const std::string &layout_name_or_id) const =0
Determines the given layout's primary tileset.
Abstract interface for querying Porytiles tileset ownership.
virtual bool is_porytiles_managed(const std::string &tileset_name) const =0
Checks whether a tileset is managed by Porytiles.
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.
Abstract interface for querying tileset metadata by name.
virtual bool exists(const std::string &tileset_name) const =0
Checks whether a tileset exists in the backing store for the given tileset name.
Repository interface for the Tileset aggregate root.
ChainableResult< std::unique_ptr< Tileset > > load(const std::string &name) const
Loads an existing Tileset from storage.
Abstract class for structured error reporting and diagnostic output.
virtual void warning_note(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged note message associated with a warning.
virtual void remark(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged remark message.
const TextFormatter & formatter() const
virtual void warning(const std::string &tag, const std::vector< std::string > &lines) const =0
Display a tagged warning 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.
@ automatic
Scan layout metadata to find the partner primary automatically.
@ off
Skip primary loading entirely. Compile as a standalone secondary.
@ manual
Use the partner primary specified via primary_pairing_partners config.
ChainableResult< std::unique_ptr< Tileset > > resolve_partner_primary(const std::string &tileset_name, const ConfigValue< PrimaryPairingMode > &pairing_mode, const ConfigValue< std::vector< std::string > > &partners, const TilesetRepo *tileset_repo, const TilesetMetadataProvider *metadata_provider, const LayoutMetadataProvider *layout_metadata_provider, const PorytilesTilesetManager *tileset_manager, const UserDiagnostics *diag)
Resolves the partner primary tileset for a secondary tileset.
std::vector< std::string > format_config_note(const TextFormatter &format, const ConfigValue< T > &config)
Format a ConfigValue into diagnostic note lines.
std::vector< std::string > format_config_note_with_separator(const TextFormatter &format, const ConfigValue< T > &config)
Format a ConfigValue into diagnostic note lines with a separator.