20const std::filesystem::path graphics_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"graphics.h";
21const std::filesystem::path metatiles_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"metatiles.h";
23const std::string tileset_prefix =
"gTileset_";
24const std::string porytiles_managed_suffix =
"PorytilesManaged_";
29[[nodiscard]] std::string extract_shorthand(
const std::string &tileset_name)
31 if (!tileset_name.starts_with(tileset_prefix)) {
34 return tileset_name.substr(tileset_prefix.size());
40[[nodiscard]] std::string
41generate_tiles_declaration(
const std::string &shorthand,
const std::string &bin_path_base,
const std::string &snake_dir)
44 "const u32 gTilesetTiles_{}{}[] = INCBIN_U32(\"{}/{}/porytiles_bin/tiles.4bpp.lz\");",
45 porytiles_managed_suffix,
54[[nodiscard]] std::vector<std::string> generate_palettes_declaration(
55 const std::string &shorthand,
56 const std::string &bin_path_base,
57 const std::string &snake_dir,
58 std::size_t num_palettes)
60 std::vector<std::string> lines;
62 lines.push_back(fmt::format(
"const u16 gTilesetPalettes_{}{}[][16] =", porytiles_managed_suffix, shorthand));
63 lines.emplace_back(
"{");
65 for (std::size_t i = 0; i < num_palettes; ++i) {
66 const std::string
comma = (i < num_palettes - 1) ?
"," :
"";
69 " INCBIN_U16(\"{}/{}/porytiles_bin/palettes/{:02}.gbapal\"){}", bin_path_base, snake_dir, i,
comma));
72 lines.emplace_back(
"};");
79[[nodiscard]] std::string generate_metatiles_declaration(
80 const std::string &shorthand,
const std::string &bin_path_base,
const std::string &snake_dir)
83 "const u16 gMetatiles_{}{}[] = INCBIN_U16(\"{}/{}/porytiles_bin/metatiles.bin\");",
84 porytiles_managed_suffix,
98[[nodiscard]] std::string generate_attributes_declaration(
99 const std::string &shorthand,
100 const std::string &bin_path_base,
101 const std::string &snake_dir,
102 std::size_t metatile_attr_size)
104 const std::string c_type = (metatile_attr_size == 4) ?
"u32" :
"u16";
105 const std::string incbin_macro = (metatile_attr_size == 4) ?
"INCBIN_U32" :
"INCBIN_U16";
107 "const {} gMetatileAttributes_{}{}[] = {}(\"{}/{}/porytiles_bin/metatile_attributes.bin\");",
109 porytiles_managed_suffix,
120read_file_lines(
const std::filesystem::path &path,
const TextFormatter *format)
122 std::ifstream in{path};
128 std::vector<std::string> lines;
130 while (std::getline(in, line)) {
131 lines.push_back(line);
140write_file_lines(
const std::filesystem::path &path,
const std::vector<std::string> &lines,
const TextFormatter *format)
142 std::ofstream out{path};
143 if (!out.is_open()) {
148 for (
const auto &line : lines) {
167[[nodiscard]] std::size_t find_append_position(
const std::vector<std::string> &lines)
170 for (std::size_t i = lines.size(); i > 0; --i) {
171 const auto &line = lines[i - 1];
173 if (!line.empty() && !line.starts_with(
"#") && line.find_first_not_of(
' ') != std::string::npos) {
183[[nodiscard]]
bool is_porytiles_managed_declaration(
const std::string &line,
const std::string &shorthand)
185 const std::string pattern = porytiles_managed_suffix + shorthand;
186 return line.find(pattern) != std::string::npos;
194 std::filesystem::path project_root, gsl::not_null<const TextFormatter *> format)
195 : project_root_{std::move(project_root)}, format_{format}
200 const std::string &tileset_name,
const std::string &bin_path_base, std::size_t num_palettes)
const
202 const std::string shorthand = extract_shorthand(tileset_name);
203 if (shorthand.empty()) {
209 const auto graphics_path = project_root_ / graphics_rel_path;
214 read_file_lines(graphics_path, format_),
216 "Failed to read graphics.h for tileset '{}'.",
220 const std::string tiles_decl = generate_tiles_declaration(shorthand, bin_path_base, snake_dir);
221 auto palettes_decl_lines = generate_palettes_declaration(shorthand, bin_path_base, snake_dir, num_palettes);
224 const std::size_t pos = find_append_position(lines);
227 lines.insert(lines.begin() +
static_cast<std::ptrdiff_t
>(pos),
"");
230 lines.insert(lines.begin() +
static_cast<std::ptrdiff_t
>(pos) + 1, tiles_decl);
233 lines.insert(lines.begin() +
static_cast<std::ptrdiff_t
>(pos) + 2,
"");
236 for (std::size_t i = 0; i < palettes_decl_lines.size(); ++i) {
238 lines.begin() +
static_cast<std::ptrdiff_t
>(pos) + 3 +
static_cast<std::ptrdiff_t
>(i),
239 palettes_decl_lines[i]);
243 return write_file_lines(graphics_path, lines, format_);
247 const std::string &tileset_name,
const std::string &bin_path_base, std::size_t metatile_attr_size)
const
249 const std::string shorthand = extract_shorthand(tileset_name);
250 if (shorthand.empty()) {
256 const auto metatiles_path = project_root_ / metatiles_rel_path;
261 read_file_lines(metatiles_path, format_),
263 "Failed to read metatiles.h for tileset '{}'.",
267 const std::string metatiles_decl = generate_metatiles_declaration(shorthand, bin_path_base, snake_dir);
268 const std::string attributes_decl =
269 generate_attributes_declaration(shorthand, bin_path_base, snake_dir, metatile_attr_size);
272 const std::size_t pos = find_append_position(lines);
275 lines.insert(lines.begin() +
static_cast<std::ptrdiff_t
>(pos),
"");
278 lines.insert(lines.begin() +
static_cast<std::ptrdiff_t
>(pos) + 1, metatiles_decl);
281 lines.insert(lines.begin() +
static_cast<std::ptrdiff_t
>(pos) + 2, attributes_decl);
284 return write_file_lines(metatiles_path, lines, format_);
289 const std::string shorthand = extract_shorthand(tileset_name);
290 if (shorthand.empty()) {
297 const auto graphics_path = project_root_ / graphics_rel_path;
301 read_file_lines(graphics_path, format_),
303 "Failed to read graphics.h for tileset '{}'.",
308 std::vector<std::string> filtered_lines;
309 bool in_palette_array =
false;
311 for (
const auto &line : lines) {
312 if (is_porytiles_managed_declaration(line, shorthand)) {
314 if (line.find(
"[][16] =") != std::string::npos) {
315 in_palette_array =
true;
321 if (in_palette_array) {
323 if (line.find(
"};") != std::string::npos) {
324 in_palette_array =
false;
329 filtered_lines.push_back(line);
332 auto write_result = write_file_lines(graphics_path, filtered_lines, format_);
333 if (!write_result.has_value()) {
340 const auto metatiles_path = project_root_ / metatiles_rel_path;
344 read_file_lines(metatiles_path, format_),
346 "Failed to read metatiles.h for tileset '{}'.",
350 std::vector<std::string> filtered_lines;
351 for (
const auto &line : lines) {
352 if (!is_porytiles_managed_declaration(line, shorthand)) {
353 filtered_lines.push_back(line);
357 auto write_result = write_file_lines(metatiles_path, filtered_lines, format_);
358 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 > append_metatiles_declarations(const std::string &tileset_name, const std::string &bin_path_base, std::size_t metatile_attr_size) const
Appends INCBIN declarations for a Porytiles-managed tileset to metatiles.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.
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.