yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_automation_service.cc
Go to the documentation of this file.
2
3#ifdef YAZE_WITH_GRPC
4
6
7#include <grpcpp/grpcpp.h>
8
11#include "protos/canvas_automation.grpc.pb.h"
12#include "protos/canvas_automation.pb.h"
13
14namespace yaze {
15
16namespace {
17
18// Helper to convert absl::Status to grpc::Status
19grpc::Status ConvertStatus(const absl::Status& status) {
20 if (status.ok()) {
21 return grpc::Status::OK;
22 }
23
24 grpc::StatusCode code;
25 switch (status.code()) {
26 case absl::StatusCode::kNotFound:
27 code = grpc::StatusCode::NOT_FOUND;
28 break;
29 case absl::StatusCode::kInvalidArgument:
30 code = grpc::StatusCode::INVALID_ARGUMENT;
31 break;
32 case absl::StatusCode::kFailedPrecondition:
33 code = grpc::StatusCode::FAILED_PRECONDITION;
34 break;
35 case absl::StatusCode::kOutOfRange:
36 code = grpc::StatusCode::OUT_OF_RANGE;
37 break;
38 case absl::StatusCode::kUnimplemented:
39 code = grpc::StatusCode::UNIMPLEMENTED;
40 break;
41 case absl::StatusCode::kInternal:
42 code = grpc::StatusCode::INTERNAL;
43 break;
44 case absl::StatusCode::kUnavailable:
45 code = grpc::StatusCode::UNAVAILABLE;
46 break;
47 default:
48 code = grpc::StatusCode::UNKNOWN;
49 break;
50 }
51
52 return grpc::Status(code, std::string(status.message().data(), status.message().size()));
53}
54
55} // namespace
56
57void CanvasAutomationServiceImpl::RegisterCanvas(const std::string& canvas_id,
58 gui::Canvas* canvas) {
59 canvases_[canvas_id] = canvas;
60}
61
62void CanvasAutomationServiceImpl::RegisterOverworldEditor(
63 const std::string& canvas_id, editor::OverworldEditor* editor) {
64 overworld_editors_[canvas_id] = editor;
65}
66
67gui::Canvas* CanvasAutomationServiceImpl::GetCanvas(
68 const std::string& canvas_id) {
69 auto it = canvases_.find(canvas_id);
70 if (it != canvases_.end()) {
71 return it->second;
72 }
73 return nullptr;
74}
75
76editor::OverworldEditor* CanvasAutomationServiceImpl::GetOverworldEditor(
77 const std::string& canvas_id) {
78 auto it = overworld_editors_.find(canvas_id);
79 if (it != overworld_editors_.end()) {
80 return it->second;
81 }
82 return nullptr;
83}
84
85// ============================================================================
86// Tile Operations
87// ============================================================================
88
89absl::Status CanvasAutomationServiceImpl::SetTile(
90 const proto::SetTileRequest* request, proto::SetTileResponse* response) {
91 auto* canvas = GetCanvas(request->canvas_id());
92 if (!canvas) {
93 response->set_success(false);
94 response->set_error("Canvas not found: " + request->canvas_id());
95 return absl::NotFoundError(response->error());
96 }
97
98 auto* api = canvas->GetAutomationAPI();
99 bool success = api->SetTileAt(request->x(), request->y(), request->tile_id());
100
101 response->set_success(success);
102 if (!success) {
103 response->set_error(
104 "Failed to set tile - out of bounds or callback failed");
105 }
106
107 return absl::OkStatus();
108}
109
110absl::Status CanvasAutomationServiceImpl::GetTile(
111 const proto::GetTileRequest* request, proto::GetTileResponse* response) {
112 auto* canvas = GetCanvas(request->canvas_id());
113 if (!canvas) {
114 response->set_success(false);
115 response->set_error("Canvas not found: " + request->canvas_id());
116 return absl::NotFoundError(response->error());
117 }
118
119 auto* api = canvas->GetAutomationAPI();
120 int tile_id = api->GetTileAt(request->x(), request->y());
121
122 if (tile_id >= 0) {
123 response->set_tile_id(tile_id);
124 response->set_success(true);
125 } else {
126 response->set_success(false);
127 response->set_error("Tile not found - out of bounds or no callback set");
128 }
129
130 return absl::OkStatus();
131}
132
133absl::Status CanvasAutomationServiceImpl::SetTiles(
134 const proto::SetTilesRequest* request, proto::SetTilesResponse* response) {
135 auto* canvas = GetCanvas(request->canvas_id());
136 if (!canvas) {
137 response->set_success(false);
138 response->set_error("Canvas not found: " + request->canvas_id());
139 return absl::NotFoundError(response->error());
140 }
141
142 auto* api = canvas->GetAutomationAPI();
143
144 std::vector<std::tuple<int, int, int>> tiles;
145 for (const auto& tile : request->tiles()) {
146 tiles.push_back({tile.x(), tile.y(), tile.tile_id()});
147 }
148
149 bool success = api->SetTiles(tiles);
150 response->set_success(success);
151 response->set_tiles_painted(tiles.size());
152
153 return absl::OkStatus();
154}
155
156// ============================================================================
157// Selection Operations
158// ============================================================================
159
160absl::Status CanvasAutomationServiceImpl::SelectTile(
161 const proto::SelectTileRequest* request,
162 proto::SelectTileResponse* response) {
163 auto* canvas = GetCanvas(request->canvas_id());
164 if (!canvas) {
165 response->set_success(false);
166 response->set_error("Canvas not found: " + request->canvas_id());
167 return absl::NotFoundError(response->error());
168 }
169
170 auto* api = canvas->GetAutomationAPI();
171 api->SelectTile(request->x(), request->y());
172 response->set_success(true);
173
174 return absl::OkStatus();
175}
176
177absl::Status CanvasAutomationServiceImpl::SelectTileRect(
178 const proto::SelectTileRectRequest* request,
179 proto::SelectTileRectResponse* response) {
180 auto* canvas = GetCanvas(request->canvas_id());
181 if (!canvas) {
182 response->set_success(false);
183 response->set_error("Canvas not found: " + request->canvas_id());
184 return absl::NotFoundError(response->error());
185 }
186
187 auto* api = canvas->GetAutomationAPI();
188 const auto& rect = request->rect();
189 api->SelectTileRect(rect.x1(), rect.y1(), rect.x2(), rect.y2());
190
191 auto selection = api->GetSelection();
192 response->set_success(true);
193 response->set_tiles_selected(selection.selected_tiles.size());
194
195 return absl::OkStatus();
196}
197
198absl::Status CanvasAutomationServiceImpl::GetSelection(
199 const proto::GetSelectionRequest* request,
200 proto::GetSelectionResponse* response) {
201 auto* canvas = GetCanvas(request->canvas_id());
202 if (!canvas) {
203 return absl::NotFoundError("Canvas not found: " + request->canvas_id());
204 }
205
206 auto* api = canvas->GetAutomationAPI();
207 auto selection = api->GetSelection();
208
209 response->set_has_selection(selection.has_selection);
210
211 for (const auto& tile : selection.selected_tiles) {
212 auto* coord = response->add_selected_tiles();
213 coord->set_x(static_cast<int>(tile.x));
214 coord->set_y(static_cast<int>(tile.y));
215 }
216
217 auto* start = response->mutable_selection_start();
218 start->set_x(static_cast<int>(selection.selection_start.x));
219 start->set_y(static_cast<int>(selection.selection_start.y));
220
221 auto* end = response->mutable_selection_end();
222 end->set_x(static_cast<int>(selection.selection_end.x));
223 end->set_y(static_cast<int>(selection.selection_end.y));
224
225 return absl::OkStatus();
226}
227
228absl::Status CanvasAutomationServiceImpl::ClearSelection(
229 const proto::ClearSelectionRequest* request,
230 proto::ClearSelectionResponse* response) {
231 auto* canvas = GetCanvas(request->canvas_id());
232 if (!canvas) {
233 response->set_success(false);
234 return absl::NotFoundError("Canvas not found: " + request->canvas_id());
235 }
236
237 auto* api = canvas->GetAutomationAPI();
238 api->ClearSelection();
239 response->set_success(true);
240
241 return absl::OkStatus();
242}
243
244// ============================================================================
245// View Operations
246// ============================================================================
247
248absl::Status CanvasAutomationServiceImpl::ScrollToTile(
249 const proto::ScrollToTileRequest* request,
250 proto::ScrollToTileResponse* response) {
251 auto* canvas = GetCanvas(request->canvas_id());
252 if (!canvas) {
253 response->set_success(false);
254 response->set_error("Canvas not found: " + request->canvas_id());
255 return absl::NotFoundError(response->error());
256 }
257
258 auto* api = canvas->GetAutomationAPI();
259 api->ScrollToTile(request->x(), request->y(), request->center());
260 response->set_success(true);
261
262 return absl::OkStatus();
263}
264
265absl::Status CanvasAutomationServiceImpl::CenterOn(
266 const proto::CenterOnRequest* request, proto::CenterOnResponse* response) {
267 auto* canvas = GetCanvas(request->canvas_id());
268 if (!canvas) {
269 response->set_success(false);
270 response->set_error("Canvas not found: " + request->canvas_id());
271 return absl::NotFoundError(response->error());
272 }
273
274 auto* api = canvas->GetAutomationAPI();
275 api->CenterOn(request->x(), request->y());
276 response->set_success(true);
277
278 return absl::OkStatus();
279}
280
281absl::Status CanvasAutomationServiceImpl::SetZoom(
282 const proto::SetZoomRequest* request, proto::SetZoomResponse* response) {
283 auto* canvas = GetCanvas(request->canvas_id());
284 if (!canvas) {
285 response->set_success(false);
286 response->set_error("Canvas not found: " + request->canvas_id());
287 return absl::NotFoundError(response->error());
288 }
289
290 auto* api = canvas->GetAutomationAPI();
291 api->SetZoom(request->zoom());
292
293 float actual_zoom = api->GetZoom();
294 response->set_success(true);
295 response->set_actual_zoom(actual_zoom);
296
297 return absl::OkStatus();
298}
299
300absl::Status CanvasAutomationServiceImpl::GetZoom(
301 const proto::GetZoomRequest* request, proto::GetZoomResponse* response) {
302 auto* canvas = GetCanvas(request->canvas_id());
303 if (!canvas) {
304 return absl::NotFoundError("Canvas not found: " + request->canvas_id());
305 }
306
307 auto* api = canvas->GetAutomationAPI();
308 response->set_zoom(api->GetZoom());
309
310 return absl::OkStatus();
311}
312
313// ============================================================================
314// Query Operations
315// ============================================================================
316
317absl::Status CanvasAutomationServiceImpl::GetDimensions(
318 const proto::GetDimensionsRequest* request,
319 proto::GetDimensionsResponse* response) {
320 auto* canvas = GetCanvas(request->canvas_id());
321 if (!canvas) {
322 return absl::NotFoundError("Canvas not found: " + request->canvas_id());
323 }
324
325 auto* api = canvas->GetAutomationAPI();
326 auto dims = api->GetDimensions();
327
328 auto* proto_dims = response->mutable_dimensions();
329 proto_dims->set_width_tiles(dims.width_tiles);
330 proto_dims->set_height_tiles(dims.height_tiles);
331 proto_dims->set_tile_size(dims.tile_size);
332
333 return absl::OkStatus();
334}
335
336absl::Status CanvasAutomationServiceImpl::GetVisibleRegion(
337 const proto::GetVisibleRegionRequest* request,
338 proto::GetVisibleRegionResponse* response) {
339 auto* canvas = GetCanvas(request->canvas_id());
340 if (!canvas) {
341 return absl::NotFoundError("Canvas not found: " + request->canvas_id());
342 }
343
344 auto* api = canvas->GetAutomationAPI();
345 auto region = api->GetVisibleRegion();
346
347 auto* proto_region = response->mutable_region();
348 proto_region->set_min_x(region.min_x);
349 proto_region->set_min_y(region.min_y);
350 proto_region->set_max_x(region.max_x);
351 proto_region->set_max_y(region.max_y);
352
353 return absl::OkStatus();
354}
355
356absl::Status CanvasAutomationServiceImpl::IsTileVisible(
357 const proto::IsTileVisibleRequest* request,
358 proto::IsTileVisibleResponse* response) {
359 auto* canvas = GetCanvas(request->canvas_id());
360 if (!canvas) {
361 return absl::NotFoundError("Canvas not found: " + request->canvas_id());
362 }
363
364 auto* api = canvas->GetAutomationAPI();
365 response->set_is_visible(api->IsTileVisible(request->x(), request->y()));
366
367 return absl::OkStatus();
368}
369
370// ============================================================================
371// gRPC Service Wrapper
372// ============================================================================
373
381class CanvasAutomationServiceGrpc final
382 : public proto::CanvasAutomation::Service {
383 public:
384 explicit CanvasAutomationServiceGrpc(CanvasAutomationServiceImpl* impl)
385 : impl_(impl) {}
386
387 // Tile Operations
388 grpc::Status SetTile(grpc::ServerContext* context,
389 const proto::SetTileRequest* request,
390 proto::SetTileResponse* response) override {
391 return ConvertStatus(impl_->SetTile(request, response));
392 }
393
394 grpc::Status GetTile(grpc::ServerContext* context,
395 const proto::GetTileRequest* request,
396 proto::GetTileResponse* response) override {
397 return ConvertStatus(impl_->GetTile(request, response));
398 }
399
400 grpc::Status SetTiles(grpc::ServerContext* context,
401 const proto::SetTilesRequest* request,
402 proto::SetTilesResponse* response) override {
403 return ConvertStatus(impl_->SetTiles(request, response));
404 }
405
406 // Selection Operations
407 grpc::Status SelectTile(grpc::ServerContext* context,
408 const proto::SelectTileRequest* request,
409 proto::SelectTileResponse* response) override {
410 return ConvertStatus(impl_->SelectTile(request, response));
411 }
412
413 grpc::Status SelectTileRect(
414 grpc::ServerContext* context, const proto::SelectTileRectRequest* request,
415 proto::SelectTileRectResponse* response) override {
416 return ConvertStatus(impl_->SelectTileRect(request, response));
417 }
418
419 grpc::Status GetSelection(grpc::ServerContext* context,
420 const proto::GetSelectionRequest* request,
421 proto::GetSelectionResponse* response) override {
422 return ConvertStatus(impl_->GetSelection(request, response));
423 }
424
425 grpc::Status ClearSelection(
426 grpc::ServerContext* context, const proto::ClearSelectionRequest* request,
427 proto::ClearSelectionResponse* response) override {
428 return ConvertStatus(impl_->ClearSelection(request, response));
429 }
430
431 // View Operations
432 grpc::Status ScrollToTile(grpc::ServerContext* context,
433 const proto::ScrollToTileRequest* request,
434 proto::ScrollToTileResponse* response) override {
435 return ConvertStatus(impl_->ScrollToTile(request, response));
436 }
437
438 grpc::Status CenterOn(grpc::ServerContext* context,
439 const proto::CenterOnRequest* request,
440 proto::CenterOnResponse* response) override {
441 return ConvertStatus(impl_->CenterOn(request, response));
442 }
443
444 grpc::Status SetZoom(grpc::ServerContext* context,
445 const proto::SetZoomRequest* request,
446 proto::SetZoomResponse* response) override {
447 return ConvertStatus(impl_->SetZoom(request, response));
448 }
449
450 grpc::Status GetZoom(grpc::ServerContext* context,
451 const proto::GetZoomRequest* request,
452 proto::GetZoomResponse* response) override {
453 return ConvertStatus(impl_->GetZoom(request, response));
454 }
455
456 // Query Operations
457 grpc::Status GetDimensions(grpc::ServerContext* context,
458 const proto::GetDimensionsRequest* request,
459 proto::GetDimensionsResponse* response) override {
460 return ConvertStatus(impl_->GetDimensions(request, response));
461 }
462
463 grpc::Status GetVisibleRegion(
464 grpc::ServerContext* context,
465 const proto::GetVisibleRegionRequest* request,
466 proto::GetVisibleRegionResponse* response) override {
467 return ConvertStatus(impl_->GetVisibleRegion(request, response));
468 }
469
470 grpc::Status IsTileVisible(grpc::ServerContext* context,
471 const proto::IsTileVisibleRequest* request,
472 proto::IsTileVisibleResponse* response) override {
473 return ConvertStatus(impl_->IsTileVisible(request, response));
474 }
475
476 private:
477 CanvasAutomationServiceImpl* impl_;
478};
479
480// Factory function to create the gRPC wrapper
481// Returns as base grpc::Service* to avoid incomplete type issues in headers
482std::unique_ptr<grpc::Service> CreateCanvasAutomationServiceGrpc(
483 CanvasAutomationServiceImpl* impl) {
484 return std::make_unique<CanvasAutomationServiceGrpc>(impl);
485}
486
487} // namespace yaze
488
489#endif // YAZE_WITH_GRPC