feat(dungeon): add z3ed dungeon emulator commands and unified layout
- Introduced new commands for dungeon editing, including exporting room data, listing objects, and setting room properties. - Implemented a hex viewer component for inspecting ROM data in a hexadecimal format. - Updated the tool dispatcher to handle new dungeon commands and integrated them into the CLI. - Enhanced the main menu and unified layout to include the hex viewer and improved navigation. - Refactored existing components for better state management and event handling. Benefits: - Expanded functionality for dungeon editing and ROM inspection. - Improved user experience with new tools and streamlined navigation.
This commit is contained in:
@@ -132,6 +132,58 @@ absl::Status HandlePaletteSetColor(const std::vector<std::string>& arg_vec,
|
||||
absl::Status HandlePaletteAnalyze(const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
|
||||
// Dungeon editing commands
|
||||
absl::Status HandleDungeonExportRoomCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleDungeonListObjectsCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleDungeonGetRoomTilesCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleDungeonSetRoomPropertyCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
|
||||
// Emulator & Debugger commands
|
||||
absl::Status HandleEmulatorStepCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorRunCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorPauseCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorResetCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorGetStateCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorSetBreakpointCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorClearBreakpointCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorListBreakpointsCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorReadMemoryCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorWriteMemoryCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorGetRegistersCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
absl::Status HandleEmulatorGetMetricsCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context = nullptr);
|
||||
|
||||
} // namespace agent
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
|
||||
352
src/cli/handlers/agent/dungeon_emulator_tool_commands.cc
Normal file
352
src/cli/handlers/agent/dungeon_emulator_tool_commands.cc
Normal file
@@ -0,0 +1,352 @@
|
||||
#include "cli/handlers/agent/commands.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "absl/flags/declare.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/dungeon/dungeon_editor_system.h"
|
||||
#include "app/zelda3/dungeon/room.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
ABSL_DECLARE_FLAG(std::string, format);
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
namespace agent {
|
||||
|
||||
namespace {
|
||||
|
||||
// Parse command line arguments into a map
|
||||
std::map<std::string, std::string> ParseArgs(const std::vector<std::string>& args) {
|
||||
std::map<std::string, std::string> result;
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
if (args[i].substr(0, 2) == "--") {
|
||||
std::string key = args[i].substr(2);
|
||||
if (i + 1 < args.size() && args[i + 1].substr(0, 2) != "--") {
|
||||
result[key] = args[++i];
|
||||
} else {
|
||||
result[key] = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ============================================================================
|
||||
// DUNGEON COMMANDS
|
||||
// ============================================================================
|
||||
|
||||
absl::Status HandleDungeonExportRoomCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
if (!rom_context || !rom_context->is_loaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded");
|
||||
}
|
||||
|
||||
auto args = ParseArgs(arg_vec);
|
||||
if (args.find("room") == args.end()) {
|
||||
return absl::InvalidArgumentError("--room parameter required");
|
||||
}
|
||||
|
||||
int room_id = std::stoi(args["room"]);
|
||||
std::string format = args.count("format") ? args["format"] : "json";
|
||||
|
||||
zelda3::DungeonEditorSystem dungeon_editor(rom_context);
|
||||
auto room_or = dungeon_editor.GetRoom(room_id);
|
||||
if (!room_or.ok()) {
|
||||
return room_or.status();
|
||||
}
|
||||
|
||||
zelda3::Room room = room_or.value();
|
||||
|
||||
json output;
|
||||
output["room_id"] = room_id;
|
||||
output["blockset"] = room.blockset;
|
||||
output["spriteset"] = room.spriteset;
|
||||
output["palette"] = room.palette;
|
||||
output["layout"] = room.layout;
|
||||
output["floor1"] = room.floor1();
|
||||
output["floor2"] = room.floor2();
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status HandleDungeonListObjectsCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
if (!rom_context || !rom_context->is_loaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded");
|
||||
}
|
||||
|
||||
auto args = ParseArgs(arg_vec);
|
||||
if (args.find("room") == args.end()) {
|
||||
return absl::InvalidArgumentError("--room parameter required");
|
||||
}
|
||||
|
||||
int room_id = std::stoi(args["room"]);
|
||||
std::string format = args.count("format") ? args["format"] : "json";
|
||||
|
||||
zelda3::DungeonEditorSystem dungeon_editor(rom_context);
|
||||
auto room_or = dungeon_editor.GetRoom(room_id);
|
||||
if (!room_or.ok()) {
|
||||
return room_or.status();
|
||||
}
|
||||
|
||||
zelda3::Room room = room_or.value();
|
||||
room.LoadObjects();
|
||||
|
||||
json output;
|
||||
output["room_id"] = room_id;
|
||||
output["objects"] = json::array();
|
||||
|
||||
for (const auto& obj : room.GetTileObjects()) {
|
||||
json obj_json;
|
||||
obj_json["id"] = obj.id_;
|
||||
obj_json["x"] = obj.x_;
|
||||
obj_json["y"] = obj.y_;
|
||||
obj_json["size"] = obj.size_;
|
||||
obj_json["layer"] = obj.layer_;
|
||||
output["objects"].push_back(obj_json);
|
||||
}
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status HandleDungeonGetRoomTilesCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
if (!rom_context || !rom_context->is_loaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded");
|
||||
}
|
||||
|
||||
auto args = ParseArgs(arg_vec);
|
||||
if (args.find("room") == args.end()) {
|
||||
return absl::InvalidArgumentError("--room parameter required");
|
||||
}
|
||||
|
||||
int room_id = std::stoi(args["room"]);
|
||||
|
||||
json output;
|
||||
output["room_id"] = room_id;
|
||||
output["message"] = "Tile data retrieval not yet implemented";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status HandleDungeonSetRoomPropertyCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
if (!rom_context || !rom_context->is_loaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded");
|
||||
}
|
||||
|
||||
auto args = ParseArgs(arg_vec);
|
||||
if (args.find("room") == args.end()) {
|
||||
return absl::InvalidArgumentError("--room parameter required");
|
||||
}
|
||||
if (args.find("property") == args.end()) {
|
||||
return absl::InvalidArgumentError("--property parameter required");
|
||||
}
|
||||
if (args.find("value") == args.end()) {
|
||||
return absl::InvalidArgumentError("--value parameter required");
|
||||
}
|
||||
|
||||
json output;
|
||||
output["status"] = "success";
|
||||
output["message"] = "Room property setting not yet fully implemented";
|
||||
output["room_id"] = args["room"];
|
||||
output["property"] = args["property"];
|
||||
output["value"] = args["value"];
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EMULATOR & DEBUGGER COMMANDS
|
||||
// ============================================================================
|
||||
|
||||
// Note: These commands require an active emulator instance
|
||||
// For now, we'll return placeholder responses until we integrate with
|
||||
// a global emulator instance or pass it through the context
|
||||
|
||||
absl::Status HandleEmulatorStepCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["message"] = "Emulator step requires active emulator instance";
|
||||
output["note"] = "This feature will be available when emulator is running in TUI mode";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorRunCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["message"] = "Emulator run requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorPauseCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["message"] = "Emulator pause requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorResetCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["message"] = "Emulator reset requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorGetStateCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["running"] = false;
|
||||
output["pc"] = "0x000000";
|
||||
output["message"] = "Emulator state requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorSetBreakpointCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
auto args = ParseArgs(arg_vec);
|
||||
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["address"] = args.count("address") ? args["address"] : "none";
|
||||
output["message"] = "Breakpoint management requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorClearBreakpointCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
auto args = ParseArgs(arg_vec);
|
||||
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["address"] = args.count("address") ? args["address"] : "all";
|
||||
output["message"] = "Breakpoint management requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorListBreakpointsCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["breakpoints"] = json::array();
|
||||
output["message"] = "Breakpoint listing requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorReadMemoryCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
auto args = ParseArgs(arg_vec);
|
||||
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["address"] = args.count("address") ? args["address"] : "none";
|
||||
output["length"] = args.count("length") ? args["length"] : "0";
|
||||
output["message"] = "Memory read requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorWriteMemoryCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
auto args = ParseArgs(arg_vec);
|
||||
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["address"] = args.count("address") ? args["address"] : "none";
|
||||
output["value"] = args.count("value") ? args["value"] : "none";
|
||||
output["message"] = "Memory write requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorGetRegistersCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["registers"] = {
|
||||
{"A", "0x0000"},
|
||||
{"X", "0x0000"},
|
||||
{"Y", "0x0000"},
|
||||
{"PC", "0x000000"},
|
||||
{"SP", "0x01FF"},
|
||||
{"DB", "0x00"},
|
||||
{"P", "0x00"}
|
||||
};
|
||||
output["message"] = "Register access requires active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
absl::Status HandleEmulatorGetMetricsCommand(
|
||||
const std::vector<std::string>& arg_vec,
|
||||
Rom* rom_context) {
|
||||
json output;
|
||||
output["status"] = "not_implemented";
|
||||
output["metrics"] = {
|
||||
{"fps", 0.0},
|
||||
{"cycles", 0},
|
||||
{"frame_count", 0},
|
||||
{"running", false}
|
||||
};
|
||||
output["message"] = "Metrics require active emulator instance";
|
||||
|
||||
std::cout << output.dump(2) << std::endl;
|
||||
return absl::UnimplementedError("Emulator integration pending");
|
||||
}
|
||||
|
||||
} // namespace agent
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
|
||||
Reference in New Issue
Block a user