Files
EVEngine/test/rpg_reload.cpp
T
西风逍遥游 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

70 lines
2.0 KiB
C++

#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include "common/StateValue.h"
#include "rpg/RPGActor.h"
#include "rpg/RpgState.h"
#include "rpg/Skill.h"
#include "rpg/SkillSystem.h"
#include <string>
using namespace eve::rpg;
TEST_CASE("rpg.state.captureRestoreCastingAndCooldown") {
SkillRegistry::clear();
RPGActor* actor = RPGActor::createActor();
SkillDefinition def;
def.id = "fireball";
def.castTime = 1.5f;
SkillRegistry::registerSkill(def);
actor->learnSkill("fireball");
actor->setSkillCooldown("fireball", 2.5f);
CHECK(eve::rpg::SkillSystem::beginCast(actor, "fireball"));
CHECK(eve::rpg::SkillSystem::isCasting(actor));
eve::StateValue captured;
REQUIRE(eve::rpg::captureRpgState(captured));
// Mutate everything, then restore.
eve::rpg::SkillSystem::cancelCast(actor);
actor->setSkillCooldown("fireball", 0.f);
CHECK(!eve::rpg::SkillSystem::isCasting(actor));
std::string err;
CHECK(eve::rpg::restoreRpgState(captured, &err));
CHECK(err.empty());
CHECK(eve::rpg::SkillSystem::isCasting(actor));
CHECK_EQ(eve::rpg::SkillSystem::getCastingSkillId(actor), std::string("fireball"));
CHECK(eve::rpg::SkillSystem::getCooldownRemaining(actor, "fireball") == 2.5f);
actor->release();
SkillRegistry::clear();
}
TEST_CASE("rpg.state.resetCancelsCasting") {
SkillRegistry::clear();
RPGActor* actor = RPGActor::createActor();
SkillDefinition def;
def.id = "channel";
def.castTime = 1.f;
SkillRegistry::registerSkill(def);
actor->learnSkill("channel");
CHECK(eve::rpg::SkillSystem::beginCast(actor, "channel"));
CHECK(eve::rpg::SkillSystem::isCasting(actor));
CHECK(eve::rpg::resetRpgState());
CHECK(!eve::rpg::SkillSystem::isCasting(actor));
actor->release();
SkillRegistry::clear();
}
TEST_CASE("rpg.state.restoreRejectsMalformed") {
std::string err;
CHECK(!eve::rpg::restoreRpgState(eve::StateValue::object(), &err));
CHECK(!err.empty());
}