yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
project_commands.cc
Go to the documentation of this file.
2
3#include <filesystem>
4#include <fstream>
5#include <iostream>
6
7#include "core/asar_wrapper.h"
8#include "core/project.h"
9#include "util/bps.h"
10#include "util/file_util.h"
11#include "util/macro.h"
12
13namespace yaze {
14namespace cli {
15namespace handlers {
16
18 Rom* rom, const resources::ArgumentParser& parser,
19 resources::OutputFormatter& formatter) {
20 auto project_opt = parser.GetString("project_name");
21
22 if (!project_opt.has_value()) {
23 return absl::InvalidArgumentError(
24 "Missing required argument: project_name");
25 }
26
27 std::string project_name = project_opt.value();
28
30 auto status = project.Create(project_name, ".");
31 if (!status.ok()) {
32 return status;
33 }
34
35 formatter.AddField("status", "success");
36 formatter.AddField("message",
37 "Successfully initialized project: " + project_name);
38 formatter.AddField("project_name", project_name);
39
40 return absl::OkStatus();
41}
42
44 Rom* rom, const resources::ArgumentParser& parser,
45 resources::OutputFormatter& formatter) {
47 auto status = project.Open(".");
48 if (!status.ok()) {
49 return status;
50 }
51
52 Rom build_rom;
53 status = build_rom.LoadFromFile(project.rom_filename);
54 if (!status.ok()) {
55 return status;
56 }
57
58 // Apply BPS patches - cross-platform with std::filesystem
59 namespace fs = std::filesystem;
60 std::vector<std::string> bps_files;
61
62 try {
63 for (const auto& entry : fs::directory_iterator(project.patches_folder)) {
64 if (entry.path().extension() == ".bps") {
65 bps_files.push_back(entry.path().string());
66 }
67 }
68 } catch (const fs::filesystem_error& e) {
69 // Patches folder doesn't exist or not accessible
70 }
71
72 for (const auto& patch_file : bps_files) {
73 std::ifstream patch_stream(patch_file, std::ios::binary);
74 if (!patch_stream.is_open()) {
75 return absl::InternalError("Failed to open BPS patch: " + patch_file);
76 }
77
78 std::vector<uint8_t> patch_data(
79 (std::istreambuf_iterator<char>(patch_stream)),
80 std::istreambuf_iterator<char>());
81 if (patch_data.empty()) {
82 return absl::InvalidArgumentError("BPS patch is empty: " + patch_file);
83 }
84
85 std::vector<uint8_t> patched_rom;
86 auto apply_status =
87 util::ApplyBpsPatch(build_rom.vector(), patch_data, patched_rom);
88 if (!apply_status.ok()) {
89 return absl::InternalError("Failed to apply BPS patch " + patch_file +
90 ": " + std::string(apply_status.message()));
91 }
92
93 auto load_patched_status = build_rom.LoadFromData(patched_rom);
94 if (!load_patched_status.ok()) {
95 return absl::InternalError("Failed to load patched ROM after " +
96 patch_file + ": " +
97 std::string(load_patched_status.message()));
98 }
99 }
100
101 // Run asar on assembly files - cross-platform
102 std::vector<std::string> asm_files;
103 try {
104 for (const auto& entry : fs::directory_iterator(project.patches_folder)) {
105 if (entry.path().extension() == ".asm") {
106 asm_files.push_back(entry.path().string());
107 }
108 }
109 } catch (const fs::filesystem_error& e) {
110 // No asm files
111 }
112
113 // Apply ASM patches using Asar
114 if (!asm_files.empty()) {
116 auto init_status = asar.Initialize();
117 if (!init_status.ok()) {
118 formatter.AddField("warning",
119 "Asar not available, skipping ASM patches: " +
120 std::string(init_status.message()));
121 } else {
122 for (const auto& asm_file : asm_files) {
123 auto rom_data = build_rom.vector();
124 auto result = asar.ApplyPatch(asm_file, rom_data);
125
126 if (!result.ok()) {
127 return absl::InternalError("ASM patch failed for " + asm_file + ": " +
128 std::string(result.status().message()));
129 }
130
131 if (result->success) {
132 build_rom.LoadFromData(rom_data);
133 formatter.AddField("asm_applied", asm_file);
134
135 // Log extracted symbols count
136 if (!result->symbols.empty()) {
137 formatter.AddField(
138 "symbols_" + fs::path(asm_file).stem().string(),
139 std::to_string(result->symbols.size()) + " symbols");
140 }
141 } else {
142 // Log errors but continue with other patches
143 std::string error_msg = "Errors in " + asm_file + ":";
144 for (const auto& error : result->errors) {
145 error_msg += "\n " + error;
146 }
147 formatter.AddField("error", error_msg);
148 return absl::InternalError(error_msg);
149 }
150 }
151 }
152 }
153
154 std::string output_file = project.name + ".sfc";
155 status = build_rom.SaveToFile({.save_new = true, .filename = output_file});
156 if (!status.ok()) {
157 return status;
158 }
159
160 formatter.AddField("status", "success");
161 formatter.AddField("message", "Successfully built project: " + project.name);
162 formatter.AddField("project_name", project.name);
163 formatter.AddField("output_file", output_file);
164
165 return absl::OkStatus();
166}
167
168} // namespace handlers
169} // namespace cli
170} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:155
const auto & vector() const
Definition rom.h:143
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:291
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:255
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
Utility for consistent output formatting across commands.
void AddField(const std::string &key, const std::string &value)
Add a key-value pair.
Modern C++ wrapper for Asar 65816 assembler integration.
absl::StatusOr< AsarPatchResult > ApplyPatch(const std::string &patch_path, std::vector< uint8_t > &rom_data, const std::vector< std::string > &include_paths={})
absl::Status Initialize()
absl::Status ApplyBpsPatch(const std::vector< uint8_t > &source, const std::vector< uint8_t > &patch, std::vector< uint8_t > &output)
Definition bps.cc:75
Modern project structure with comprehensive settings consolidation.
Definition project.h:164
std::string patches_folder
Definition project.h:180
absl::Status Create(const std::string &project_name, const std::string &base_path)
Definition project.cc:244
absl::Status Open(const std::string &project_path)
Definition project.cc:323