7#include <grpcpp/grpcpp.h>
12#include "protos/canvas_automation.grpc.pb.h"
13#include "protos/canvas_automation.pb.h"
20grpc::Status ConvertStatus(
const absl::Status& status) {
22 return grpc::Status::OK;
25 grpc::StatusCode code;
26 switch (status.code()) {
27 case absl::StatusCode::kNotFound:
28 code = grpc::StatusCode::NOT_FOUND;
30 case absl::StatusCode::kInvalidArgument:
31 code = grpc::StatusCode::INVALID_ARGUMENT;
33 case absl::StatusCode::kFailedPrecondition:
34 code = grpc::StatusCode::FAILED_PRECONDITION;
36 case absl::StatusCode::kOutOfRange:
37 code = grpc::StatusCode::OUT_OF_RANGE;
39 case absl::StatusCode::kUnimplemented:
40 code = grpc::StatusCode::UNIMPLEMENTED;
42 case absl::StatusCode::kInternal:
43 code = grpc::StatusCode::INTERNAL;
45 case absl::StatusCode::kUnavailable:
46 code = grpc::StatusCode::UNAVAILABLE;
49 code = grpc::StatusCode::UNKNOWN;
53 return grpc::Status(code, std::string(status.message().data(), status.message().size()));
58void CanvasAutomationServiceImpl::RegisterCanvas(
const std::string& canvas_id,
59 gui::Canvas* canvas) {
60 canvases_[canvas_id] = canvas;
63void CanvasAutomationServiceImpl::RegisterOverworldEditor(
64 const std::string& canvas_id, editor::OverworldEditor* editor) {
65 overworld_editors_[canvas_id] = editor;
68gui::Canvas* CanvasAutomationServiceImpl::GetCanvas(
69 const std::string& canvas_id) {
70 auto it = canvases_.find(canvas_id);
71 if (it != canvases_.end()) {
77editor::OverworldEditor* CanvasAutomationServiceImpl::GetOverworldEditor(
78 const std::string& canvas_id) {
79 auto it = overworld_editors_.find(canvas_id);
80 if (it != overworld_editors_.end()) {
90absl::Status CanvasAutomationServiceImpl::SetTile(
91 const proto::SetTileRequest* request, proto::SetTileResponse* response) {
92 auto* canvas = GetCanvas(request->canvas_id());
94 response->set_success(
false);
95 response->set_error(
"Canvas not found: " + request->canvas_id());
96 return absl::NotFoundError(response->error());
99 auto* api = canvas->GetAutomationAPI();
100 bool success = api->SetTileAt(request->x(), request->y(), request->tile_id());
102 response->set_success(success);
105 "Failed to set tile - out of bounds or callback failed");
108 return absl::OkStatus();
111absl::Status CanvasAutomationServiceImpl::GetTile(
112 const proto::GetTileRequest* request, proto::GetTileResponse* response) {
113 auto* canvas = GetCanvas(request->canvas_id());
115 response->set_success(
false);
116 response->set_error(
"Canvas not found: " + request->canvas_id());
117 return absl::NotFoundError(response->error());
120 auto* api = canvas->GetAutomationAPI();
121 int tile_id = api->GetTileAt(request->x(), request->y());
124 response->set_tile_id(tile_id);
125 response->set_success(
true);
127 response->set_success(
false);
128 response->set_error(
"Tile not found - out of bounds or no callback set");
131 return absl::OkStatus();
134absl::Status CanvasAutomationServiceImpl::SetTiles(
135 const proto::SetTilesRequest* request, proto::SetTilesResponse* response) {
136 auto* canvas = GetCanvas(request->canvas_id());
138 response->set_success(
false);
139 response->set_error(
"Canvas not found: " + request->canvas_id());
140 return absl::NotFoundError(response->error());
143 auto* api = canvas->GetAutomationAPI();
145 std::vector<std::tuple<int, int, int>> tiles;
146 for (
const auto& tile : request->tiles()) {
147 tiles.push_back({tile.x(), tile.y(), tile.tile_id()});
150 bool success = api->SetTiles(tiles);
151 response->set_success(success);
152 response->set_tiles_painted(tiles.size());
154 return absl::OkStatus();
161absl::Status CanvasAutomationServiceImpl::SelectTile(
162 const proto::SelectTileRequest* request,
163 proto::SelectTileResponse* response) {
164 auto* canvas = GetCanvas(request->canvas_id());
166 response->set_success(
false);
167 response->set_error(
"Canvas not found: " + request->canvas_id());
168 return absl::NotFoundError(response->error());
171 auto* api = canvas->GetAutomationAPI();
172 api->SelectTile(request->x(), request->y());
173 response->set_success(
true);
175 return absl::OkStatus();
178absl::Status CanvasAutomationServiceImpl::SelectTileRect(
179 const proto::SelectTileRectRequest* request,
180 proto::SelectTileRectResponse* response) {
181 auto* canvas = GetCanvas(request->canvas_id());
183 response->set_success(
false);
184 response->set_error(
"Canvas not found: " + request->canvas_id());
185 return absl::NotFoundError(response->error());
188 auto* api = canvas->GetAutomationAPI();
189 const auto& rect = request->rect();
190 api->SelectTileRect(rect.x1(), rect.y1(), rect.x2(), rect.y2());
192 auto selection = api->GetSelection();
193 response->set_success(
true);
194 response->set_tiles_selected(selection.selected_tiles.size());
196 return absl::OkStatus();
199absl::Status CanvasAutomationServiceImpl::GetSelection(
200 const proto::GetSelectionRequest* request,
201 proto::GetSelectionResponse* response) {
202 auto* canvas = GetCanvas(request->canvas_id());
204 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
207 auto* api = canvas->GetAutomationAPI();
208 auto selection = api->GetSelection();
210 response->set_has_selection(selection.has_selection);
212 for (
const auto& tile : selection.selected_tiles) {
213 auto* coord = response->add_selected_tiles();
214 coord->set_x(
static_cast<int>(tile.x));
215 coord->set_y(
static_cast<int>(tile.y));
218 auto* start = response->mutable_selection_start();
219 start->set_x(
static_cast<int>(selection.selection_start.x));
220 start->set_y(
static_cast<int>(selection.selection_start.y));
222 auto* end = response->mutable_selection_end();
223 end->set_x(
static_cast<int>(selection.selection_end.x));
224 end->set_y(
static_cast<int>(selection.selection_end.y));
226 return absl::OkStatus();
229absl::Status CanvasAutomationServiceImpl::ClearSelection(
230 const proto::ClearSelectionRequest* request,
231 proto::ClearSelectionResponse* response) {
232 auto* canvas = GetCanvas(request->canvas_id());
234 response->set_success(
false);
235 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
238 auto* api = canvas->GetAutomationAPI();
239 api->ClearSelection();
240 response->set_success(
true);
242 return absl::OkStatus();
249absl::Status CanvasAutomationServiceImpl::ScrollToTile(
250 const proto::ScrollToTileRequest* request,
251 proto::ScrollToTileResponse* response) {
252 auto* canvas = GetCanvas(request->canvas_id());
254 response->set_success(
false);
255 response->set_error(
"Canvas not found: " + request->canvas_id());
256 return absl::NotFoundError(response->error());
259 auto* api = canvas->GetAutomationAPI();
260 api->ScrollToTile(request->x(), request->y(), request->center());
261 response->set_success(
true);
263 return absl::OkStatus();
266absl::Status CanvasAutomationServiceImpl::CenterOn(
267 const proto::CenterOnRequest* request, proto::CenterOnResponse* response) {
268 auto* canvas = GetCanvas(request->canvas_id());
270 response->set_success(
false);
271 response->set_error(
"Canvas not found: " + request->canvas_id());
272 return absl::NotFoundError(response->error());
275 auto* api = canvas->GetAutomationAPI();
276 api->CenterOn(request->x(), request->y());
277 response->set_success(
true);
279 return absl::OkStatus();
282absl::Status CanvasAutomationServiceImpl::SetZoom(
283 const proto::SetZoomRequest* request, proto::SetZoomResponse* response) {
284 auto* canvas = GetCanvas(request->canvas_id());
286 response->set_success(
false);
287 response->set_error(
"Canvas not found: " + request->canvas_id());
288 return absl::NotFoundError(response->error());
291 auto* api = canvas->GetAutomationAPI();
292 api->SetZoom(request->zoom());
294 float actual_zoom = api->GetZoom();
295 response->set_success(
true);
296 response->set_actual_zoom(actual_zoom);
298 return absl::OkStatus();
301absl::Status CanvasAutomationServiceImpl::GetZoom(
302 const proto::GetZoomRequest* request, proto::GetZoomResponse* response) {
303 auto* canvas = GetCanvas(request->canvas_id());
305 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
308 auto* api = canvas->GetAutomationAPI();
309 response->set_zoom(api->GetZoom());
311 return absl::OkStatus();
318absl::Status CanvasAutomationServiceImpl::GetDimensions(
319 const proto::GetDimensionsRequest* request,
320 proto::GetDimensionsResponse* response) {
321 auto* canvas = GetCanvas(request->canvas_id());
323 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
326 auto* api = canvas->GetAutomationAPI();
327 auto dims = api->GetDimensions();
329 auto* proto_dims = response->mutable_dimensions();
330 proto_dims->set_width_tiles(dims.width_tiles);
331 proto_dims->set_height_tiles(dims.height_tiles);
332 proto_dims->set_tile_size(dims.tile_size);
334 return absl::OkStatus();
337absl::Status CanvasAutomationServiceImpl::GetVisibleRegion(
338 const proto::GetVisibleRegionRequest* request,
339 proto::GetVisibleRegionResponse* response) {
340 auto* canvas = GetCanvas(request->canvas_id());
342 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
345 auto* api = canvas->GetAutomationAPI();
346 auto region = api->GetVisibleRegion();
348 auto* proto_region = response->mutable_region();
349 proto_region->set_min_x(region.min_x);
350 proto_region->set_min_y(region.min_y);
351 proto_region->set_max_x(region.max_x);
352 proto_region->set_max_y(region.max_y);
354 return absl::OkStatus();
357absl::Status CanvasAutomationServiceImpl::IsTileVisible(
358 const proto::IsTileVisibleRequest* request,
359 proto::IsTileVisibleResponse* response) {
360 auto* canvas = GetCanvas(request->canvas_id());
362 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
365 auto* api = canvas->GetAutomationAPI();
366 response->set_is_visible(api->IsTileVisible(request->x(), request->y()));
368 return absl::OkStatus();
375absl::Status CanvasAutomationServiceImpl::ScreenToTile(
376 const proto::ScreenToTileRequest* request,
377 proto::ScreenToTileResponse* response) {
378 auto* canvas = GetCanvas(request->canvas_id());
380 response->set_success(
false);
381 response->set_error(
"Canvas not found: " + request->canvas_id());
382 return absl::NotFoundError(response->error());
386 gui::CoordinateMapper mapper;
387 mapper.SetCanvasId(request->canvas_id());
390 gui::CanvasGeometry geometry;
391 geometry.canvas_p0 = canvas->zero_point();
392 geometry.canvas_sz = canvas->canvas_size();
393 geometry.canvas_p1 = ImVec2(geometry.canvas_p0.x + geometry.canvas_sz.x,
394 geometry.canvas_p0.y + geometry.canvas_sz.y);
395 geometry.scrolling = canvas->scrolling();
396 mapper.SetGeometry(geometry);
397 mapper.SetScale(canvas->global_scale());
400 gui::CoordinateMapperConfig config;
401 config.tile_size = canvas->GetGridStep();
402 config.tiles_per_row =
static_cast<int>(canvas->canvas_size().x / config.tile_size);
403 config.tiles_per_col =
static_cast<int>(canvas->canvas_size().y / config.tile_size);
404 config.use_tile16 = (config.tile_size == 16.0f);
405 mapper.SetConfig(config);
408 auto result = mapper.ScreenToTile(request->screen_x(), request->screen_y());
411 response->set_success(
true);
412 response->set_screen_x(result.screen_x);
413 response->set_screen_y(result.screen_y);
414 response->set_canvas_x(result.canvas_x);
415 response->set_canvas_y(result.canvas_y);
416 response->set_content_x(result.content_x);
417 response->set_content_y(result.content_y);
418 response->set_in_canvas_bounds(result.in_canvas_bounds);
421 auto* tile_info = response->mutable_tile_info();
422 tile_info->set_tile_id(result.tile_info.tile_id);
423 tile_info->set_tile16_index(result.tile_info.tile16_index);
424 tile_info->set_rom_offset(result.tile_info.rom_offset);
425 tile_info->set_palette_group(result.tile_info.palette_group);
426 tile_info->set_palette_index(result.tile_info.palette_index);
427 tile_info->set_tile_origin_x(result.tile_info.tile_origin_px.x);
428 tile_info->set_tile_origin_y(result.tile_info.tile_origin_px.y);
429 tile_info->set_tile_width(result.tile_info.tile_size_px.x);
430 tile_info->set_tile_height(result.tile_info.tile_size_px.y);
431 tile_info->set_is_valid(result.tile_info.is_valid);
432 tile_info->set_map_x(result.tile_info.map_x);
433 tile_info->set_map_y(result.tile_info.map_y);
434 tile_info->set_local_map_id(result.tile_info.local_map_id);
436 return absl::OkStatus();
450class CanvasAutomationServiceGrpc final
451 :
public proto::CanvasAutomation::Service {
453 explicit CanvasAutomationServiceGrpc(CanvasAutomationServiceImpl* impl)
457 grpc::Status SetTile(grpc::ServerContext* context,
458 const proto::SetTileRequest* request,
459 proto::SetTileResponse* response)
override {
460 return ConvertStatus(impl_->SetTile(request, response));
463 grpc::Status GetTile(grpc::ServerContext* context,
464 const proto::GetTileRequest* request,
465 proto::GetTileResponse* response)
override {
466 return ConvertStatus(impl_->GetTile(request, response));
469 grpc::Status SetTiles(grpc::ServerContext* context,
470 const proto::SetTilesRequest* request,
471 proto::SetTilesResponse* response)
override {
472 return ConvertStatus(impl_->SetTiles(request, response));
476 grpc::Status SelectTile(grpc::ServerContext* context,
477 const proto::SelectTileRequest* request,
478 proto::SelectTileResponse* response)
override {
479 return ConvertStatus(impl_->SelectTile(request, response));
482 grpc::Status SelectTileRect(
483 grpc::ServerContext* context,
const proto::SelectTileRectRequest* request,
484 proto::SelectTileRectResponse* response)
override {
485 return ConvertStatus(impl_->SelectTileRect(request, response));
488 grpc::Status GetSelection(grpc::ServerContext* context,
489 const proto::GetSelectionRequest* request,
490 proto::GetSelectionResponse* response)
override {
491 return ConvertStatus(impl_->GetSelection(request, response));
494 grpc::Status ClearSelection(
495 grpc::ServerContext* context,
const proto::ClearSelectionRequest* request,
496 proto::ClearSelectionResponse* response)
override {
497 return ConvertStatus(impl_->ClearSelection(request, response));
501 grpc::Status ScrollToTile(grpc::ServerContext* context,
502 const proto::ScrollToTileRequest* request,
503 proto::ScrollToTileResponse* response)
override {
504 return ConvertStatus(impl_->ScrollToTile(request, response));
507 grpc::Status CenterOn(grpc::ServerContext* context,
508 const proto::CenterOnRequest* request,
509 proto::CenterOnResponse* response)
override {
510 return ConvertStatus(impl_->CenterOn(request, response));
513 grpc::Status SetZoom(grpc::ServerContext* context,
514 const proto::SetZoomRequest* request,
515 proto::SetZoomResponse* response)
override {
516 return ConvertStatus(impl_->SetZoom(request, response));
519 grpc::Status GetZoom(grpc::ServerContext* context,
520 const proto::GetZoomRequest* request,
521 proto::GetZoomResponse* response)
override {
522 return ConvertStatus(impl_->GetZoom(request, response));
526 grpc::Status GetDimensions(grpc::ServerContext* context,
527 const proto::GetDimensionsRequest* request,
528 proto::GetDimensionsResponse* response)
override {
529 return ConvertStatus(impl_->GetDimensions(request, response));
532 grpc::Status GetVisibleRegion(
533 grpc::ServerContext* context,
534 const proto::GetVisibleRegionRequest* request,
535 proto::GetVisibleRegionResponse* response)
override {
536 return ConvertStatus(impl_->GetVisibleRegion(request, response));
539 grpc::Status IsTileVisible(grpc::ServerContext* context,
540 const proto::IsTileVisibleRequest* request,
541 proto::IsTileVisibleResponse* response)
override {
542 return ConvertStatus(impl_->IsTileVisible(request, response));
546 grpc::Status ScreenToTile(grpc::ServerContext* context,
547 const proto::ScreenToTileRequest* request,
548 proto::ScreenToTileResponse* response)
override {
549 return ConvertStatus(impl_->ScreenToTile(request, response));
553 CanvasAutomationServiceImpl* impl_;
558std::unique_ptr<grpc::Service> CreateCanvasAutomationServiceGrpc(
559 CanvasAutomationServiceImpl* impl) {
560 return std::make_unique<CanvasAutomationServiceGrpc>(impl);