feat: Implement Canvas Automation Service for Enhanced GUI Control
- Introduced a new gRPC service for canvas automation, enabling remote control of canvas operations for AI agents, GUI testing, and collaborative editing. - Added proto definitions for canvas automation, including tile operations, selection management, and view control functionalities. - Implemented the CanvasAutomationServiceImpl class to handle various canvas operations, ensuring a robust interface for automation tasks. - Updated CMake configuration to include new proto files and service implementations, enhancing the build system for the canvas automation features.
This commit is contained in:
@@ -83,11 +83,13 @@ if(YAZE_WITH_GRPC)
|
||||
${CMAKE_SOURCE_DIR}/third_party/json/include)
|
||||
target_compile_definitions(yaze_core_lib PRIVATE YAZE_WITH_JSON)
|
||||
|
||||
# Add proto definitions for test harness and ROM service
|
||||
# Add proto definitions for test harness, ROM service, and canvas automation
|
||||
target_add_protobuf(yaze_core_lib
|
||||
${PROJECT_SOURCE_DIR}/src/app/core/proto/imgui_test_harness.proto)
|
||||
${PROJECT_SOURCE_DIR}/src/protos/imgui_test_harness.proto)
|
||||
target_add_protobuf(yaze_core_lib
|
||||
${PROJECT_SOURCE_DIR}/src/protos/rom_service.proto)
|
||||
target_add_protobuf(yaze_core_lib
|
||||
${PROJECT_SOURCE_DIR}/src/protos/canvas_automation.proto)
|
||||
|
||||
# Add test harness implementation
|
||||
target_sources(yaze_core_lib PRIVATE
|
||||
|
||||
338
src/app/core/service/canvas_automation_service.cc
Normal file
338
src/app/core/service/canvas_automation_service.cc
Normal file
@@ -0,0 +1,338 @@
|
||||
#include "app/core/service/canvas_automation_service.h"
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
|
||||
#include "src/protos/canvas_automation.pb.h"
|
||||
#include "app/editor/overworld/overworld_editor.h"
|
||||
#include "app/gui/canvas/canvas_automation_api.h"
|
||||
|
||||
namespace yaze {
|
||||
|
||||
void CanvasAutomationServiceImpl::RegisterCanvas(const std::string& canvas_id,
|
||||
gui::Canvas* canvas) {
|
||||
canvases_[canvas_id] = canvas;
|
||||
}
|
||||
|
||||
void CanvasAutomationServiceImpl::RegisterOverworldEditor(
|
||||
const std::string& canvas_id, editor::OverworldEditor* editor) {
|
||||
overworld_editors_[canvas_id] = editor;
|
||||
}
|
||||
|
||||
gui::Canvas* CanvasAutomationServiceImpl::GetCanvas(const std::string& canvas_id) {
|
||||
auto it = canvases_.find(canvas_id);
|
||||
if (it != canvases_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
editor::OverworldEditor* CanvasAutomationServiceImpl::GetOverworldEditor(
|
||||
const std::string& canvas_id) {
|
||||
auto it = overworld_editors_.find(canvas_id);
|
||||
if (it != overworld_editors_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Tile Operations
|
||||
// ============================================================================
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::SetTile(
|
||||
const proto::SetTileRequest* request, proto::SetTileResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
bool success = api->SetTileAt(request->x(), request->y(), request->tile_id());
|
||||
|
||||
response->set_success(success);
|
||||
if (!success) {
|
||||
response->set_error("Failed to set tile - out of bounds or callback failed");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::GetTile(
|
||||
const proto::GetTileRequest* request, proto::GetTileResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
int tile_id = api->GetTileAt(request->x(), request->y());
|
||||
|
||||
if (tile_id >= 0) {
|
||||
response->set_tile_id(tile_id);
|
||||
response->set_success(true);
|
||||
} else {
|
||||
response->set_success(false);
|
||||
response->set_error("Tile not found - out of bounds or no callback set");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::SetTiles(
|
||||
const proto::SetTilesRequest* request, proto::SetTilesResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
|
||||
std::vector<std::tuple<int, int, int>> tiles;
|
||||
for (const auto& tile : request->tiles()) {
|
||||
tiles.push_back({tile.x(), tile.y(), tile.tile_id()});
|
||||
}
|
||||
|
||||
bool success = api->SetTiles(tiles);
|
||||
response->set_success(success);
|
||||
response->set_tiles_painted(tiles.size());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Selection Operations
|
||||
// ============================================================================
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::SelectTile(
|
||||
const proto::SelectTileRequest* request, proto::SelectTileResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
api->SelectTile(request->x(), request->y());
|
||||
response->set_success(true);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::SelectTileRect(
|
||||
const proto::SelectTileRectRequest* request,
|
||||
proto::SelectTileRectResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
const auto& rect = request->rect();
|
||||
api->SelectTileRect(rect.x1(), rect.y1(), rect.x2(), rect.y2());
|
||||
|
||||
auto selection = api->GetSelection();
|
||||
response->set_success(true);
|
||||
response->set_tiles_selected(selection.selected_tiles.size());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::GetSelection(
|
||||
const proto::GetSelectionRequest* request,
|
||||
proto::GetSelectionResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
return absl::NotFoundError("Canvas not found: " + request->canvas_id());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
auto selection = api->GetSelection();
|
||||
|
||||
response->set_has_selection(selection.has_selection);
|
||||
|
||||
for (const auto& tile : selection.selected_tiles) {
|
||||
auto* coord = response->add_selected_tiles();
|
||||
coord->set_x(static_cast<int>(tile.x));
|
||||
coord->set_y(static_cast<int>(tile.y));
|
||||
}
|
||||
|
||||
auto* start = response->mutable_selection_start();
|
||||
start->set_x(static_cast<int>(selection.selection_start.x));
|
||||
start->set_y(static_cast<int>(selection.selection_start.y));
|
||||
|
||||
auto* end = response->mutable_selection_end();
|
||||
end->set_x(static_cast<int>(selection.selection_end.x));
|
||||
end->set_y(static_cast<int>(selection.selection_end.y));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::ClearSelection(
|
||||
const proto::ClearSelectionRequest* request,
|
||||
proto::ClearSelectionResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
return absl::NotFoundError("Canvas not found: " + request->canvas_id());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
api->ClearSelection();
|
||||
response->set_success(true);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// View Operations
|
||||
// ============================================================================
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::ScrollToTile(
|
||||
const proto::ScrollToTileRequest* request,
|
||||
proto::ScrollToTileResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
api->ScrollToTile(request->x(), request->y(), request->center());
|
||||
response->set_success(true);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::CenterOn(
|
||||
const proto::CenterOnRequest* request, proto::CenterOnResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
api->CenterOn(request->x(), request->y());
|
||||
response->set_success(true);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::SetZoom(
|
||||
const proto::SetZoomRequest* request, proto::SetZoomResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
response->set_success(false);
|
||||
response->set_error("Canvas not found: " + request->canvas_id());
|
||||
return absl::NotFoundError(response->error());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
api->SetZoom(request->zoom());
|
||||
|
||||
float actual_zoom = api->GetZoom();
|
||||
response->set_success(true);
|
||||
response->set_actual_zoom(actual_zoom);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::GetZoom(
|
||||
const proto::GetZoomRequest* request, proto::GetZoomResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
return absl::NotFoundError("Canvas not found: " + request->canvas_id());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
response->set_zoom(api->GetZoom());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Query Operations
|
||||
// ============================================================================
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::GetDimensions(
|
||||
const proto::GetDimensionsRequest* request,
|
||||
proto::GetDimensionsResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
return absl::NotFoundError("Canvas not found: " + request->canvas_id());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
auto dims = api->GetDimensions();
|
||||
|
||||
auto* proto_dims = response->mutable_dimensions();
|
||||
proto_dims->set_width_tiles(dims.width_tiles);
|
||||
proto_dims->set_height_tiles(dims.height_tiles);
|
||||
proto_dims->set_tile_size(dims.tile_size);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::GetVisibleRegion(
|
||||
const proto::GetVisibleRegionRequest* request,
|
||||
proto::GetVisibleRegionResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
return absl::NotFoundError("Canvas not found: " + request->canvas_id());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
auto region = api->GetVisibleRegion();
|
||||
|
||||
auto* proto_region = response->mutable_region();
|
||||
proto_region->set_min_x(region.min_x);
|
||||
proto_region->set_min_y(region.min_y);
|
||||
proto_region->set_max_x(region.max_x);
|
||||
proto_region->set_max_y(region.max_y);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CanvasAutomationServiceImpl::IsTileVisible(
|
||||
const proto::IsTileVisibleRequest* request,
|
||||
proto::IsTileVisibleResponse* response) {
|
||||
|
||||
auto* canvas = GetCanvas(request->canvas_id());
|
||||
if (!canvas) {
|
||||
return absl::NotFoundError("Canvas not found: " + request->canvas_id());
|
||||
}
|
||||
|
||||
auto* api = canvas->GetAutomationAPI();
|
||||
response->set_is_visible(api->IsTileVisible(request->x(), request->y()));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_WITH_GRPC
|
||||
|
||||
133
src/app/core/service/canvas_automation_service.h
Normal file
133
src/app/core/service/canvas_automation_service.h
Normal file
@@ -0,0 +1,133 @@
|
||||
#ifndef YAZE_APP_CORE_SERVICE_CANVAS_AUTOMATION_SERVICE_H_
|
||||
#define YAZE_APP_CORE_SERVICE_CANVAS_AUTOMATION_SERVICE_H_
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/gui/canvas.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace grpc {
|
||||
class ServerContext;
|
||||
}
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
class OverworldEditor;
|
||||
}
|
||||
|
||||
namespace proto {
|
||||
// Forward declare proto types
|
||||
class SetTileRequest;
|
||||
class SetTileResponse;
|
||||
class GetTileRequest;
|
||||
class GetTileResponse;
|
||||
class SetTilesRequest;
|
||||
class SetTilesResponse;
|
||||
class SelectTileRequest;
|
||||
class SelectTileResponse;
|
||||
class SelectTileRectRequest;
|
||||
class SelectTileRectResponse;
|
||||
class GetSelectionRequest;
|
||||
class GetSelectionResponse;
|
||||
class ClearSelectionRequest;
|
||||
class ClearSelectionResponse;
|
||||
class ScrollToTileRequest;
|
||||
class ScrollToTileResponse;
|
||||
class CenterOnRequest;
|
||||
class CenterOnResponse;
|
||||
class SetZoomRequest;
|
||||
class SetZoomResponse;
|
||||
class GetZoomRequest;
|
||||
class GetZoomResponse;
|
||||
class GetDimensionsRequest;
|
||||
class GetDimensionsResponse;
|
||||
class GetVisibleRegionRequest;
|
||||
class GetVisibleRegionResponse;
|
||||
class IsTileVisibleRequest;
|
||||
class IsTileVisibleResponse;
|
||||
} // namespace proto
|
||||
|
||||
/**
|
||||
* @brief Implementation of CanvasAutomation gRPC service
|
||||
*
|
||||
* Provides remote access to canvas automation API for:
|
||||
* - AI agent tool calls
|
||||
* - Remote GUI testing
|
||||
* - Collaborative editing workflows
|
||||
* - CLI automation scripts
|
||||
*/
|
||||
class CanvasAutomationServiceImpl {
|
||||
public:
|
||||
CanvasAutomationServiceImpl() = default;
|
||||
|
||||
// Register a canvas for automation
|
||||
void RegisterCanvas(const std::string& canvas_id, gui::Canvas* canvas);
|
||||
|
||||
// Register an overworld editor (for tile get/set callbacks)
|
||||
void RegisterOverworldEditor(const std::string& canvas_id,
|
||||
editor::OverworldEditor* editor);
|
||||
|
||||
// RPC method implementations
|
||||
absl::Status SetTile(const proto::SetTileRequest* request,
|
||||
proto::SetTileResponse* response);
|
||||
|
||||
absl::Status GetTile(const proto::GetTileRequest* request,
|
||||
proto::GetTileResponse* response);
|
||||
|
||||
absl::Status SetTiles(const proto::SetTilesRequest* request,
|
||||
proto::SetTilesResponse* response);
|
||||
|
||||
absl::Status SelectTile(const proto::SelectTileRequest* request,
|
||||
proto::SelectTileResponse* response);
|
||||
|
||||
absl::Status SelectTileRect(const proto::SelectTileRectRequest* request,
|
||||
proto::SelectTileRectResponse* response);
|
||||
|
||||
absl::Status GetSelection(const proto::GetSelectionRequest* request,
|
||||
proto::GetSelectionResponse* response);
|
||||
|
||||
absl::Status ClearSelection(const proto::ClearSelectionRequest* request,
|
||||
proto::ClearSelectionResponse* response);
|
||||
|
||||
absl::Status ScrollToTile(const proto::ScrollToTileRequest* request,
|
||||
proto::ScrollToTileResponse* response);
|
||||
|
||||
absl::Status CenterOn(const proto::CenterOnRequest* request,
|
||||
proto::CenterOnResponse* response);
|
||||
|
||||
absl::Status SetZoom(const proto::SetZoomRequest* request,
|
||||
proto::SetZoomResponse* response);
|
||||
|
||||
absl::Status GetZoom(const proto::GetZoomRequest* request,
|
||||
proto::GetZoomResponse* response);
|
||||
|
||||
absl::Status GetDimensions(const proto::GetDimensionsRequest* request,
|
||||
proto::GetDimensionsResponse* response);
|
||||
|
||||
absl::Status GetVisibleRegion(const proto::GetVisibleRegionRequest* request,
|
||||
proto::GetVisibleRegionResponse* response);
|
||||
|
||||
absl::Status IsTileVisible(const proto::IsTileVisibleRequest* request,
|
||||
proto::IsTileVisibleResponse* response);
|
||||
|
||||
private:
|
||||
gui::Canvas* GetCanvas(const std::string& canvas_id);
|
||||
editor::OverworldEditor* GetOverworldEditor(const std::string& canvas_id);
|
||||
|
||||
// Canvas registry
|
||||
std::unordered_map<std::string, gui::Canvas*> canvases_;
|
||||
|
||||
// Editor registry (for tile callbacks)
|
||||
std::unordered_map<std::string, editor::OverworldEditor*> overworld_editors_;
|
||||
};
|
||||
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_WITH_GRPC
|
||||
#endif // YAZE_APP_CORE_SERVICE_CANVAS_AUTOMATION_SERVICE_H_
|
||||
|
||||
236
src/protos/canvas_automation.proto
Normal file
236
src/protos/canvas_automation.proto
Normal file
@@ -0,0 +1,236 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package yaze.proto;
|
||||
|
||||
// ============================================================================
|
||||
// Canvas Automation Service
|
||||
// ============================================================================
|
||||
// Provides remote control of canvas operations for:
|
||||
// - AI agents via tool calls
|
||||
// - ImGuiTestHarness automation
|
||||
// - Remote GUI testing and validation
|
||||
// - Batch scripting workflows
|
||||
// - Coordinate conversion independent of zoom/scroll
|
||||
//
|
||||
// All operations use logical tile coordinates, not pixel coordinates.
|
||||
// This ensures commands work consistently regardless of UI zoom level.
|
||||
|
||||
service CanvasAutomation {
|
||||
// Tile Operations
|
||||
rpc SetTile(SetTileRequest) returns (SetTileResponse);
|
||||
rpc GetTile(GetTileRequest) returns (GetTileResponse);
|
||||
rpc SetTiles(SetTilesRequest) returns (SetTilesResponse);
|
||||
|
||||
// Selection Operations
|
||||
rpc SelectTile(SelectTileRequest) returns (SelectTileResponse);
|
||||
rpc SelectTileRect(SelectTileRectRequest) returns (SelectTileRectResponse);
|
||||
rpc GetSelection(GetSelectionRequest) returns (GetSelectionResponse);
|
||||
rpc ClearSelection(ClearSelectionRequest) returns (ClearSelectionResponse);
|
||||
|
||||
// View Operations
|
||||
rpc ScrollToTile(ScrollToTileRequest) returns (ScrollToTileResponse);
|
||||
rpc CenterOn(CenterOnRequest) returns (CenterOnResponse);
|
||||
rpc SetZoom(SetZoomRequest) returns (SetZoomResponse);
|
||||
rpc GetZoom(GetZoomRequest) returns (GetZoomResponse);
|
||||
|
||||
// Query Operations
|
||||
rpc GetDimensions(GetDimensionsRequest) returns (GetDimensionsResponse);
|
||||
rpc GetVisibleRegion(GetVisibleRegionRequest) returns (GetVisibleRegionResponse);
|
||||
rpc IsTileVisible(IsTileVisibleRequest) returns (IsTileVisibleResponse);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Common Types
|
||||
// ============================================================================
|
||||
|
||||
message TileCoord {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
}
|
||||
|
||||
message TileData {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
int32 tile_id = 3;
|
||||
}
|
||||
|
||||
message Rect {
|
||||
int32 x1 = 1;
|
||||
int32 y1 = 2;
|
||||
int32 x2 = 3;
|
||||
int32 y2 = 4;
|
||||
}
|
||||
|
||||
message Dimensions {
|
||||
int32 width_tiles = 1;
|
||||
int32 height_tiles = 2;
|
||||
int32 tile_size = 3;
|
||||
}
|
||||
|
||||
message VisibleRegion {
|
||||
int32 min_x = 1;
|
||||
int32 min_y = 2;
|
||||
int32 max_x = 3;
|
||||
int32 max_y = 4;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Tile Operations
|
||||
// ============================================================================
|
||||
|
||||
message SetTileRequest {
|
||||
string canvas_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
int32 tile_id = 4;
|
||||
}
|
||||
|
||||
message SetTileResponse {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message GetTileRequest {
|
||||
string canvas_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
}
|
||||
|
||||
message GetTileResponse {
|
||||
int32 tile_id = 1;
|
||||
bool success = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message SetTilesRequest {
|
||||
string canvas_id = 1;
|
||||
repeated TileData tiles = 2;
|
||||
}
|
||||
|
||||
message SetTilesResponse {
|
||||
bool success = 1;
|
||||
int32 tiles_painted = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Selection Operations
|
||||
// ============================================================================
|
||||
|
||||
message SelectTileRequest {
|
||||
string canvas_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
}
|
||||
|
||||
message SelectTileResponse {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message SelectTileRectRequest {
|
||||
string canvas_id = 1;
|
||||
Rect rect = 2;
|
||||
}
|
||||
|
||||
message SelectTileRectResponse {
|
||||
bool success = 1;
|
||||
int32 tiles_selected = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message GetSelectionRequest {
|
||||
string canvas_id = 1;
|
||||
}
|
||||
|
||||
message GetSelectionResponse {
|
||||
bool has_selection = 1;
|
||||
repeated TileCoord selected_tiles = 2;
|
||||
TileCoord selection_start = 3;
|
||||
TileCoord selection_end = 4;
|
||||
}
|
||||
|
||||
message ClearSelectionRequest {
|
||||
string canvas_id = 1;
|
||||
}
|
||||
|
||||
message ClearSelectionResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// View Operations
|
||||
// ============================================================================
|
||||
|
||||
message ScrollToTileRequest {
|
||||
string canvas_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
bool center = 4;
|
||||
}
|
||||
|
||||
message ScrollToTileResponse {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message CenterOnRequest {
|
||||
string canvas_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
}
|
||||
|
||||
message CenterOnResponse {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message SetZoomRequest {
|
||||
string canvas_id = 1;
|
||||
float zoom = 2;
|
||||
}
|
||||
|
||||
message SetZoomResponse {
|
||||
bool success = 1;
|
||||
float actual_zoom = 2; // May be clamped
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message GetZoomRequest {
|
||||
string canvas_id = 1;
|
||||
}
|
||||
|
||||
message GetZoomResponse {
|
||||
float zoom = 1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Query Operations
|
||||
// ============================================================================
|
||||
|
||||
message GetDimensionsRequest {
|
||||
string canvas_id = 1;
|
||||
}
|
||||
|
||||
message GetDimensionsResponse {
|
||||
Dimensions dimensions = 1;
|
||||
}
|
||||
|
||||
message GetVisibleRegionRequest {
|
||||
string canvas_id = 1;
|
||||
}
|
||||
|
||||
message GetVisibleRegionResponse {
|
||||
VisibleRegion region = 1;
|
||||
}
|
||||
|
||||
message IsTileVisibleRequest {
|
||||
string canvas_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
}
|
||||
|
||||
message IsTileVisibleResponse {
|
||||
bool is_visible = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user