载入中...
搜索中...
未找到
WorldSnapshot.cpp
浏览该文件的文档.
86 static eve::Result<void> finishPrepared(World3D& world, int nextBodyId, int nextShapeId, int nextJointId,
108bool hasExactFields(const eve::Value::Object& object, std::initializer_list<std::string_view> expected) {
137 eve::DiagnosticCode::ParseError, "snapshot integer is not a uint64 decimal string", std::string(name)));
149 eve::DiagnosticCode::ParseError, "snapshot integer is not an int64 decimal string", std::string(name)));
158 const double result = value->isDouble() ? value->asDouble() : static_cast<double>(value->asInt());
161 eve::DiagnosticCode::InvalidArgument, "snapshot numeric field must be finite", std::string(name)));
168 if (number.value() < -std::numeric_limits<float>::max() || number.value() > std::numeric_limits<float>::max())
170 eve::DiagnosticCode::InvalidArgument, "snapshot numeric field is outside float range", std::string(name)));
186 eve::DiagnosticCode::InvariantViolation, "physics snapshot schema constant is invalid", "schema"));
190eve::Result<void> checkEnvelope(const eve::SnapshotEnvelope& snapshot, std::string_view type, std::string_view schema) {
218 if (duration.value() < 0 || revision.value() != stepCount.value() || tick.value() != snapshot.tick.value() ||
231 auto valid = detail::validateSimulationObservation(result.value, "physics.snapshot.observation");
255bool validBodyType(const std::string& type) { return type == "static" || type == "kinematic" || type == "dynamic"; }
259 if (!object || !hasExactFields(*object, {"active", "angle", "awake", "bullet", "fixedRotation", "fixtures", "id", "type", "vx",
268 eve::DiagnosticCode::ParseError, "2D physics snapshot body id is invalid", "payload.bodies.id"));
273 eve::DiagnosticCode::InvalidArgument, "2D physics snapshot body type is invalid", "payload.bodies.type"));
307 return eve::Result<Body2DState>::failure(eve::Diagnostic::error(eve::DiagnosticCode::ParseError,
316 if (!object || !hasExactFields(*object, {"active", "awake", "bullet", "fixedRotation", "id", "type", "x", "y", "z",
325 eve::DiagnosticCode::ParseError, "3D physics snapshot body id is invalid", "payload.bodies.id"));
330 eve::DiagnosticCode::InvalidArgument, "3D physics snapshot body type is invalid", "payload.bodies.type"));
356 return eve::Result<Body3DState>::failure(eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument,
503eve::Value::Object observationFields(const SimulationObservation& observation, eve::SimulationTick tick) {
508 object.emplace("simulatedDurationNs", eve::Value(std::to_string(observation.simulatedDuration.nanoseconds())));
559 eve::DiagnosticCode::Conflict, "physics snapshot contains a duplicate body id", "payload.bodies.id"));
569 eve::DiagnosticCode::ParseError, "physics snapshot bodies must be an array", "payload.bodies"));
585 eve::DiagnosticCode::ParseError, "physics snapshot bodies must be an array", "payload.bodies"));
631 values.push_back(static_cast<float>(component.isDouble() ? component.asDouble() : component.asInt()) * meter);
667eve::Result<std::vector<float>> readFloatArray(const eve::Value::Object& object, std::string_view name) {
684eve::Result<std::vector<std::int32_t>> readIntArray(const eve::Value::Object& object, std::string_view name) {
694 eve::DiagnosticCode::ParseError, "snapshot integer array item must be a string", std::string(name)));
698 if (ec != std::errc{} || end != text.data() + text.size() || parsed < INT32_MIN || parsed > INT32_MAX)
713 auto prepared = WorldSnapshotAccess::makeDetachedWorld3D(gravityX, gravityY, gravityZ, instanceId);
739 auto a = readFloat(*object, "a"); auto b = readFloat(*object, "b"); auto c = readFloat(*object, "c");
744 eve::DiagnosticCode::Conflict, "3D shape references invalid identity or source", "payload.shapes"));
747 if (kind.value() == "box") shape = body->newBoxShape(a.value() * 2.f, b.value() * 2.f, c.value() * 2.f);
751 auto vertices = readFloatArray(*object, "hullVertices"); auto maxVertices = readInt64(*object, "hullMaxVertices");
757 auto vertices = readFloatArray(*object, "meshVertices"); auto indices = readIntArray(*object, "meshIndices");
758 auto weld = readBool(*object, "meshWeldVertices"); auto tolerance = readFloat(*object, "meshWeldTolerance");
759 auto edges = readBool(*object, "meshIdentifyEdges"); auto median = readBool(*object, "meshUseMedianSplit");
763 shape = body->newTriangleMeshShape(vertices.value(), indices.value(), weld.value(), tolerance.value(), edges.value(), median.value());
765 auto heights = readFloatArray(*object, "heightValues"); auto cx = readInt64(*object, "heightCountX"); auto cz = readInt64(*object, "heightCountZ");
766 auto sx = readFloat(*object, "heightCellSizeX"); auto sz = readFloat(*object, "heightCellSizeZ"); auto mn = readFloat(*object, "heightGlobalMin"); auto mx = readFloat(*object, "heightGlobalMax"); auto clockwise = readBool(*object, "heightClockwise");
770 shape = body->newHeightFieldShape(static_cast<int>(cx.value()), static_cast<int>(cz.value()), sx.value(), sz.value(), heights.value(), mn.value(), mx.value(), clockwise.value());
774 eve::DiagnosticCode::Unsupported, "3D shape kind cannot be reconstructed", "payload.shapes.kind"));
788 if (!bodyAId || !bodyBId || !id || id.value() <= 0 || id.value() > std::numeric_limits<int>::max() ||
789 !jointIds.insert(static_cast<int>(id.value())).second || !kind || !frames || frames.value().size() != 14 ||
790 !bodyById.contains(static_cast<int>(bodyAId.value())) || !bodyById.contains(static_cast<int>(bodyBId.value())))
792 eve::DiagnosticCode::Conflict, "3D joint references invalid bodies or frames", "payload.joints"));
793 Body3D* aBody = bodyById.at(static_cast<int>(bodyAId.value())); Body3D* bBody = bodyById.at(static_cast<int>(bodyBId.value()));
801 joint = prepared->newDistanceJoint(aBody, bBody, anchorA.x, anchorA.y, anchorA.z, anchorB.x, anchorB.y, anchorB.z, length);
804 joint = prepared->newRevoluteJoint(aBody, bBody, anchorA.x, anchorA.y, anchorA.z, axis.x, axis.y, axis.z);
807 joint = prepared->newPrismaticJoint(aBody, bBody, anchorA.x, anchorA.y, anchorA.z, axis.x, axis.y, axis.z);
810 joint = prepared->newSphericalJoint(aBody, bBody, anchorA.x, anchorA.y, anchorA.z, axis.x, axis.y, axis.z);
812 const b3Vec3 suspension = b3Body_GetWorldVector(aBody->raw(), b3RotateVector(qa, b3Vec3_axisX));
814 joint = prepared->newWheelJoint(aBody, bBody, anchorA.x, anchorA.y, anchorA.z, suspension.x, suspension.y, suspension.z, wheel.x, wheel.y, wheel.z);
827 eve::DiagnosticCode::Unsupported, "3D joint kind cannot be reconstructed", "payload.joints.kind"));
844eve::Result<eve::SnapshotEnvelope> World::snapshot(const eve::SnapshotHashProvider& hashProvider) const {
847 eve::DiagnosticCode::PreconditionViolation, "Cannot snapshot a destroyed or uninitialized physics world",
863 eve::DiagnosticCode::PreconditionViolation, "Cannot restore a destroyed or uninitialized physics world",
880 eve::DiagnosticCode::ParseError, "v1 physics snapshot bodies are malformed", "payload.bodies"));
888 for (Body* candidate : bodies_) if (candidate && id && candidate->getId() == static_cast<int>(id.value())) live = candidate;
897 if (!object || !hasExactFields(*object, {"bodies", "gravityX", "gravityY", "meter", "tick", "revision", "stepCount",
900 eve::DiagnosticCode::ParseError, "2D physics snapshot payload has unknown or missing fields", "payload"));
913 eve::DiagnosticCode::InvalidArgument, "physics snapshot meter must be positive", "payload.meter"));
929eve::Result<eve::SnapshotEnvelope> World3D::snapshot(const eve::SnapshotHashProvider& hashProvider) const {
932 eve::DiagnosticCode::PreconditionViolation, "Cannot snapshot a destroyed or uninitialized 3D physics world",
949 eve::DiagnosticCode::PreconditionViolation, "Cannot restore a destroyed or uninitialized 3D physics world",
966 migrated->emplace("shapes", shapesTopologyValue(std::vector<Shape3D*>(shapes_.begin(), shapes_.end())));
967 migrated->emplace("joints", jointsTopologyValue(std::vector<Joint3D*>(joints_.begin(), joints_.end())));
975 if (!object || !hasExactFields(*object, {"bodies", "gravityX", "gravityY", "gravityZ", "joints", "shapes", "tick", "revision",
978 eve::DiagnosticCode::ParseError, "3D physics snapshot payload has unknown or missing fields", "payload"));
991 if (!snapshotShapes || !snapshotShapes->isArray() || !snapshotJoints || !snapshotJoints->isArray())
993 eve::DiagnosticCode::ParseError, "3D physics snapshot topology fields must be arrays", "payload.shapes"));
1017 eve::DiagnosticCode::InvariantViolation, "2D physics body handle space cannot represent restored links",
1028 const auto bodyAvailable = static_cast<std::uint64_t>(PhysicsBodyHandle::invalidIndex) - nextBodyHandleIndex_;
1029 const auto shapeAvailable = static_cast<std::uint64_t>(PhysicsShapeHandle::invalidIndex) - nextShapeHandleIndex_;
1030 const auto jointAvailable = static_cast<std::uint64_t>(PhysicsJointHandle::invalidIndex) - nextJointHandleIndex_;
1031 if (bodies_.size() > bodyAvailable || shapes_.size() > shapeAvailable || joints_.size() > jointAvailable)
1033 eve::DiagnosticCode::InvariantViolation, "3D physics handle space cannot represent restored links",
Backend-neutral, observable fixed-step contract for physics domains.
#define EV_READ_BODY3D_BOOL(name)
#define EV_READ_BODY3D_FLOAT(name)
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 constexpr Duration fromNanoseconds(std::int64_t nanoseconds) noexcept
Construct an exact duration from nanoseconds.
Definition Time.h:55
const std::string & format() const noexcept
Returns the canonical namespace:name representation.
Definition Identity.h:436
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
static constexpr index_type invalidIndex
Reserved index value shared by all invalid handles.
Definition RuntimeHandle.h:124
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
const T * getIf() const noexcept
Return a typed pointer, or nullptr when the kind differs.
Definition Value.h:180
constexpr bool isNil() const noexcept
Returns whether this value is the all-zero nil ID.
Definition Identity.h:176
constexpr std::uint64_t value() const noexcept
Returns the underlying value at an explicit protocol boundary.
Definition StrongUint64.h:26
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create pr...
Definition Body3D.h:24
2D rigid body (Box2D) in pixel-space coordinates. Owned by a World; create shapes with newRectangleFi...
Definition Body.h:21
3D shape (box/sphere/capsule) attached to a Body3D with material settings. Created via Body3D::new*Sh...
Definition Shape3D.h:25
Box3D rigid-body world. Script coordinates are meters (Box3D native), unlike 2D World which uses pixe...
Definition World3D.h:63
PhysicsJointHandle nextJointRuntimeHandle()
Internal: next generation-qualified joint handle.
Definition World3D.cpp:896
SimulationObservation simulationObservation() const noexcept
Snapshot of completed backend steps and logical simulation time.
Definition World3D.cpp:761
eve::Result< eve::SnapshotEnvelope > snapshot(const eve::SnapshotHashProvider &hashProvider) const
Captures a versioned, integrity-checked 3D world snapshot.
Definition WorldSnapshot.cpp:929
eve::Result< void > restore(const eve::SnapshotEnvelope &snapshot, const eve::SnapshotHashProvider &hashProvider)
Restores a verified snapshot without exposing partial state.
Definition WorldSnapshot.cpp:945
PhysicsBodyHandle nextBodyRuntimeHandle()
Internal: next generation-qualified body handle.
Definition World3D.cpp:884
eve::SimulationTick simulationTick() const noexcept
Current deterministic tick; save data should persist this value.
Definition World3D.h:139
void clearContactEvents()
Clears all contact and trigger buffers before the next step.
Definition World3D.cpp:1086
PhysicsShapeHandle nextShapeRuntimeHandle()
Internal: next generation-qualified shape handle.
Definition World3D.cpp:890
Box2D world wrapper (2D physics) with pixel-space coordinates. Handles stepping, gravity,...
Definition World.h:41
SimulationObservation simulationObservation() const noexcept
Snapshot of completed backend steps and logical simulation time.
Definition World.cpp:385
eve::SimulationTick simulationTick() const noexcept
Current deterministic tick; save data should persist this value.
Definition World.h:109
eve::Result< void > restore(const eve::SnapshotEnvelope &snapshot, const eve::SnapshotHashProvider &hashProvider)
Restores a verified snapshot without exposing partial state.
Definition WorldSnapshot.cpp:859
PhysicsBodyHandle nextBodyRuntimeHandle()
Definition World.cpp:425
void clearContactEvents()
Clears collected begin/end contact and impact event buffers.
Definition World.cpp:643
eve::Result< eve::SnapshotEnvelope > snapshot(const eve::SnapshotHashProvider &hashProvider) const
Captures a versioned, integrity-checked world snapshot.
Definition WorldSnapshot.cpp:844
Result< float > readFloat(const Accessor &accessor, std::uint32_t element, std::uint32_t component)
Read one bounded finite FLOAT component.
Definition GltfDecode.cpp:221
bool readString(const eve::Value::Object &object, const char *name, std::string &output)
Definition ArtifactProvider.cpp:20
const EditorValue * field(const EditorValue &value, const char *name)
Definition RoadNetworkEditTarget.cpp:15
bool readNumber(const EditorValue &value, const char *name, float &output)
Definition RoadNetworkEditTarget.cpp:30
@ InvalidArgument
@ UnknownVersion
@ PreconditionViolation
@ Unsupported
@ InvariantViolation
@ Failed
@ ParseError
@ Conflict
@ Applied
detail::StrongUint64< detail::SimulationTickTag > SimulationTick
Deterministic simulation time step; it is not wall-clock time.
Definition Time.h:31
Result< SnapshotEnvelope > makeSnapshotEnvelope(std::string type, LogicalId schema, SchemaVersion schemaVersion, PersistentId instanceId, Revision revision, SimulationTick tick, Value payload, const SnapshotHashProvider &hashProvider)
Construct and seal a snapshot envelope.
Definition Snapshot.cpp:103
Result< void > verifySnapshotEnvelope(const SnapshotEnvelope &snapshot, const SnapshotHashProvider &hashProvider)
Verify an envelope's content hash without modifying it.
Definition Snapshot.cpp:63
std::function< Result< ContentId >(std::string_view canonicalInput)> SnapshotHashProvider
Injected content-digest implementation used by snapshots.
Definition Snapshot.h:36
Stable outer format shared by persistence and cross-process snapshots.
Definition Snapshot.h:46
Observable backend progress shared by CPU and accelerator providers.
Definition SimulationBackend.h:136
eve::SimulationTick lastTick
Tick of the most recently completed step.
Definition SimulationBackend.h:140
static void setJointId(Joint3D &joint, int id)
Definition WorldSnapshot.cpp:73
static std::unique_ptr< World3D > makeDetachedWorld3D(float gx, float gy, float gz, eve::PersistentId instanceId)
Definition WorldSnapshot.cpp:74
static void setShapeId(Shape3D &shape, int id)
Definition WorldSnapshot.cpp:72
static void setBodyId(Body3D &body, int id)
Definition WorldSnapshot.cpp:71
static eve::Result< void > finishPrepared(World3D &world, int nextBodyId, int nextShapeId, int nextJointId, const SimulationObservation &observation)
Definition WorldSnapshot.cpp:86
static eve::Result< void > finishPrepared(World &world, int nextId, const SimulationObservation &observation)
Definition WorldSnapshot.cpp:78
static eve::Value shapeSource(const Shape3D &shape)
Definition WorldSnapshot.cpp:30
static void adopt(World3D &live, World3D &prepared)
Definition WorldSnapshot.cpp:98
static void adopt(World &live, World &prepared)
Definition WorldSnapshot.cpp:97
static void setBodyId(Body &body, int id)
Definition WorldSnapshot.cpp:70