yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
emulator_commands.cc
Go to the documentation of this file.
2
3#include <grpcpp/grpcpp.h>
4
5#include "absl/status/statusor.h"
6#include "absl/strings/escaping.h"
7#include "absl/strings/str_split.h"
8#include "absl/strings/string_view.h"
9#include "absl/time/time.h"
10#include "protos/emulator_service.grpc.pb.h"
11
12namespace yaze {
13namespace cli {
14namespace handlers {
15
16namespace {
17
18// A simple client for the EmulatorService
20 public:
22 auto channel = grpc::CreateChannel("localhost:50051",
23 grpc::InsecureChannelCredentials());
24 stub_ = agent::EmulatorService::NewStub(channel);
25 }
26
27 template <typename TRequest, typename TResponse>
28 absl::StatusOr<TResponse> CallRpc(
29 grpc::Status (agent::EmulatorService::Stub::*rpc_method)(
30 grpc::ClientContext*, const TRequest&, TResponse*),
31 const TRequest& request) {
32 TResponse response;
33 grpc::ClientContext context;
34
35 auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(5);
36 context.set_deadline(deadline);
37
38 grpc::Status status =
39 (stub_.get()->*rpc_method)(&context, request, &response);
40
41 if (!status.ok()) {
42 return absl::UnavailableError(absl::StrFormat(
43 "RPC failed: (%d) %s", status.error_code(), status.error_message()));
44 }
45 return response;
46 }
47
48 private:
49 std::unique_ptr<agent::EmulatorService::Stub> stub_;
50};
51
52// Helper to parse button from string
53absl::StatusOr<agent::Button> StringToButton(absl::string_view s) {
54 if (s == "A")
55 return agent::Button::A;
56 if (s == "B")
57 return agent::Button::B;
58 if (s == "X")
59 return agent::Button::X;
60 if (s == "Y")
61 return agent::Button::Y;
62 if (s == "L")
63 return agent::Button::L;
64 if (s == "R")
65 return agent::Button::R;
66 if (s == "SELECT")
67 return agent::Button::SELECT;
68 if (s == "START")
69 return agent::Button::START;
70 if (s == "UP")
71 return agent::Button::UP;
72 if (s == "DOWN")
73 return agent::Button::DOWN;
74 if (s == "LEFT")
75 return agent::Button::LEFT;
76 if (s == "RIGHT")
77 return agent::Button::RIGHT;
78 return absl::InvalidArgumentError(absl::StrCat("Unknown button: ", s));
79}
80
81} // namespace
82
83// --- Command Implementations ---
84
86 Rom* rom, const resources::ArgumentParser& parser,
87 resources::OutputFormatter& formatter) {
88 EmulatorClient client;
89 agent::Empty request;
90 auto response_or =
91 client.CallRpc(&agent::EmulatorService::Stub::Reset, request);
92 if (!response_or.ok()) {
93 return response_or.status();
94 }
95 auto response = response_or.value();
96
97 formatter.BeginObject("EmulatorReset");
98 formatter.AddField("success", response.success());
99 formatter.AddField("message", response.message());
100 formatter.EndObject();
101 return absl::OkStatus();
102}
103
105 Rom* rom, const resources::ArgumentParser& parser,
106 resources::OutputFormatter& formatter) {
107 EmulatorClient client;
108 agent::GameStateRequest request;
109 request.set_include_screenshot(parser.HasFlag("screenshot"));
110
111 auto response_or =
112 client.CallRpc(&agent::EmulatorService::Stub::GetGameState, request);
113 if (!response_or.ok()) {
114 return response_or.status();
115 }
116 auto response = response_or.value();
117
118 formatter.BeginObject("EmulatorState");
119 formatter.AddField("game_mode", static_cast<uint64_t>(response.game_mode()));
120 formatter.AddField("link_state",
121 static_cast<uint64_t>(response.link_state()));
122 formatter.AddField("link_pos_x",
123 static_cast<uint64_t>(response.link_pos_x()));
124 formatter.AddField("link_pos_y",
125 static_cast<uint64_t>(response.link_pos_y()));
126 formatter.AddField("link_health",
127 static_cast<uint64_t>(response.link_health()));
128 if (!response.screenshot_png().empty()) {
129 formatter.AddField("screenshot_size",
130 static_cast<uint64_t>(response.screenshot_png().size()));
131 }
132 formatter.EndObject();
133 return absl::OkStatus();
134}
135
137 Rom* rom, const resources::ArgumentParser& parser,
138 resources::OutputFormatter& formatter) {
139 EmulatorClient client;
140 agent::MemoryRequest request;
141
142 uint32_t address;
143 if (!absl::SimpleHexAtoi(parser.GetString("address").value(), &address)) {
144 return absl::InvalidArgumentError("Invalid address format.");
145 }
146 request.set_address(address);
147 request.set_size(parser.GetInt("length").value_or(16));
148
149 auto response_or =
150 client.CallRpc(&agent::EmulatorService::Stub::ReadMemory, request);
151 if (!response_or.ok()) {
152 return response_or.status();
153 }
154 auto response = response_or.value();
155
156 formatter.BeginObject("MemoryRead");
157 formatter.AddHexField("address", response.address());
158 formatter.AddField("data_hex", absl::BytesToHexString(response.data()));
159 formatter.EndObject();
160 return absl::OkStatus();
161}
162
164 Rom* rom, const resources::ArgumentParser& parser,
165 resources::OutputFormatter& formatter) {
166 EmulatorClient client;
167 agent::MemoryWriteRequest request;
168
169 uint32_t address;
170 if (!absl::SimpleHexAtoi(parser.GetString("address").value(), &address)) {
171 return absl::InvalidArgumentError("Invalid address format.");
172 }
173 request.set_address(address);
174
175 std::string data_hex = parser.GetString("data").value();
176 request.set_data(absl::HexStringToBytes(data_hex));
177
178 auto response_or =
179 client.CallRpc(&agent::EmulatorService::Stub::WriteMemory, request);
180 if (!response_or.ok()) {
181 return response_or.status();
182 }
183 auto response = response_or.value();
184
185 formatter.BeginObject("MemoryWrite");
186 formatter.AddField("success", response.success());
187 formatter.AddField("message", response.message());
188 formatter.EndObject();
189 return absl::OkStatus();
190}
191
193 Rom* rom, const resources::ArgumentParser& parser,
194 resources::OutputFormatter& formatter) {
195 EmulatorClient client;
196 agent::ButtonRequest request;
197 std::vector<std::string> buttons =
198 absl::StrSplit(parser.GetString("buttons").value(), ',');
199 for (const auto& btn_str : buttons) {
200 auto button_or = StringToButton(btn_str);
201 if (!button_or.ok())
202 return button_or.status();
203 request.add_buttons(button_or.value());
204 }
205
206 auto response_or =
207 client.CallRpc(&agent::EmulatorService::Stub::PressButtons, request);
208 if (!response_or.ok()) {
209 return response_or.status();
210 }
211 auto response = response_or.value();
212
213 formatter.BeginObject("PressButtons");
214 formatter.AddField("success", response.success());
215 formatter.AddField("message", response.message());
216 formatter.EndObject();
217 return absl::OkStatus();
218}
219
221 Rom* rom, const resources::ArgumentParser& parser,
222 resources::OutputFormatter& formatter) {
223 EmulatorClient client;
224 agent::ButtonRequest request;
225 std::vector<std::string> buttons =
226 absl::StrSplit(parser.GetString("buttons").value(), ',');
227 for (const auto& btn_str : buttons) {
228 auto button_or = StringToButton(btn_str);
229 if (!button_or.ok())
230 return button_or.status();
231 request.add_buttons(button_or.value());
232 }
233
234 auto response_or =
235 client.CallRpc(&agent::EmulatorService::Stub::ReleaseButtons, request);
236 if (!response_or.ok()) {
237 return response_or.status();
238 }
239 auto response = response_or.value();
240
241 formatter.BeginObject("ReleaseButtons");
242 formatter.AddField("success", response.success());
243 formatter.AddField("message", response.message());
244 formatter.EndObject();
245 return absl::OkStatus();
246}
247
249 Rom* rom, const resources::ArgumentParser& parser,
250 resources::OutputFormatter& formatter) {
251 EmulatorClient client;
252 agent::ButtonHoldRequest request;
253 std::vector<std::string> buttons =
254 absl::StrSplit(parser.GetString("buttons").value(), ',');
255 for (const auto& btn_str : buttons) {
256 auto button_or = StringToButton(btn_str);
257 if (!button_or.ok())
258 return button_or.status();
259 request.add_buttons(button_or.value());
260 }
261 request.set_duration_ms(parser.GetInt("duration").value());
262
263 auto response_or =
264 client.CallRpc(&agent::EmulatorService::Stub::HoldButtons, request);
265 if (!response_or.ok()) {
266 return response_or.status();
267 }
268 auto response = response_or.value();
269
270 formatter.BeginObject("HoldButtons");
271 formatter.AddField("success", response.success());
272 formatter.AddField("message", response.message());
273 formatter.EndObject();
274 return absl::OkStatus();
275}
276
277// --- Placeholder Implementations for commands not yet migrated to gRPC ---
278
280 Rom* rom, const resources::ArgumentParser& parser,
281 resources::OutputFormatter& formatter) {
282 formatter.BeginObject("Emulator Step");
283 formatter.AddField("status", "not_implemented");
284 formatter.EndObject();
285 return absl::OkStatus();
286}
287
289 Rom* rom, const resources::ArgumentParser& parser,
290 resources::OutputFormatter& formatter) {
291 formatter.BeginObject("Emulator Run");
292 formatter.AddField("status", "not_implemented");
293 formatter.EndObject();
294 return absl::OkStatus();
295}
296
298 Rom* rom, const resources::ArgumentParser& parser,
299 resources::OutputFormatter& formatter) {
300 formatter.BeginObject("Emulator Pause");
301 formatter.AddField("status", "not_implemented");
302 formatter.EndObject();
303 return absl::OkStatus();
304}
305
307 Rom* rom, const resources::ArgumentParser& parser,
308 resources::OutputFormatter& formatter) {
309 formatter.BeginObject("Emulator Breakpoint Set");
310 formatter.AddField("status", "not_implemented");
311 formatter.EndObject();
312 return absl::OkStatus();
313}
314
316 Rom* rom, const resources::ArgumentParser& parser,
317 resources::OutputFormatter& formatter) {
318 formatter.BeginObject("Emulator Breakpoint Cleared");
319 formatter.AddField("status", "not_implemented");
320 formatter.EndObject();
321 return absl::OkStatus();
322}
323
325 Rom* rom, const resources::ArgumentParser& parser,
326 resources::OutputFormatter& formatter) {
327 formatter.BeginObject("Emulator Breakpoints");
328 formatter.AddField("status", "not_implemented");
329 formatter.EndObject();
330 return absl::OkStatus();
331}
332
334 Rom* rom, const resources::ArgumentParser& parser,
335 resources::OutputFormatter& formatter) {
336 formatter.BeginObject("Emulator Registers");
337 formatter.AddField("status", "not_implemented");
338 formatter.EndObject();
339 return absl::OkStatus();
340}
341
343 Rom* rom, const resources::ArgumentParser& parser,
344 resources::OutputFormatter& formatter) {
345 formatter.BeginObject("Emulator Metrics");
346 formatter.AddField("status", "not_implemented");
347 formatter.EndObject();
348 return absl::OkStatus();
349}
350
351} // namespace handlers
352} // namespace cli
353} // 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:24
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.
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.
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.
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.
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.
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.
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.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::StatusOr< TResponse > CallRpc(grpc::Status(agent::EmulatorService::Stub::*rpc_method)(grpc::ClientContext *, const TRequest &, TResponse *), const TRequest &request)
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)
bool HasFlag(const std::string &name) const
Check if a flag is present.
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
Utility for consistent output formatting across commands.
void BeginObject(const std::string &title="")
Start a JSON object or text section.
void EndObject()
End a JSON object or text section.
void AddField(const std::string &key, const std::string &value)
Add a key-value pair.
void AddHexField(const std::string &key, uint64_t value, int width=2)
Add a hex-formatted field.
absl::StatusOr< agent::Button > StringToButton(absl::string_view s)