Files
EVEngine/test/card_reload.cpp
西风逍遥游 54dea0d561 feat: state hot reload for scripts and state machines
Adds a capture -> reload -> restore pipeline so code/asset changes can be hot-applied without resetting running state:

- common: StateValue (JSON-compatible state tree) + IStateProvider capability interface.
- devtools: Snapshot v2 (script roots + native provider section, v1 compatible, strict rejection of non-data roots), ReloadSession (begin/commit/abort), eve.dev script API (stateRoots / beginStateReload / commitStateReload / abortStateReload).
- load.nut: three-phase soft reload (capture -> dofile -> restore) with migrate_instance / remap_instances helpers and eve_before_reload / eve_after_reload hooks.
- dialogue + AnimStateMachine: IStateProvider for phase/vars/rng and params/current state.
- animation: AnimClip::adopt + AnimClipRegistry + 'animclip' IAssetReloader so .eva content reloads keep clip identity.
- rpg + card: IStateProvider for casting/cooldowns and card phases.
- Tests: stateValue, snapshot v2/strict, reload script protocol, dialogue, animation state machine + reload, rpg/card state roundtrips.
2026-08-21 19:46:25 +08:00

57 lines
1.8 KiB
C++

#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include "card/Card.h"
#include "card/CardState.h"
#include "common/StateValue.h"
#include <string>
namespace {
const char* kDefs = R"JSON(
[{"id":"flame","name":"Flame","kind":"creature","cost":2,"attack":3,"health":2},
{"id":"bolt","name":"Bolt","kind":"spell","cost":3}]
)JSON";
} // namespace
TEST_CASE("card.state.captureRestorePhases") {
eve::card::Card mod;
mod.registerCardsFromJson(kDefs);
eve::card::CardData* a = mod.newCard("flame");
eve::card::CardData* b = mod.newCard("bolt");
REQUIRE(a != nullptr);
REQUIRE(b != nullptr);
a->state()->phase = eve::card::CardState::Played;
b->state()->phase = eve::card::CardState::Disabled;
b->state()->dragging = true; // transient interaction, dropped on restore
eve::StateValue captured;
REQUIRE(eve::card::captureCardState(captured));
a->state()->phase = eve::card::CardState::Deck;
b->state()->phase = eve::card::CardState::Hand;
std::string err;
CHECK(eve::card::restoreCardState(captured, &err));
CHECK(err.empty());
CHECK(static_cast<int>(a->state()->phase) == static_cast<int>(eve::card::CardState::Played));
CHECK(static_cast<int>(b->state()->phase) == static_cast<int>(eve::card::CardState::Disabled));
CHECK(!b->state()->dragging);
// Reset returns everything to the deck.
CHECK(eve::card::resetCardState());
CHECK(static_cast<int>(a->state()->phase) == static_cast<int>(eve::card::CardState::Deck));
CHECK(static_cast<int>(b->state()->phase) == static_cast<int>(eve::card::CardState::Deck));
a->release();
b->release();
}
TEST_CASE("card.state.restoreRejectsMalformed") {
std::string err;
CHECK(!eve::card::restoreCardState(eve::StateValue::object(), &err));
CHECK(!err.empty());
}