38b62cd2e8
- StateGraph: checkpoint now saves next node (prevents re-execution on resume) - Engine: pre-build node_map dict (O(1) lookup, was O(N²)) - Reranker: replace deprecated asyncio.get_event_loop() with get_running_loop() - Executor: use collections.deque for O(1) popleft (was list.pop(0)) - Dashboard: increase SSH timeouts (8s connect, 15s total), fold long columns, add macOS RAM detection, wider console (160 cols min) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
119 lines
4.6 KiB
C++
119 lines
4.6 KiB
C++
// scenario_manager.h - Story runtime wrapper for Freenove all-in-one.
|
|
#pragma once
|
|
|
|
#include <Arduino.h>
|
|
#include <ArduinoJson.h>
|
|
|
|
#include "core/scenario_def.h"
|
|
|
|
struct ScenarioSnapshot {
|
|
const ScenarioDef* scenario = nullptr;
|
|
const StepDef* step = nullptr;
|
|
const char* screen_scene_id = nullptr;
|
|
const char* audio_pack_id = nullptr;
|
|
const char* const* action_ids = nullptr;
|
|
uint8_t action_count = 0U;
|
|
bool mp3_gate_open = false;
|
|
};
|
|
|
|
struct Runtime3ArtifactInfo {
|
|
bool discovered = false;
|
|
bool loaded = false;
|
|
size_t size_bytes = 0U;
|
|
uint32_t scenario_version = 0U;
|
|
uint16_t step_count = 0U;
|
|
uint16_t transition_count = 0U;
|
|
String path;
|
|
String schema_version;
|
|
String scenario_id;
|
|
String entry_step_id;
|
|
String source_kind;
|
|
String generated_by;
|
|
String migration_mode;
|
|
String error;
|
|
};
|
|
|
|
class ScenarioManager {
|
|
public:
|
|
static const char* readScenarioField(JsonVariantConst root,
|
|
const char* const* candidates,
|
|
size_t candidate_count);
|
|
|
|
bool begin(const char* scenario_file_path);
|
|
bool beginById(const char* scenario_id);
|
|
void reset();
|
|
void tick(uint32_t now_ms);
|
|
|
|
void notifyUnlock(uint32_t now_ms);
|
|
bool notifyUnlockEvent(const char* event_name, uint32_t now_ms);
|
|
void notifyButton(uint8_t key, bool long_press, uint32_t now_ms);
|
|
void notifyAudioDone(uint32_t now_ms);
|
|
bool notifyButtonEvent(const char* event_name, uint32_t now_ms);
|
|
bool notifyEspNowEvent(const char* event_name, uint32_t now_ms);
|
|
bool notifySerialEvent(const char* event_name, uint32_t now_ms);
|
|
bool notifyTimerEvent(const char* event_name, uint32_t now_ms);
|
|
bool notifyActionEvent(const char* event_name, uint32_t now_ms);
|
|
bool notifyVoiceEvent(const char* event_name, uint32_t now_ms);
|
|
bool gotoScene(const char* scene_id, uint32_t now_ms, const char* source);
|
|
|
|
ScenarioSnapshot snapshot() const;
|
|
const Runtime3ArtifactInfo& runtime3Artifact() const;
|
|
bool consumeSceneChanged();
|
|
bool consumeAudioRequest(String* out_audio_pack_id);
|
|
uint32_t transitionEventMask() const;
|
|
void setDebugTransitionBypassEnabled(bool enabled, const char* source);
|
|
bool debugTransitionBypassEnabled() const;
|
|
|
|
private:
|
|
struct StepResourceOverride {
|
|
String step_id;
|
|
String screen_scene_id;
|
|
String audio_pack_id;
|
|
static constexpr uint8_t kMaxActionOverrides = 8U;
|
|
String action_ids[kMaxActionOverrides];
|
|
const char* action_ptrs[kMaxActionOverrides] = {nullptr};
|
|
uint8_t action_count = 0U;
|
|
};
|
|
|
|
static constexpr uint8_t kMaxStepResourceOverrides = 24U;
|
|
|
|
void clearStepResourceOverrides();
|
|
void clearRuntime3ArtifactInfo();
|
|
void loadRuntime3ArtifactInfo(const char* scenario_file_path, const char* scenario_id);
|
|
void loadStepResourceOverrides(const char* scenario_file_path);
|
|
const StepResourceOverride* findStepResourceOverride(const char* step_id) const;
|
|
void applyStepResourceOverride(const StepDef* step,
|
|
const char** out_screen_scene_id,
|
|
const char** out_audio_pack_id,
|
|
const char* const** out_action_ids = nullptr,
|
|
uint8_t* out_action_count = nullptr) const;
|
|
|
|
bool dispatchEvent(StoryEventType type, const char* event_name, uint32_t now_ms, const char* source);
|
|
bool applyTransition(const TransitionDef& transition, uint32_t now_ms, const char* source, const char* event_name);
|
|
bool runImmediateTransitions(uint32_t now_ms, const char* source, const char* parent_event_name);
|
|
void evaluateAfterMsTransitions(uint32_t now_ms);
|
|
void enterStep(int8_t step_index, uint32_t now_ms, const char* source, const char* event_name = nullptr);
|
|
const StepDef* currentStep() const;
|
|
bool transitionMatches(const TransitionDef& transition, StoryEventType type, const char* event_name) const;
|
|
bool isTransitionAllowed(const TransitionDef& transition, const char* context, const char* event_name) const;
|
|
|
|
const ScenarioDef* scenario_ = nullptr;
|
|
int8_t current_step_index_ = -1;
|
|
uint32_t step_entered_at_ms_ = 0U;
|
|
bool scene_changed_ = false;
|
|
bool test_mode_ = false;
|
|
bool timer_armed_ = false;
|
|
bool timer_fired_ = false;
|
|
uint32_t etape2_due_at_ms_ = 0U;
|
|
bool win_due_armed_ = false;
|
|
bool win_due_fired_ = false;
|
|
uint32_t win_due_at_ms_ = 0U;
|
|
bool debug_transition_bypass_enabled_ = false;
|
|
String pending_audio_pack_;
|
|
String forced_screen_scene_id_;
|
|
String initial_step_override_;
|
|
StepResourceOverride step_resource_overrides_[kMaxStepResourceOverrides];
|
|
uint8_t step_resource_override_count_ = 0U;
|
|
Runtime3ArtifactInfo runtime3_artifact_;
|
|
};
|