10#include "fmt/format.h"
21const std::filesystem::path graphics_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"graphics.h";
22const std::filesystem::path metatiles_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"metatiles.h";
24const std::string tileset_prefix =
"gTileset_";
25const std::string porytiles_managed_suffix =
"PorytilesManaged_";
28[[nodiscard]] std::string extract_shorthand(
const std::string &tileset_name)
30 if (!tileset_name.starts_with(tileset_prefix)) {
33 return tileset_name.substr(tileset_prefix.size());
37[[nodiscard]] std::string
38generate_tiles_declaration(
const std::string &shorthand,
const std::string &bin_path_base,
const std::string &snake_dir)
41 "const u32 gTilesetTiles_{}{}[] = INCBIN_U32(\"{}/{}/porytiles_bin/tiles.4bpp.lz\");",
42 porytiles_managed_suffix,
49[[nodiscard]] std::vector<std::string> generate_palettes_declaration(
50 const std::string &shorthand,
51 const std::string &bin_path_base,
52 const std::string &snake_dir,
53 std::size_t num_palettes)
55 std::vector<std::string> lines;
57 lines.push_back(fmt::format(
"const u16 gTilesetPalettes_{}{}[][16] =", porytiles_managed_suffix, shorthand));
58 lines.emplace_back(
"{");
64 " INCBIN_U16(\"{}/{}/porytiles_bin/palettes/{:02}.gbapal\"){}", bin_path_base, snake_dir, i,
comma));
67 lines.emplace_back(
"};");
72[[nodiscard]] std::string generate_metatiles_declaration(
73 const std::string &shorthand,
const std::string &bin_path_base,
const std::string &snake_dir)
76 "const u16 gMetatiles_{}{}[] = INCBIN_U16(\"{}/{}/porytiles_bin/metatiles.bin\");",
77 porytiles_managed_suffix,
90[[nodiscard]] std::string generate_attributes_declaration(
91 const std::string &shorthand,
92 const std::string &bin_path_base,
93 const std::string &snake_dir,
94 std::size_t attribute_bytes)
96 const std::string c_type = (attribute_bytes == 4) ?
"u32" : (attribute_bytes == 1) ?
"u8" :
"u16";
97 const std::string incbin_macro = (attribute_bytes == 4) ?
"INCBIN_U32"
98 : (attribute_bytes == 1) ?
"INCBIN_U8"
101 "const {} gMetatileAttributes_{}{}[] = {}(\"{}/{}/porytiles_bin/metatile_attributes.bin\");",
103 porytiles_managed_suffix,
112read_file_lines(
const std::filesystem::path &path,
const TextFormatter *format)
114 std::ifstream in{path};
120 std::vector<std::string> lines;
122 while (std::getline(in, line)) {
123 lines.push_back(line);
130write_file_lines(
const std::filesystem::path &path,
const std::vector<std::string> &lines,
const TextFormatter *format)
132 std::ofstream out{path};
133 if (!out.is_open()) {
138 for (
const auto &line : lines) {
156[[nodiscard]]
bool is_porytiles_managed_declaration(
const std::string &line,
const std::string &shorthand)
158 const std::string pattern = porytiles_managed_suffix + shorthand;
159 for (std::size_t pos = line.find(pattern); pos != std::string::npos; pos = line.find(pattern, pos + 1)) {
160 const std::size_t after = pos + pattern.size();
161 if (after >= line.size()) {
164 const auto next =
static_cast<unsigned char>(line[after]);
165 if (std::isalnum(next) == 0 && next !=
'_') {
177[[nodiscard]] std::vector<std::string>
178strip_graphics_declarations(
const std::vector<std::string> &lines,
const std::string &shorthand)
180 std::vector<std::string> filtered_lines;
181 bool in_palette_array =
false;
183 for (
const auto &line : lines) {
184 if (is_porytiles_managed_declaration(line, shorthand)) {
186 if (line.find(
"[][16] =") != std::string::npos) {
187 in_palette_array =
true;
193 if (in_palette_array) {
195 if (line.find(
"};") != std::string::npos) {
196 in_palette_array =
false;
201 filtered_lines.push_back(line);
204 return filtered_lines;
211[[nodiscard]] std::vector<std::string>
212strip_metatiles_declarations(
const std::vector<std::string> &lines,
const std::string &shorthand)
214 std::vector<std::string> filtered_lines;
215 for (
const auto &line : lines) {
216 if (!is_porytiles_managed_declaration(line, shorthand)) {
217 filtered_lines.push_back(line);
220 return filtered_lines;
224void trim_trailing_blank_lines(std::vector<std::string> &lines)
226 while (!lines.empty() && lines.back().find_first_not_of(
" \t") == std::string::npos) {
236 std::filesystem::path project_root, gsl::not_null<const TextFormatter *> format)
237 : project_root_{std::move(project_root)}, format_{format}
242 const std::string &tileset_name,
const std::string &bin_path_base, std::size_t num_palettes)
const
244 const std::string shorthand = extract_shorthand(tileset_name);
245 if (shorthand.empty()) {
251 const auto graphics_path = project_root_ / graphics_rel_path;
256 read_file_lines(graphics_path, format_),
258 "Failed to read graphics.h for tileset '{}'.",
262 const std::string tiles_decl = generate_tiles_declaration(shorthand, bin_path_base, snake_dir);
263 auto palettes_decl_lines = generate_palettes_declaration(shorthand, bin_path_base, snake_dir, num_palettes);
268 lines = strip_graphics_declarations(lines, shorthand);
269 trim_trailing_blank_lines(lines);
271 lines.emplace_back(
"");
272 lines.push_back(tiles_decl);
273 lines.emplace_back(
"");
274 lines.append_range(palettes_decl_lines);
277 return write_file_lines(graphics_path, lines, format_);
281 const std::string &tileset_name,
const std::string &bin_path_base, std::size_t attribute_bytes)
const
283 const std::string shorthand = extract_shorthand(tileset_name);
284 if (shorthand.empty()) {
290 const auto metatiles_path = project_root_ / metatiles_rel_path;
295 read_file_lines(metatiles_path, format_),
297 "Failed to read metatiles.h for tileset '{}'.",
301 const std::string metatiles_decl = generate_metatiles_declaration(shorthand, bin_path_base, snake_dir);
302 const std::string attributes_decl =
303 generate_attributes_declaration(shorthand, bin_path_base, snake_dir, attribute_bytes);
308 lines = strip_metatiles_declarations(lines, shorthand);
309 trim_trailing_blank_lines(lines);
311 lines.emplace_back(
"");
312 lines.push_back(metatiles_decl);
313 lines.push_back(attributes_decl);
316 return write_file_lines(metatiles_path, lines, format_);
321 const std::string shorthand = extract_shorthand(tileset_name);
322 if (shorthand.empty()) {
329 const auto graphics_path = project_root_ / graphics_rel_path;
333 read_file_lines(graphics_path, format_),
335 "Failed to read graphics.h for tileset '{}'.",
338 const std::vector<std::string> filtered_lines = strip_graphics_declarations(lines, shorthand);
340 auto write_result = write_file_lines(graphics_path, filtered_lines, format_);
341 if (!write_result.has_value()) {
348 const auto metatiles_path = project_root_ / metatiles_rel_path;
352 read_file_lines(metatiles_path, format_),
354 "Failed to read metatiles.h for tileset '{}'.",
357 const std::vector<std::string> filtered_lines = strip_metatiles_declarations(lines, shorthand);
359 auto write_result = write_file_lines(metatiles_path, filtered_lines, format_);
360 if (!write_result.has_value()) {
#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 smart string wrapper that preserves word structure for lossless case format conversion.
std::string to_snake_case() const
Outputs all words flattened and joined with underscores.
ChainableResult< void > append_graphics_declarations(const std::string &tileset_name, const std::string &bin_path_base, std::size_t num_palettes) const
Appends INCBIN declarations for a Porytiles-managed tileset to graphics.h.
ChainableResult< void > remove_declarations(const std::string &tileset_name) const
Removes INCBIN declarations for a Porytiles-managed tileset (for restore workflow).
IncbinDeclarationAppender(std::filesystem::path project_root, gsl::not_null< const TextFormatter * > format)
Constructs an IncbinDeclarationAppender with required dependencies.
ChainableResult< void > append_metatiles_declarations(const std::string &tileset_name, const std::string &bin_path_base, std::size_t attribute_bytes) const
Appends INCBIN declarations for a Porytiles-managed tileset to metatiles.h.
static const Style bold
Bold text formatting.
Abstract base class for applying text styling with context-aware formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > ¶ms) const
Formats a string with styled parameters using fmtlib syntax.
constexpr std::size_t num_palettes