7#include "absl/strings/str_format.h"
12#include "imgui/imgui.h"
13#include "imgui/misc/cpp/imgui_stdlib.h"
19constexpr ImVec4
kGreen{0.2f, 0.75f, 0.3f, 1.0f};
20constexpr ImVec4
kRed{0.85f, 0.2f, 0.2f, 1.0f};
21constexpr ImVec4
kYellow{0.85f, 0.75f, 0.1f, 1.0f};
22constexpr ImVec4
kGrey{0.55f, 0.55f, 0.55f, 1.0f};
29 return flag ?
"OK" :
"X";
34 ImGui::TextColored(kGreen,
"[ran]");
37 if (state ==
"skipped") {
38 ImGui::TextColored(kGrey,
"[skipped]");
41 ImGui::TextColored(kYellow,
"[%s]", state.c_str());
45 ImGui::Text(
" %s", label);
47 if (flag.has_value()) {
51 ImGui::TextColored(kGrey,
"-");
58 std::ifstream file(path);
59 if (!file.is_open()) {
82 project->GetZ3dkArtifactPath(
"annotations.json"), &annotations);
83 const bool has_hooks =
85 if (!has_lint && !has_annotations && !has_hooks) {
89 if (!ImGui::CollapsingHeader(
"z3dk Artifacts",
90 ImGuiTreeNodeFlags_DefaultOpen)) {
95 const int errors = lint.contains(
"errors") && lint[
"errors"].is_array()
96 ?
static_cast<int>(lint[
"errors"].size())
99 lint.contains(
"warnings") && lint[
"warnings"].is_array()
100 ?
static_cast<int>(lint[
"warnings"].size())
102 ImGui::Text(
"Lint diagnostics: %d error(s), %d warning(s)", errors,
105 if (has_annotations) {
106 const int count = annotations.contains(
"annotations") &&
107 annotations[
"annotations"].is_array()
108 ?
static_cast<int>(annotations[
"annotations"].size())
110 ImGui::Text(
"Annotations: %d", count);
113 const int count = hooks.contains(
"hooks") && hooks[
"hooks"].is_array()
114 ?
static_cast<int>(hooks[
"hooks"].size())
116 ImGui::Text(
"Hook/write blocks: %d", count);
128 return "oracle.validation";
132 return "Hack Validation";
148 return "Hack Validation";
152 return "Run project validation and readiness checks for the active hack";
158 return project !=
nullptr && project->project_opened() && backend !=
nullptr;
162 return "Validation backend is not available for the active hack project";
190 return project->rom_filename;
195 return "roms/zelda3.sfc";
202 if (
pending_.wait_for(std::chrono::milliseconds(0)) !=
203 std::future_status::ready) {
220 oracle_validation::SmokeOptions smoke_opts;
223 smoke_opts.strict_readiness =
229 oracle_validation::PreflightOptions preflight_opts;
236 Rom* rom_context =
nullptr;
244 pending_ = std::async(std::launch::async, [mode, smoke_opts, preflight_opts,
247 return backend->RunValidation(mode, smoke_opts, preflight_opts,
251 oracle_validation::OracleRunResult result;
254 result.error_message =
"No hack workflow backend registered";
255 result.status_code = absl::StatusCode::kFailedPrecondition;
261 ImGui::SeparatorText(
"Options");
263 ImGui::SetNextItemWidth(320.0f);
264 ImGui::InputText(
"ROM Path", &
rom_path_);
266 if (ImGui::SmallButton(
"From ROM")) {
270 ImGui::SetNextItemWidth(80.0f);
276 ImGui::SeparatorText(
"Preflight options");
277 ImGui::SetNextItemWidth(200.0f);
280 ImGui::TextDisabled(
"(e.g. 0x25,0x27)");
284 ImGui::SetNextItemWidth(280.0f);
291 const bool rom_missing =
294 ImGui::BeginDisabled();
297 ImGui::BeginDisabled();
300 if (ImGui::Button(
"Run Structural Smoke")) {
304 if (ImGui::Button(
"Run Strict Readiness")) {
308 if (ImGui::Button(
"Run Oracle Preflight")) {
313 ImGui::EndDisabled();
318 ImGui::EndDisabled();
320 ImGui::TextColored(kRed,
"Load a ROM first");
326 ImGui::TextDisabled(
"No results yet. Run a check above.");
331 const char* mode_label =
335 ?
"Strict Readiness Smoke"
336 :
"Structural Smoke");
337 const bool overall_ok =
338 result.smoke.has_value()
340 : (result.preflight.has_value() && result.preflight->ok);
342 ImGui::TextColored(overall_ok ? kGreen :
kRed,
"%s %s",
CheckStr(overall_ok),
344 ImGui::SameLine(0.0f, 16.0f);
345 ImGui::TextColored(kGrey,
"%s", result.timestamp.c_str());
347 ImGui::SetNextItemWidth(380.0f);
348 ImGui::InputText(
"##cli_cmd",
const_cast<char*
>(result.cli_command.c_str()),
349 result.cli_command.size() + 1, ImGuiInputTextFlags_ReadOnly);
351 if (ImGui::SmallButton(
"Copy")) {
352 ImGui::SetClipboardText(result.cli_command.c_str());
355 if (!result.error_message.empty()) {
356 ImGui::TextColored(kRed,
ICON_MD_ERROR " %s", result.error_message.c_str());
358 "Hint: check that the ROM is loaded and the command is available.");
363 if (result.json_parse_failed) {
364 ImGui::TextColored(kYellow,
370 if (result.smoke.has_value()) {
373 if (result.preflight.has_value()) {
380 const oracle_validation::SmokeResult& smoke) {
381 if (ImGui::CollapsingHeader(
"D4 Zora Temple",
382 ImGuiTreeNodeFlags_DefaultOpen)) {
383 ImGui::TextColored(
BoolColor(smoke.d4.structural_ok),
" Structural %s",
385 ImGui::Text(
" Required rooms check:");
389 smoke.d4.required_rooms_ok);
392 if (ImGui::CollapsingHeader(
"D6 Goron Mines",
393 ImGuiTreeNodeFlags_DefaultOpen)) {
395 BoolColor(smoke.d6.meets_min_track_rooms),
" Track rooms %d / %d %s",
396 smoke.d6.track_rooms_found, smoke.d6.min_track_rooms,
397 smoke.d6.meets_min_track_rooms ?
"(ok)" :
"(below threshold)");
398 ImGui::TextColored(
BoolColor(smoke.d6.ok),
" Audit command %s",
402 if (ImGui::CollapsingHeader(
"D3 Kalyxo Castle",
403 ImGuiTreeNodeFlags_DefaultOpen)) {
404 ImGui::Text(
" Readiness check:");
412 const oracle_validation::PreflightResult& preflight) {
413 if (ImGui::CollapsingHeader(
"Water Fill", ImGuiTreeNodeFlags_DefaultOpen)) {
414 ImGui::TextColored(
BoolColor(preflight.water_fill_region_ok),
415 " Region present %s",
416 CheckStr(preflight.water_fill_region_ok));
417 ImGui::TextColored(
BoolColor(preflight.water_fill_table_ok),
419 CheckStr(preflight.water_fill_table_ok));
422 if (ImGui::CollapsingHeader(
"Custom Collision",
423 ImGuiTreeNodeFlags_DefaultOpen)) {
424 ImGui::TextColored(
BoolColor(preflight.custom_collision_maps_ok),
426 CheckStr(preflight.custom_collision_maps_ok));
427 ImGui::Text(
" Required rooms check:");
431 preflight.required_rooms_ok);
434 if (!preflight.errors.empty()) {
435 const std::string errors_label = absl::StrFormat(
436 "Errors (%d)###preflight_errors", preflight.error_count);
437 if (ImGui::CollapsingHeader(errors_label.c_str())) {
438 for (
const auto& err : preflight.errors) {
439 ImGui::TextColored(kRed,
" [%s] %s", err.code.c_str(),
440 err.message.c_str());
441 if (err.room_id.has_value()) {
443 ImGui::TextColored(kGrey,
" room %s", err.room_id->c_str());
451 const oracle_validation::OracleRunResult& result) {
452 if (ImGui::CollapsingHeader(
"Raw Output (diagnostics)")) {
453 ImGui::InputTextMultiline(
454 "##raw",
const_cast<char*
>(result.raw_output.c_str()),
455 result.raw_output.size() + 1, ImVec2(-1.0f, 120.0f),
456 ImGuiInputTextFlags_ReadOnly);
void DrawSmokeCards(const oracle_validation::SmokeResult &smoke)
std::optional< oracle_validation::OracleRunResult > last_result_
std::string GetWorkflowDescription() const override
Optional workflow description for menus/command palette.
std::string status_message_
void DrawRawOutput(const oracle_validation::OracleRunResult &result)
float GetPreferredWidth() const override
Get preferred width for this panel (optional)
std::string GetIcon() const override
Material Design icon for this panel.
std::string GetWorkflowGroup() const override
Optional workflow group for hack-centric actions.
std::string required_collision_rooms_
WindowLifecycle GetWindowLifecycle() const override
Get the lifecycle category for this window.
std::string GetId() const override
Unique identifier for this panel.
std::string GetWorkflowLabel() const override
Optional workflow label for menus/command palette.
void Draw(bool *p_open) override
Draw the panel content.
std::future< oracle_validation::OracleRunResult > pending_
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
bool IsEnabled() const override
Check if this panel is currently enabled.
void LaunchRun(oracle_validation::RunMode mode)
std::string GetDisabledTooltip() const override
Get tooltip text when panel is disabled.
static std::string DefaultRomPath()
~OracleValidationPanel() override
std::string GetEditorCategory() const override
Editor category this panel belongs to.
void DrawPreflightCards(const oracle_validation::PreflightResult &preflight)
#define ICON_MD_VERIFIED_USER
Rom * rom()
Get the current ROM instance.
::yaze::project::YazeProject * current_project()
Get the current project instance.
workflow::ValidationCapability * hack_validation_backend()
ImVec4 BoolColor(bool flag)
void DrawZ3dkArtifactSummary()
void DrawOptionalBool(const char *label, const std::optional< bool > &flag)
void DrawCheckBadge(const std::string &state)
const char * CheckStr(bool flag)
bool LoadJsonSummaryFile(const std::string &path, Json *out)
std::string CurrentTimestamp()
Editors are the view controllers for the application.
WindowLifecycle
Defines lifecycle behavior for editor windows.
@ CrossEditor
User can pin to persist across editors.
#define REGISTER_PANEL(PanelClass)
Auto-registration macro for panels with default constructors.