7#include <grpcpp/grpcpp.h>
12#include "protos/canvas_automation.grpc.pb.h"
13#include "protos/canvas_automation.pb.h"
21grpc::Status ConvertStatus(
const absl::Status& status) {
23 return grpc::Status::OK;
26 grpc::StatusCode code;
27 switch (status.code()) {
28 case absl::StatusCode::kNotFound:
29 code = grpc::StatusCode::NOT_FOUND;
31 case absl::StatusCode::kInvalidArgument:
32 code = grpc::StatusCode::INVALID_ARGUMENT;
34 case absl::StatusCode::kFailedPrecondition:
35 code = grpc::StatusCode::FAILED_PRECONDITION;
37 case absl::StatusCode::kOutOfRange:
38 code = grpc::StatusCode::OUT_OF_RANGE;
40 case absl::StatusCode::kUnimplemented:
41 code = grpc::StatusCode::UNIMPLEMENTED;
43 case absl::StatusCode::kInternal:
44 code = grpc::StatusCode::INTERNAL;
46 case absl::StatusCode::kUnavailable:
47 code = grpc::StatusCode::UNAVAILABLE;
50 case absl::StatusCode::kDeadlineExceeded:
51 code = grpc::StatusCode::DEADLINE_EXCEEDED;
53 case absl::StatusCode::kCancelled:
54 code = grpc::StatusCode::CANCELLED;
57 code = grpc::StatusCode::UNKNOWN;
62 code, std::string(status.message().data(), status.message().size()));
67void CanvasAutomationServiceImpl::RegisterCanvas(
const std::string& canvas_id,
68 gui::Canvas* canvas) {
69 canvases_[canvas_id] = canvas;
72void CanvasAutomationServiceImpl::RegisterOverworldEditor(
73 const std::string& canvas_id, editor::OverworldEditor* editor) {
74 overworld_editors_[canvas_id] = editor;
77gui::Canvas* CanvasAutomationServiceImpl::GetCanvas(
78 const std::string& canvas_id) {
79 auto it = canvases_.find(canvas_id);
80 if (it != canvases_.end()) {
86editor::OverworldEditor* CanvasAutomationServiceImpl::GetOverworldEditor(
87 const std::string& canvas_id) {
88 auto it = overworld_editors_.find(canvas_id);
89 if (it != overworld_editors_.end()) {
99absl::Status CanvasAutomationServiceImpl::SetTile(
100 const proto::SetTileRequest* request, proto::SetTileResponse* response) {
101 auto* canvas = GetCanvas(request->canvas_id());
103 response->set_success(
false);
104 response->set_error(
"Canvas not found: " + request->canvas_id());
105 return absl::NotFoundError(response->error());
108 auto* api = canvas->GetAutomationAPI();
109 bool success = api->SetTileAt(request->x(), request->y(), request->tile_id());
111 response->set_success(success);
114 "Failed to set tile - out of bounds or callback failed");
117 return absl::OkStatus();
120absl::Status CanvasAutomationServiceImpl::GetTile(
121 const proto::GetTileRequest* request, proto::GetTileResponse* response) {
122 auto* canvas = GetCanvas(request->canvas_id());
124 response->set_success(
false);
125 response->set_error(
"Canvas not found: " + request->canvas_id());
126 return absl::NotFoundError(response->error());
129 auto* api = canvas->GetAutomationAPI();
130 int tile_id = api->GetTileAt(request->x(), request->y());
133 response->set_tile_id(tile_id);
134 response->set_success(
true);
136 response->set_success(
false);
137 response->set_error(
"Tile not found - out of bounds or no callback set");
140 return absl::OkStatus();
143absl::Status CanvasAutomationServiceImpl::SetTiles(
144 const proto::SetTilesRequest* request, proto::SetTilesResponse* response) {
145 auto* canvas = GetCanvas(request->canvas_id());
147 response->set_success(
false);
148 response->set_error(
"Canvas not found: " + request->canvas_id());
149 return absl::NotFoundError(response->error());
152 auto* api = canvas->GetAutomationAPI();
154 std::vector<std::tuple<int, int, int>> tiles;
155 for (
const auto& tile : request->tiles()) {
156 tiles.push_back({tile.x(), tile.y(), tile.tile_id()});
159 bool success = api->SetTiles(tiles);
160 response->set_success(success);
161 response->set_tiles_painted(tiles.size());
163 return absl::OkStatus();
170absl::Status CanvasAutomationServiceImpl::SelectTile(
171 const proto::SelectTileRequest* request,
172 proto::SelectTileResponse* response) {
173 auto* canvas = GetCanvas(request->canvas_id());
175 response->set_success(
false);
176 response->set_error(
"Canvas not found: " + request->canvas_id());
177 return absl::NotFoundError(response->error());
180 auto* api = canvas->GetAutomationAPI();
181 api->SelectTile(request->x(), request->y());
182 response->set_success(
true);
184 return absl::OkStatus();
187absl::Status CanvasAutomationServiceImpl::SelectTileRect(
188 const proto::SelectTileRectRequest* request,
189 proto::SelectTileRectResponse* response) {
190 auto* canvas = GetCanvas(request->canvas_id());
192 response->set_success(
false);
193 response->set_error(
"Canvas not found: " + request->canvas_id());
194 return absl::NotFoundError(response->error());
197 auto* api = canvas->GetAutomationAPI();
198 const auto& rect = request->rect();
199 api->SelectTileRect(rect.x1(), rect.y1(), rect.x2(), rect.y2());
201 auto selection = api->GetSelection();
202 response->set_success(
true);
203 response->set_tiles_selected(selection.selected_tiles.size());
205 return absl::OkStatus();
208absl::Status CanvasAutomationServiceImpl::GetSelection(
209 const proto::GetSelectionRequest* request,
210 proto::GetSelectionResponse* response) {
211 auto* canvas = GetCanvas(request->canvas_id());
213 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
216 auto* api = canvas->GetAutomationAPI();
217 auto selection = api->GetSelection();
219 response->set_has_selection(selection.has_selection);
221 for (
const auto& tile : selection.selected_tiles) {
222 auto* coord = response->add_selected_tiles();
223 coord->set_x(
static_cast<int>(tile.x));
224 coord->set_y(
static_cast<int>(tile.y));
227 auto* start = response->mutable_selection_start();
228 start->set_x(
static_cast<int>(selection.selection_start.x));
229 start->set_y(
static_cast<int>(selection.selection_start.y));
231 auto* end = response->mutable_selection_end();
232 end->set_x(
static_cast<int>(selection.selection_end.x));
233 end->set_y(
static_cast<int>(selection.selection_end.y));
235 return absl::OkStatus();
238absl::Status CanvasAutomationServiceImpl::ClearSelection(
239 const proto::ClearSelectionRequest* request,
240 proto::ClearSelectionResponse* response) {
241 auto* canvas = GetCanvas(request->canvas_id());
243 response->set_success(
false);
244 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
247 auto* api = canvas->GetAutomationAPI();
248 api->ClearSelection();
249 response->set_success(
true);
251 return absl::OkStatus();
258absl::Status CanvasAutomationServiceImpl::ScrollToTile(
259 const proto::ScrollToTileRequest* request,
260 proto::ScrollToTileResponse* response) {
261 auto* canvas = GetCanvas(request->canvas_id());
263 response->set_success(
false);
264 response->set_error(
"Canvas not found: " + request->canvas_id());
265 return absl::NotFoundError(response->error());
268 auto* api = canvas->GetAutomationAPI();
269 api->ScrollToTile(request->x(), request->y(), request->center());
270 response->set_success(
true);
272 return absl::OkStatus();
275absl::Status CanvasAutomationServiceImpl::CenterOn(
276 const proto::CenterOnRequest* request, proto::CenterOnResponse* response) {
277 auto* canvas = GetCanvas(request->canvas_id());
279 response->set_success(
false);
280 response->set_error(
"Canvas not found: " + request->canvas_id());
281 return absl::NotFoundError(response->error());
284 auto* api = canvas->GetAutomationAPI();
285 api->CenterOn(request->x(), request->y());
286 response->set_success(
true);
288 return absl::OkStatus();
291absl::Status CanvasAutomationServiceImpl::SetZoom(
292 const proto::SetZoomRequest* request, proto::SetZoomResponse* response) {
293 auto* canvas = GetCanvas(request->canvas_id());
295 response->set_success(
false);
296 response->set_error(
"Canvas not found: " + request->canvas_id());
297 return absl::NotFoundError(response->error());
300 auto* api = canvas->GetAutomationAPI();
301 api->SetZoom(request->zoom());
303 float actual_zoom = api->GetZoom();
304 response->set_success(
true);
305 response->set_actual_zoom(actual_zoom);
307 return absl::OkStatus();
310absl::Status CanvasAutomationServiceImpl::GetZoom(
311 const proto::GetZoomRequest* request, proto::GetZoomResponse* response) {
312 auto* canvas = GetCanvas(request->canvas_id());
314 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
317 auto* api = canvas->GetAutomationAPI();
318 response->set_zoom(api->GetZoom());
320 return absl::OkStatus();
327absl::Status CanvasAutomationServiceImpl::GetDimensions(
328 const proto::GetDimensionsRequest* request,
329 proto::GetDimensionsResponse* response) {
330 auto* canvas = GetCanvas(request->canvas_id());
332 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
335 auto* api = canvas->GetAutomationAPI();
336 auto dims = api->GetDimensions();
338 auto* proto_dims = response->mutable_dimensions();
339 proto_dims->set_width_tiles(dims.width_tiles);
340 proto_dims->set_height_tiles(dims.height_tiles);
341 proto_dims->set_tile_size(dims.tile_size);
343 return absl::OkStatus();
346absl::Status CanvasAutomationServiceImpl::GetVisibleRegion(
347 const proto::GetVisibleRegionRequest* request,
348 proto::GetVisibleRegionResponse* response) {
349 auto* canvas = GetCanvas(request->canvas_id());
351 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
354 auto* api = canvas->GetAutomationAPI();
355 auto region = api->GetVisibleRegion();
357 auto* proto_region = response->mutable_region();
358 proto_region->set_min_x(region.min_x);
359 proto_region->set_min_y(region.min_y);
360 proto_region->set_max_x(region.max_x);
361 proto_region->set_max_y(region.max_y);
363 return absl::OkStatus();
366absl::Status CanvasAutomationServiceImpl::IsTileVisible(
367 const proto::IsTileVisibleRequest* request,
368 proto::IsTileVisibleResponse* response) {
369 auto* canvas = GetCanvas(request->canvas_id());
371 return absl::NotFoundError(
"Canvas not found: " + request->canvas_id());
374 auto* api = canvas->GetAutomationAPI();
375 response->set_is_visible(api->IsTileVisible(request->x(), request->y()));
377 return absl::OkStatus();
384absl::Status CanvasAutomationServiceImpl::ScreenToTile(
385 const proto::ScreenToTileRequest* request,
386 proto::ScreenToTileResponse* response) {
387 auto* canvas = GetCanvas(request->canvas_id());
389 response->set_success(
false);
390 response->set_error(
"Canvas not found: " + request->canvas_id());
391 return absl::NotFoundError(response->error());
395 gui::CoordinateMapper mapper;
396 mapper.SetCanvasId(request->canvas_id());
399 gui::CanvasGeometry geometry;
400 geometry.canvas_p0 = canvas->zero_point();
401 geometry.canvas_sz = canvas->canvas_size();
402 geometry.canvas_p1 = ImVec2(geometry.canvas_p0.x + geometry.canvas_sz.x,
403 geometry.canvas_p0.y + geometry.canvas_sz.y);
404 geometry.scrolling = canvas->scrolling();
405 mapper.SetGeometry(geometry);
406 mapper.SetScale(canvas->global_scale());
409 gui::CoordinateMapperConfig config;
410 config.tile_size = canvas->GetGridStep();
411 config.tiles_per_row =
412 static_cast<int>(canvas->canvas_size().x / config.tile_size);
413 config.tiles_per_col =
414 static_cast<int>(canvas->canvas_size().y / config.tile_size);
415 config.use_tile16 = (config.tile_size == 16.0f);
416 mapper.SetConfig(config);
419 auto result = mapper.ScreenToTile(request->screen_x(), request->screen_y());
422 response->set_success(
true);
423 response->set_screen_x(result.screen_x);
424 response->set_screen_y(result.screen_y);
425 response->set_canvas_x(result.canvas_x);
426 response->set_canvas_y(result.canvas_y);
427 response->set_content_x(result.content_x);
428 response->set_content_y(result.content_y);
429 response->set_in_canvas_bounds(result.in_canvas_bounds);
432 auto* tile_info = response->mutable_tile_info();
433 tile_info->set_tile_id(result.tile_info.tile_id);
434 tile_info->set_tile16_index(result.tile_info.tile16_index);
435 tile_info->set_rom_offset(result.tile_info.rom_offset);
436 tile_info->set_palette_group(result.tile_info.palette_group);
437 tile_info->set_palette_index(result.tile_info.palette_index);
438 tile_info->set_tile_origin_x(result.tile_info.tile_origin_px.x);
439 tile_info->set_tile_origin_y(result.tile_info.tile_origin_px.y);
440 tile_info->set_tile_width(result.tile_info.tile_size_px.x);
441 tile_info->set_tile_height(result.tile_info.tile_size_px.y);
442 tile_info->set_is_valid(result.tile_info.is_valid);
443 tile_info->set_map_x(result.tile_info.map_x);
444 tile_info->set_map_y(result.tile_info.map_y);
445 tile_info->set_local_map_id(result.tile_info.local_map_id);
447 return absl::OkStatus();
461class CanvasAutomationServiceGrpc final
462 :
public proto::CanvasAutomation::Service {
464 explicit CanvasAutomationServiceGrpc(CanvasAutomationServiceImpl* impl)
468 grpc::Status SetTile(grpc::ServerContext* context,
469 const proto::SetTileRequest* request,
470 proto::SetTileResponse* response)
override {
471 return OnUiThread([&]() {
return impl_->SetTile(request, response); });
474 grpc::Status GetTile(grpc::ServerContext* context,
475 const proto::GetTileRequest* request,
476 proto::GetTileResponse* response)
override {
477 return OnUiThread([&]() {
return impl_->GetTile(request, response); });
480 grpc::Status SetTiles(grpc::ServerContext* context,
481 const proto::SetTilesRequest* request,
482 proto::SetTilesResponse* response)
override {
483 return OnUiThread([&]() {
return impl_->SetTiles(request, response); });
487 grpc::Status SelectTile(grpc::ServerContext* context,
488 const proto::SelectTileRequest* request,
489 proto::SelectTileResponse* response)
override {
490 return OnUiThread([&]() {
return impl_->SelectTile(request, response); });
493 grpc::Status SelectTileRect(
494 grpc::ServerContext* context,
const proto::SelectTileRectRequest* request,
495 proto::SelectTileRectResponse* response)
override {
497 [&]() {
return impl_->SelectTileRect(request, response); });
500 grpc::Status GetSelection(grpc::ServerContext* context,
501 const proto::GetSelectionRequest* request,
502 proto::GetSelectionResponse* response)
override {
503 return OnUiThread([&]() {
return impl_->GetSelection(request, response); });
506 grpc::Status ClearSelection(
507 grpc::ServerContext* context,
const proto::ClearSelectionRequest* request,
508 proto::ClearSelectionResponse* response)
override {
510 [&]() {
return impl_->ClearSelection(request, response); });
514 grpc::Status ScrollToTile(grpc::ServerContext* context,
515 const proto::ScrollToTileRequest* request,
516 proto::ScrollToTileResponse* response)
override {
517 return OnUiThread([&]() {
return impl_->ScrollToTile(request, response); });
520 grpc::Status CenterOn(grpc::ServerContext* context,
521 const proto::CenterOnRequest* request,
522 proto::CenterOnResponse* response)
override {
523 return OnUiThread([&]() {
return impl_->CenterOn(request, response); });
526 grpc::Status SetZoom(grpc::ServerContext* context,
527 const proto::SetZoomRequest* request,
528 proto::SetZoomResponse* response)
override {
529 return OnUiThread([&]() {
return impl_->SetZoom(request, response); });
532 grpc::Status GetZoom(grpc::ServerContext* context,
533 const proto::GetZoomRequest* request,
534 proto::GetZoomResponse* response)
override {
535 return OnUiThread([&]() {
return impl_->GetZoom(request, response); });
539 grpc::Status GetDimensions(grpc::ServerContext* context,
540 const proto::GetDimensionsRequest* request,
541 proto::GetDimensionsResponse* response)
override {
543 [&]() {
return impl_->GetDimensions(request, response); });
546 grpc::Status GetVisibleRegion(
547 grpc::ServerContext* context,
548 const proto::GetVisibleRegionRequest* request,
549 proto::GetVisibleRegionResponse* response)
override {
551 [&]() {
return impl_->GetVisibleRegion(request, response); });
554 grpc::Status IsTileVisible(grpc::ServerContext* context,
555 const proto::IsTileVisibleRequest* request,
556 proto::IsTileVisibleResponse* response)
override {
558 [&]() {
return impl_->IsTileVisible(request, response); });
562 grpc::Status ScreenToTile(grpc::ServerContext* context,
563 const proto::ScreenToTileRequest* request,
564 proto::ScreenToTileResponse* response)
override {
565 return OnUiThread([&]() {
return impl_->ScreenToTile(request, response); });
574 template <
typename Fn>
575 static grpc::Status OnUiThread(Fn fn) {
576 return ConvertStatus(
577 util::UiThreadQueue::Get().RunOnUiThread(std::move(fn)));
580 CanvasAutomationServiceImpl* impl_;
585std::unique_ptr<grpc::Service> CreateCanvasAutomationServiceGrpc(
586 CanvasAutomationServiceImpl* impl) {
587 return std::make_unique<CanvasAutomationServiceGrpc>(impl);