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 }
52 return absl::PermissionDeniedError(
53 "Project builds are disabled by the project's read-only policy");
54 }
55
56 Rom build_rom;
57 status = build_rom.LoadFromFile(project.rom_filename);
58 if (!status.ok()) {
59 return status;
60 }
61
62 // Apply BPS patches - cross-platform with std::filesystem
63 namespace fs = std::filesystem;
64 std::vector<std::string> bps_files;
65
66 try {
67 for (const auto& entry : fs::directory_iterator(project.patches_folder)) {
68 if (entry.path().extension() == ".bps") {
69 bps_files.push_back(entry.path().string());
70 }
71 }
72 } catch (const fs::filesystem_error& e) {
73 // Patches folder doesn't exist or not accessible
74 }
75
76 for (const auto& patch_file : bps_files) {
77 std::ifstream patch_stream(patch_file, std::ios::binary);
78 if (!patch_stream.is_open()) {
79 return absl::InternalError("Failed to open BPS patch: " + patch_file);
80 }
81
82 std::vector<uint8_t> patch_data(
83 (std::istreambuf_iterator<char>(patch_stream)),
84 std::istreambuf_iterator<char>());
85 if (patch_data.empty()) {
86 return absl::InvalidArgumentError("BPS patch is empty: " + patch_file);
87 }
88
89 std::vector<uint8_t> patched_rom;
90 auto apply_status =
91 util::ApplyBpsPatch(build_rom.vector(), patch_data, patched_rom);
92 if (!apply_status.ok()) {
93 return absl::InternalError("Failed to apply BPS patch " + patch_file +
94 ": " + std::string(apply_status.message()));
95 }
96
97 auto load_patched_status = build_rom.LoadFromData(patched_rom);
98 if (!load_patched_status.ok()) {
99 return absl::InternalError("Failed to load patched ROM after " +
100 patch_file + ": " +
101 std::string(load_patched_status.message()));
102 }
103 }
104
105 // Run asar on assembly files - cross-platform
106 std::vector<std::string> asm_files;
107 try {
108 for (const auto& entry : fs::directory_iterator(project.patches_folder)) {
109 if (entry.path().extension() == ".asm") {
110 asm_files.push_back(entry.path().string());
111 }
112 }
113 } catch (const fs::filesystem_error& e) {
114 // No asm files
115 }
116
117 // Apply ASM patches using Asar
118 if (!asm_files.empty()) {
120 auto init_status = asar.Initialize();
121 if (!init_status.ok()) {
122 formatter.AddField("warning",
123 "Asar not available, skipping ASM patches: " +
124 std::string(init_status.message()));
125 } else {
126 for (const auto& asm_file : asm_files) {
127 auto rom_data = build_rom.vector();
128 auto result = asar.ApplyPatch(asm_file, rom_data);
129
130 if (!result.ok()) {
131 return absl::InternalError("ASM patch failed for " + asm_file + ": " +
132 std::string(result.status().message()));
133 }
134
135 if (result->success) {
136 build_rom.LoadFromData(rom_data);
137 formatter.AddField("asm_applied", asm_file);
138
139 // Log extracted symbols count
140 if (!result->symbols.empty()) {
141 formatter.AddField(
142 "symbols_" + fs::path(asm_file).stem().string(),
143 std::to_string(result->symbols.size()) + " symbols");
144 }
145 } else {
146 // Log errors but continue with other patches
147 std::string error_msg = "Errors in " + asm_file + ":";
148 for (const auto& error : result->errors) {
149 error_msg += "\n " + error;
150 }
151 formatter.AddField("error", error_msg);
152 return absl::InternalError(error_msg);
153 }
154 }
155 }
156 }
157
158 std::string output_file = project.name + ".sfc";
159 status = build_rom.SaveToFile({.save_new = true, .filename = output_file});
160 if (!status.ok()) {
161 return status;
162 }
163
164 formatter.AddField("status", "success");
165 formatter.AddField("message", "Successfully built project: " + project.name);
166 formatter.AddField("project_name", project.name);
167 formatter.AddField("output_file", output_file);
168
169 return absl::OkStatus();
170}
171
172} // namespace handlers
173} // namespace cli
174} // 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:52
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:632
const auto & vector() const
Definition rom.h:217
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:893
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:781
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
RomWritePolicy write_policy
Definition project.h:229
Modern project structure with comprehensive settings consolidation.
Definition project.h:290
std::string patches_folder
Definition project.h:316
absl::Status Create(const std::string &project_name, const std::string &base_path)
Definition project.cc:528
absl::Status Open(const std::string &project_path)
Definition project.cc:607