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