6#include "absl/strings/str_format.h"
12#include "imgui/imgui.h"
13#include "imgui/misc/cpp/imgui_stdlib.h"
18constexpr ImVec4
kGreen{0.2f, 0.75f, 0.3f, 1.0f};
19constexpr ImVec4
kRed{0.85f, 0.2f, 0.2f, 1.0f};
20constexpr ImVec4
kYellow{0.85f, 0.75f, 0.1f, 1.0f};
21constexpr ImVec4
kGrey{0.55f, 0.55f, 0.55f, 1.0f};
25const char*
CheckStr(
bool flag) {
return flag ?
"OK" :
"X"; }
29 ImGui::TextColored(
kGreen,
"[ran]");
32 if (state ==
"skipped") {
33 ImGui::TextColored(
kGrey,
"[skipped]");
36 ImGui::TextColored(
kYellow,
"[%s]", state.c_str());
40 ImGui::Text(
" %s", label);
42 if (flag.has_value()) {
46 ImGui::TextColored(
kGrey,
"-");
59 return "Oracle Validation";
90 return "roms/oos168.sfc";
97 if (
pending_.wait_for(std::chrono::milliseconds(0)) !=
98 std::future_status::ready) {
131 Rom* rom_context =
nullptr;
139 pending_ = std::async(std::launch::async,
140 [mode, smoke_opts, preflight_opts, rom_context]() {
150 "dungeon-oracle-preflight", args);
159 absl::StatusCode::kFailedPrecondition;
163 absl::StatusCode::kFailedPrecondition) {
165 std::string(status.message());
181 "oracle-smoke-check", args);
189 absl::StatusCode::kFailedPrecondition;
193 absl::StatusCode::kFailedPrecondition) {
200 result.
smoke = *parsed;
209 ImGui::SeparatorText(
"Options");
211 ImGui::SetNextItemWidth(320.0f);
212 ImGui::InputText(
"ROM Path", &
rom_path_);
214 if (ImGui::SmallButton(
"From ROM")) {
218 ImGui::SetNextItemWidth(80.0f);
224 ImGui::SeparatorText(
"Preflight options");
225 ImGui::SetNextItemWidth(200.0f);
228 ImGui::TextDisabled(
"(e.g. 0x25,0x27)");
232 ImGui::SetNextItemWidth(280.0f);
239 const bool rom_missing =
242 ImGui::BeginDisabled();
245 ImGui::BeginDisabled();
248 if (ImGui::Button(
"Run Structural Smoke")) {
252 if (ImGui::Button(
"Run Strict Readiness")) {
256 if (ImGui::Button(
"Run Oracle Preflight")) {
261 ImGui::EndDisabled();
266 ImGui::EndDisabled();
268 ImGui::TextColored(kRed,
"Load a ROM first");
274 ImGui::TextDisabled(
"No results yet. Run a check above.");
279 const char* mode_label =
283 ?
"Strict Readiness Smoke"
284 :
"Structural Smoke");
285 const bool overall_ok =
286 result.smoke.has_value()
288 : (result.preflight.has_value() && result.preflight->ok);
290 ImGui::TextColored(overall_ok ? kGreen : kRed,
"%s %s",
291 CheckStr(overall_ok), mode_label);
292 ImGui::SameLine(0.0f, 16.0f);
293 ImGui::TextColored(kGrey,
"%s", result.timestamp.c_str());
295 ImGui::SetNextItemWidth(380.0f);
296 ImGui::InputText(
"##cli_cmd",
297 const_cast<char*
>(result.cli_command.c_str()),
298 result.cli_command.size() + 1,
299 ImGuiInputTextFlags_ReadOnly);
301 if (ImGui::SmallButton(
"Copy")) {
302 ImGui::SetClipboardText(result.cli_command.c_str());
305 if (!result.error_message.empty()) {
307 result.error_message.c_str());
309 "Hint: check that the ROM is loaded and the command is available.");
314 if (result.json_parse_failed) {
316 " JSON parse failed - raw output:");
321 if (result.smoke.has_value()) {
324 if (result.preflight.has_value()) {
331 if (ImGui::CollapsingHeader(
"D4 Zora Temple", ImGuiTreeNodeFlags_DefaultOpen)) {
332 ImGui::TextColored(BoolColor(smoke.
d4.
structural_ok),
" Structural %s",
334 ImGui::Text(
" Required rooms check:");
337 DrawOptionalBool(
" Rooms 0x25/0x27 have collision:",
341 if (ImGui::CollapsingHeader(
"D6 Goron Mines", ImGuiTreeNodeFlags_DefaultOpen)) {
343 " Track rooms %d / %d %s",
346 :
"(below threshold)");
347 ImGui::TextColored(BoolColor(smoke.
d6.
ok),
" Audit command %s",
348 CheckStr(smoke.
d6.
ok));
351 if (ImGui::CollapsingHeader(
"D3 Kalyxo Castle", ImGuiTreeNodeFlags_DefaultOpen)) {
352 ImGui::Text(
" Readiness check:");
355 DrawOptionalBool(
" Room 0x32 has collision:", smoke.
d3.
ok);
361 if (ImGui::CollapsingHeader(
"Water Fill", ImGuiTreeNodeFlags_DefaultOpen)) {
363 " Region present %s",
370 if (ImGui::CollapsingHeader(
"Custom Collision",
371 ImGuiTreeNodeFlags_DefaultOpen)) {
375 ImGui::Text(
" Required rooms check:");
378 DrawOptionalBool(
" Required rooms have data:",
382 if (!preflight.
errors.empty()) {
383 const std::string errors_label = absl::StrFormat(
384 "Errors (%d)###preflight_errors", preflight.
error_count);
385 if (ImGui::CollapsingHeader(errors_label.c_str())) {
386 for (
const auto& err : preflight.
errors) {
387 ImGui::TextColored(kRed,
" [%s] %s", err.code.c_str(),
388 err.message.c_str());
389 if (err.room_id.has_value()) {
391 ImGui::TextColored(kGrey,
" room %s", err.room_id->c_str());
400 if (ImGui::CollapsingHeader(
"Raw Output (diagnostics)")) {
401 ImGui::InputTextMultiline(
402 "##raw",
const_cast<char*
>(result.
raw_output.c_str()),
403 result.
raw_output.size() + 1, ImVec2(-1.0f, 120.0f),
404 ImGuiInputTextFlags_ReadOnly);
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status Run(const std::vector< std::string > &args, Rom *rom_context, std::string *captured_output=nullptr)
Execute the command.
void DrawSmokeCards(const oracle_validation::SmokeResult &smoke)
std::string status_message_
void DrawRawOutput(const oracle_validation::OracleRunResult &result)
float GetPreferredWidth() const override
Get preferred width for this panel (optional)
std::future< oracle_validation::OracleRunResult > pending_
std::string GetIcon() const override
Material Design icon for this panel.
std::string required_collision_rooms_
std::string GetId() const override
Unique identifier for this panel.
void Draw(bool *p_open) override
Draw the panel content.
PanelCategory GetPanelCategory() const override
Get the lifecycle category for this panel.
std::optional< oracle_validation::OracleRunResult > last_result_
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
void LaunchRun(oracle_validation::RunMode mode)
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.
ImVec4 BoolColor(bool flag)
void DrawOptionalBool(const char *label, const std::optional< bool > &flag)
void DrawCheckBadge(const std::string &state)
const char * CheckStr(bool flag)
std::vector< std::string > BuildSmokeArgs(const SmokeOptions &opts)
std::vector< std::string > BuildPreflightArgs(const PreflightOptions &opts)
std::string CurrentTimestamp()
std::string BuildCliCommand(const std::string &command_name, const std::vector< std::string > &args)
absl::StatusOr< SmokeResult > ParseSmokeCheckOutput(const std::string &json_str)
absl::StatusOr< PreflightResult > ParsePreflightOutput(const std::string &json_str)
Editors are the view controllers for the application.
PanelCategory
Defines lifecycle behavior for editor panels.
@ CrossEditor
User can pin to persist across editors.
#define REGISTER_PANEL(PanelClass)
Auto-registration macro for panels with default constructors.
std::string error_message
std::optional< SmokeResult > smoke
std::optional< PreflightResult > preflight
absl::StatusCode status_code
std::string required_collision_rooms
std::string required_rooms_check
bool water_fill_region_ok
bool custom_collision_maps_ok
std::optional< bool > required_rooms_ok
std::vector< PreflightError > errors
std::string readiness_check
std::optional< bool > required_rooms_ok
std::string required_rooms_check
bool meets_min_track_rooms