载入中...
搜索中...
未找到
AttackVfxRecipe.cpp
浏览该文件的文档.
18 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unknown attack VFX field"), std::string(path + "." + key)));
25 if (!std::isfinite(*v)) return Result<float>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected finite number"), std::string(path)));
30 return Result<float>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected number"), std::string(path)));
35 if (!std::isfinite(*v)) return Result<double>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected finite number"), std::string(path)));
38 if (const auto* v = value.getIf<std::int64_t>()) return Result<double>::success(static_cast<double>(*v));
39 return Result<double>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected number"), std::string(path)));
43 if (!value.isString()) return Result<LogicalId>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected logical id string"), std::string(path)));
45 if (!parsed) return Result<LogicalId>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("logical id must be namespace:name"), std::string(path)));
54 return Result<AttackVfxVec3>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected three-number array"), std::string(path)));
66 if (!value.isString()) return Result<AttackVfxPhaseKind>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected string"), std::string(path)));
68 if (text == "anticipate") return Result<AttackVfxPhaseKind>::success(AttackVfxPhaseKind::Anticipate);
72 if (text == "aftermath") return Result<AttackVfxPhaseKind>::success(AttackVfxPhaseKind::Aftermath);
74 return Result<AttackVfxPhaseKind>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unknown phase kind"), std::string(path)));
78 if (!value.isString()) return Result<AttackVfxLayerRole>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected string"), std::string(path)));
80 if (text == "blockingMesh") return Result<AttackVfxLayerRole>::success(AttackVfxLayerRole::BlockingMesh);
83 if (text == "particles") return Result<AttackVfxLayerRole>::success(AttackVfxLayerRole::Particles);
85 if (text == "distortion") return Result<AttackVfxLayerRole>::success(AttackVfxLayerRole::Distortion);
89 return Result<AttackVfxLayerRole>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unknown layer role"), std::string(path)));
94 return Result<AttackVfxStopBehavior>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected string"), std::string(path)));
96 if (text == "stopEmitting") return Result<AttackVfxStopBehavior>::success(AttackVfxStopBehavior::StopEmitting);
99 return Result<AttackVfxStopBehavior>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unknown stopBehavior"), std::string(path)));
102Result<AttackVfxSpatialAttachment> parseAttachment(const Value& value, const std::string& path) {
104 return Result<AttackVfxSpatialAttachment>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected string"), std::string(path)));
109 return Result<AttackVfxSpatialAttachment>::success(AttackVfxSpatialAttachment::FollowPositionOnly);
111 return Result<AttackVfxSpatialAttachment>::success(AttackVfxSpatialAttachment::WorldTransformAtStart);
112 return Result<AttackVfxSpatialAttachment>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unknown attachment"), std::string(path)));
117 return Result<AttackVfxSpatialAnchor>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected string"), std::string(path)));
119 if (text == "source") return Result<AttackVfxSpatialAnchor>::success(AttackVfxSpatialAnchor::Source);
120 if (text == "target") return Result<AttackVfxSpatialAnchor>::success(AttackVfxSpatialAnchor::Target);
121 return Result<AttackVfxSpatialAnchor>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unknown anchor"), std::string(path)));
128 if (!object) return Result<AttackVfxSpatial>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
148 return Result<AttackVfxSpatial>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("targetIndex must be >= 0"), std::string(path + ".targetIndex")));
153 return Result<AttackVfxSpatial>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("bone must be a string"), std::string(path + ".bone")));
176Result<std::map<std::string, float>> parseFloatMap(const Value* value, const std::string& path) {
181 return Result<std::map<std::string, float>>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
190Result<std::map<std::string, std::string>> parseStringMap(const Value* value, const std::string& path) {
195 return Result<std::map<std::string, std::string>>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
198 return Result<std::map<std::string, std::string>>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected string"), std::string(path + "." + name)));
206 if (!object) return Result<AttackVfxLayer>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
214 return Result<AttackVfxLayer>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("role is required"), std::string(path + ".role")));
222 return Result<AttackVfxLayer>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("uri must be a string"), std::string(path + ".uri")));
250 if (!object) return Result<AttackVfxPhase>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
252 *object, {"kind", "startCue", "endCue", "startOffsetSeconds", "durationSeconds", "layers"}, path);
258 return Result<AttackVfxPhase>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("kind is required"), std::string(path + ".kind")));
266 return Result<AttackVfxPhase>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("startCue must be a string"), std::string(path + ".startCue")));
271 return Result<AttackVfxPhase>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("endCue must be a string"), std::string(path + ".endCue")));
289 return Result<AttackVfxPhase>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("layers must be an array"), std::string(path + ".layers")));
307 if (!object) return Result<AttackVfxPalette>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
331Result<AttackVfxSkin> parseSkinObject(const Value::Object& object, const std::string& path, bool requireSchema) {
342 return Result<AttackVfxSkin>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("schema must be eve.stylize.attack-vfx-skin"), std::string(path + ".schema")));
345 return Result<AttackVfxSkin>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("schemaVersion is required"), std::string(path + ".schemaVersion")));
348 return Result<AttackVfxSkin>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unsupported skin schemaVersion"), std::string(path + ".schemaVersion")));
354 return Result<AttackVfxSkin>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("id is required"), std::string(path + ".id")));
386 return Result<AttackVfxSkin>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("statusOverlayUri must be a string"), std::string(path + ".statusOverlayUri")));
398 if (!object) return Result<AttackVfxBudget>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("expected object"), std::string(path)));
404 return Result<AttackVfxBudget>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("lod must be >= 0"), std::string(path + ".lod")));
406 return Result<AttackVfxBudget>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("lod exceeds int range"), std::string(path + ".lod")));
412 return Result<AttackVfxBudget>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("maxParticles must be >= 0"), std::string(path + ".maxParticles")));
414 return Result<AttackVfxBudget>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("maxParticles exceeds int range"), std::string(path + ".maxParticles")));
420 return Result<AttackVfxBudget>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("allowDistortion must be boolean"), std::string(path + ".allowDistortion")));
483 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("positionOffset must be finite"), std::string(std::string(path) + ".positionOffset")));
484 if (!finite(rotationOffsetDegrees.x) || !finite(rotationOffsetDegrees.y) || !finite(rotationOffsetDegrees.z))
485 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("rotationOffsetDegrees must be finite"), std::string(std::string(path) + ".rotationOffsetDegrees")));
488 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("scale components must be finite and > 0"), std::string(std::string(path) + ".scale")));
498 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("uri is required for this layer role"), std::string(std::string(path) + ".uri")));
502 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("floatParams values must be finite"), std::string(std::string(path) + ".floatParams")));
509 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("startOffsetSeconds must be finite and >= 0"), std::string(std::string(path) + ".startOffsetSeconds")));
511 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("durationSeconds must be finite and >= 0"), std::string(std::string(path) + ".durationSeconds")));
520 if (!id.isValid()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("skin id is required"), std::string("id")));
523 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("palette channel must be in [0,1]"), std::string(path)));
532 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("shakeProfile values must be finite"), std::string("shakeProfile")));
537 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("distortionProfile values must be finite"), std::string("distortionProfile")));
543 if (!id.isValid()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("recipe id is required"), std::string("id")));
544 if (phases.empty()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("recipe requires at least one phase"), std::string("phases")));
545 if (budget.lod < 0) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("lod must be >= 0"), std::string("budget.lod")));
547 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("maxParticles must be >= 0"), std::string("budget.maxParticles")));
556 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("inline skin.id must match skinId"), std::string("skin.id")));
565 if (!object) return Result<AttackVfxSkin>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("skin must be an object"), std::string("")));
574 if (!object) return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("recipe must be an object"), std::string("")));
576 auto known = rejectUnknown(*object, {"schema", "schemaVersion", "id", "phases", "skinId", "skin", "budget"}, "");
581 if (schema == object->end() || !schema->second.isString() || schema->second.asString() != schemaId)
582 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("schema must be eve.stylize.attack-vfx"), std::string("schema")));
585 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("schemaVersion is required"), std::string("schemaVersion")));
588 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("unsupported schemaVersion"), std::string("schemaVersion")));
593 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("id is required"), std::string("id")));
601 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("phases is required"), std::string("phases")));
604 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("phases must be an array"), std::string("phases")));
622 return Result<AttackVfxRecipe>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, std::string("skin must be an object"), std::string("skin")));
655 object.emplace("attachment", Value(std::string(attackVfxSpatialAttachmentName(spatial.attachment))));
667 for (const auto& [name, value] : values) object.emplace(name, Value(static_cast<double>(value)));
682 if (!layer.floatParams.empty()) object.emplace("floatParams", Value(encodeFloatMap(layer.floatParams)));
683 object.emplace("stopBehavior", Value(std::string(attackVfxStopBehaviorName(layer.stopBehavior))));
713 if (!skin.styleHints.empty()) object.emplace("styleHints", Value(encodeStringMap(skin.styleHints)));
714 if (!skin.shakeProfile.empty()) object.emplace("shakeProfile", Value(encodeFloatMap(skin.shakeProfile)));
717 if (!skin.statusOverlayUri.empty()) object.emplace("statusOverlayUri", Value(skin.statusOverlayUri));
Data-driven layered attack VFX recipe and element skin (Phase 1 schema).
Owning, renderer-independent dynamic values.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
static std::optional< LogicalId > parse(std::string_view text)
Parses a scoped logical name.
Definition Identity.cpp:36
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Result< std::string > toJson() const
Serialize this value as deterministic compact JSON.
Definition Value.cpp:67
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
Result< std::uint64_t > reload(std::string_view json)
Parse and atomically replace the recipe on success.
Definition AttackVfxRecipe.cpp:752
AttackVfxRecipeSlot(AttackVfxRecipe recipe)
Construct a slot from an already validated recipe.
Definition AttackVfxRecipe.cpp:750
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
Definition MeshVfxPackage.h:10
AttackVfxLayerRole
Which existing presentation backend a layer binds to.
Definition AttackVfxRecipe.h:40
@ BlockingMesh
@ Particles
@ Distortion
AttackVfxSpatialAttachment
How a layer follows its resolved spatial anchor.
Definition AttackVfxRecipe.h:59
@ FollowTarget
@ WorldTransformAtStart
@ FollowPositionOnly
AttackVfxPhaseKind
Attack presentation phase along the cast → hit → linger timeline.
Definition AttackVfxRecipe.h:30
@ Anticipate
@ Aftermath
std::string_view attackVfxSpatialAnchorName(AttackVfxSpatialAnchor anchor) noexcept
Stable JSON spelling for spatial anchor.
Definition AttackVfxRecipe.cpp:472
@ ClearImmediately
@ StopEmitting
std::string_view attackVfxSpatialAttachmentName(AttackVfxSpatialAttachment mode) noexcept
Stable JSON spelling for spatial attachment.
Definition AttackVfxRecipe.cpp:463
AttackVfxSpatialAnchor
Which request endpoint supplies the spatial anchor.
Definition AttackVfxRecipe.h:66
std::string_view attackVfxPhaseKindName(AttackVfxPhaseKind kind) noexcept
Stable JSON spelling for a phase kind.
Definition AttackVfxRecipe.cpp:428
std::string_view attackVfxLayerRoleName(AttackVfxLayerRole role) noexcept
Stable JSON spelling for a layer role.
Definition AttackVfxRecipe.cpp:440
std::string_view attackVfxStopBehaviorName(AttackVfxStopBehavior behavior) noexcept
Stable JSON spelling for stop behavior.
Definition AttackVfxRecipe.cpp:455
@ InvalidArgument
Definition Container.h:602
std::size_t targetIndex
Definition ActionSpatialBlock.h:50
ActionSpatialVector3 scale
Definition ActionSpatialBlock.h:54
ActionSpatialVector3 positionOffset
Definition ActionSpatialBlock.h:52
ActionSpatialVector3 rotationOffsetDegrees
Definition ActionSpatialBlock.h:53
std::map< std::string, float > floatParams
Definition AttackVfxRecipe.h:110
Result< void > validate(std::string_view path) const
Validate role/uri/spatial/parameter invariants.
Definition AttackVfxRecipe.cpp:492
double startOffsetSeconds
Definition AttackVfxRecipe.h:128
std::vector< AttackVfxLayer > layers
Definition AttackVfxRecipe.h:130
Result< void > validate(std::string_view path) const
Validate cues, timing, and nested layers.
Definition AttackVfxRecipe.cpp:507
Versioned attack VFX composition recipe.
Definition AttackVfxRecipe.h:189
Result< std::string > toJson() const
Serialize this recipe in canonical current-schema JSON form.
Definition AttackVfxRecipe.cpp:729
static Result< AttackVfxRecipe > fromJson(std::string_view json)
Parse, validate, and return a complete recipe without mutating live state.
Definition AttackVfxRecipe.cpp:569
std::optional< LogicalId > skinId
Definition AttackVfxRecipe.h:195
Result< void > validate() const
Validate id, phases, optional skin, and budget invariants.
Definition AttackVfxRecipe.cpp:542
static constexpr std::string_view schemaId
Definition AttackVfxRecipe.h:190
static constexpr std::uint32_t schemaVersion
Definition AttackVfxRecipe.h:191
std::optional< AttackVfxSkin > skin
Definition AttackVfxRecipe.h:196
std::vector< AttackVfxPhase > phases
Definition AttackVfxRecipe.h:194
Result< void > validate() const
Validate id, palette range, and finite profile values.
Definition AttackVfxRecipe.cpp:519
static Result< AttackVfxSkin > fromJson(std::string_view json)
Parse a standalone skin document.
Definition AttackVfxRecipe.cpp:561
std::map< std::string, float > distortionProfile
Definition AttackVfxRecipe.h:157
Result< std::string > toJson() const
Serialize in canonical current-schema JSON.
Definition AttackVfxRecipe.cpp:723
std::map< std::string, float > shakeProfile
Definition AttackVfxRecipe.h:156
Result< void > validate(std::string_view path) const
Validate finite offsets and strictly positive scale.
Definition AttackVfxRecipe.cpp:480
AttackVfxVec3 rotationOffsetDegrees
Definition AttackVfxRecipe.h:90
AttackVfxVec3 positionOffset
Definition AttackVfxRecipe.h:89
Owning three-component float used at the recipe boundary.
Definition AttackVfxRecipe.h:69