载入中...
搜索中...
未找到
VehicleDefinitionRuntime.cpp
浏览该文件的文档.
2
3#include "common/Value.h"
4#include "vehicle/Vehicle.h"
5
6#include <algorithm>
7#include <cmath>
8#include <cstdint>
9#include <limits>
10#include <set>
11#include <stdexcept>
12#include <utility>
13
14namespace eve::vehicle {
15namespace {
16
17eve::LogicalId vehicleSchema() {
18 static const eve::LogicalId value = [] {
19 const auto parsed = eve::LogicalId::parse("vehicle:runtime");
20 if (!parsed) throw std::logic_error("invalid built-in vehicle snapshot schema");
21 return *parsed;
22 }();
23 return value;
24}
25
28 const auto& logical = reference.id();
29 return registry.handle(std::string(logical.namespaceName()), std::string(logical.name()));
30}
31
32const eve::Value* field(const eve::Value::Object& object, std::string_view name) {
33 const auto it = object.find(std::string(name));
34 return it == object.end() ? nullptr : &it->second;
35}
36
37bool readString(const eve::Value::Object& object, std::string_view name, std::string& result, bool required = false) {
38 const auto* value = field(object, name);
39 if (value == nullptr) return !required;
40 const auto* text = value->getIf<std::string>();
41 if (text == nullptr || (required && text->empty())) return false;
42 result = *text;
43 return true;
44}
45
46bool readNumber(const eve::Value::Object& object, std::string_view name, float& result, float fallback) {
47 const auto* value = field(object, name);
48 if (value == nullptr) {
49 result = fallback;
50 return true;
51 }
52 double number = 0.0;
53 if (const auto* real = value->getIf<double>())
54 number = *real;
55 else if (const auto* integer = value->getIf<std::int64_t>())
56 number = static_cast<double>(*integer);
57 else
58 return false;
59 if (!std::isfinite(number) || number < 0.0 || number > std::numeric_limits<float>::max()) return false;
60 result = static_cast<float>(number);
61 return true;
62}
63
64bool readSignedNumber(const eve::Value::Object& object, std::string_view name, float& result, float fallback) {
65 const auto* value = field(object, name);
66 if (value == nullptr) {
67 result = fallback;
68 return true;
69 }
70 double number = 0.0;
71 if (const auto* real = value->getIf<double>())
72 number = *real;
73 else if (const auto* integer = value->getIf<std::int64_t>())
74 number = static_cast<double>(*integer);
75 else
76 return false;
77 if (!std::isfinite(number) || number < -std::numeric_limits<float>::max() ||
78 number > std::numeric_limits<float>::max())
79 return false;
80 result = static_cast<float>(number);
81 return true;
82}
83
84bool readBool(const eve::Value::Object& object, std::string_view name, bool& result, bool fallback) {
85 const auto* value = field(object, name);
86 if (value == nullptr) {
87 result = fallback;
88 return true;
89 }
90 const auto* boolean = value->getIf<bool>();
91 if (boolean == nullptr) return false;
92 result = *boolean;
93 return true;
94}
95
96} // namespace
97
99 auto parsed = eve::Value::fromJson(source.json);
100 if (!parsed) return eve::Result<VehicleDefinition>::failure(parsed.status());
101 const auto* object = parsed.value().getIf<eve::Value::Object>();
102 if (object == nullptr)
104 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle definition must be an object", "json",
105 {}, "vehicle.definition_runtime"));
106
107 VehicleDefinition result;
108 result.id = source.id;
109 if (!readString(*object, "category", result.category) || !readString(*object, "mobility", result.mobility))
111 eve::DiagnosticCode::InvalidArgument, "vehicle category and mobility must be strings", "definition", {},
112 "vehicle.definition_runtime"));
113 if (!readNumber(*object, "maxSpeed", result.maxSpeed, result.maxSpeed) ||
114 !readNumber(*object, "accel", result.accel, result.accel) ||
115 !readNumber(*object, "turnRate", result.turnRate, result.turnRate) ||
116 !readNumber(*object, "radius", result.radius, result.radius) ||
117 !readNumber(*object, "maxHealth", result.maxHealth, result.maxHealth) || result.radius <= 0.f ||
118 result.maxHealth < 0.f)
120 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle numeric definition field is invalid",
121 "definition", {}, "vehicle.definition_runtime"));
122
123 if (const auto* physics = field(*object, "physics")) {
124 const auto* physicsObject = physics->getIf<eve::Value::Object>();
125 if (physicsObject == nullptr)
127 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle physics must be an object",
128 "physics", {}, "vehicle.definition_runtime"));
129 if (!readNumber(*physicsObject, "maxSpeed", result.maxSpeed, result.maxSpeed) ||
130 !readNumber(*physicsObject, "accel", result.accel, result.accel) ||
131 !readNumber(*physicsObject, "turnRate", result.turnRate, result.turnRate) ||
132 !readNumber(*physicsObject, "radius", result.radius, result.radius))
134 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle physics numeric field is invalid",
135 "physics", {}, "vehicle.definition_runtime"));
136 }
137
138 if (const auto* zones = field(*object, "armorZones")) {
139 const auto* array = zones->getIf<eve::Value::Array>();
140 if (array == nullptr)
143 "armorZones", {}, "vehicle.definition_runtime"));
144 for (std::size_t index = 0; index < array->size(); ++index) {
145 const auto* item = (*array)[index].getIf<eve::Value::Object>();
146 if (item == nullptr)
148 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "armor zone must be an object",
149 "armorZones", {}, "vehicle.definition_runtime"));
150 ArmorZone zone;
151 if (!readString(*item, "name", zone.name) || !readString(*item, "node", zone.node) ||
152 !readNumber(*item, "mult", zone.mult, zone.mult) || zone.name.empty())
154 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "armor zone fields are invalid",
155 "armorZones", {}, "vehicle.definition_runtime"));
156 result.armorZones.push_back(std::move(zone));
157 }
158 }
159
160 if (const auto* mounts = field(*object, "mounts")) {
161 const auto* array = mounts->getIf<eve::Value::Array>();
162 if (array == nullptr)
164 "mounts must be an array", "mounts",
165 {}, "vehicle.definition_runtime"));
166 for (std::size_t index = 0; index < array->size(); ++index) {
167 const auto* item = (*array)[index].getIf<eve::Value::Object>();
168 if (item == nullptr)
170 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "mount must be an object", "mounts",
171 {}, "vehicle.definition_runtime"));
172 MountDef mount;
173 mount.name = "mount" + std::to_string(index);
174 if (!readString(*item, "name", mount.name) || !readString(*item, "weapon", mount.weapon) ||
175 !readString(*item, "type", mount.type) || !readString(*item, "aimMode", mount.aimMode) ||
176 !readSignedNumber(*item, "yawMin", mount.yawMin, mount.yawMin) ||
177 !readSignedNumber(*item, "yawMax", mount.yawMax, mount.yawMax) ||
178 !readSignedNumber(*item, "pitchMin", mount.pitchMin, mount.pitchMin) ||
179 !readSignedNumber(*item, "pitchMax", mount.pitchMax, mount.pitchMax) ||
180 !readNumber(*item, "rotSpeed", mount.rotSpeed, mount.rotSpeed) ||
181 !readNumber(*item, "firingArc", mount.firingArc, mount.firingArc))
183 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "mount definition field is invalid",
184 "mounts", {}, "vehicle.definition_runtime"));
185 if (const auto* limits = field(*item, "limits")) {
186 const auto* values = limits->getIf<eve::Value::Array>();
187 if (values == nullptr || values->size() < 4)
189 eve::DiagnosticCode::InvalidArgument, "mount limits must contain four numbers", "mounts.limits",
190 {}, "vehicle.definition_runtime"));
191 float* output[] = {&mount.yawMin, &mount.yawMax, &mount.pitchMin, &mount.pitchMax};
192 for (std::size_t limit = 0; limit < 4; ++limit) {
193 const auto* real = (*values)[limit].getIf<double>();
194 const auto* integer = (*values)[limit].getIf<std::int64_t>();
195 const double number = real ? *real
196 : integer ? static_cast<double>(*integer)
197 : std::numeric_limits<double>::quiet_NaN();
198 if (!std::isfinite(number) || number < -std::numeric_limits<float>::max() ||
199 number > std::numeric_limits<float>::max())
202 "mounts.limits", {}, "vehicle.definition_runtime"));
203 *output[limit] = static_cast<float>(number);
204 }
205 }
206 result.mounts.push_back(std::move(mount));
207 }
208 }
209
210 if (const auto* suspension = field(*object, "suspension")) {
211 const auto* value = suspension->getIf<eve::Value::Object>();
212 if (value == nullptr)
214 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "suspension must be an object",
215 "suspension", {}, "vehicle.definition_runtime"));
216 if (!readNumber(*value, "maxTravel", result.suspension.maxTravel, result.suspension.maxTravel) ||
217 !readNumber(*value, "driveForce", result.suspension.driveForce, result.suspension.driveForce) ||
218 !readNumber(*value, "lateralGrip", result.suspension.lateralGrip, result.suspension.lateralGrip))
220 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "suspension numeric field is invalid",
221 "suspension", {}, "vehicle.definition_runtime"));
222 if (const auto* wheels = field(*value, "wheels")) {
223 const auto* array = wheels->getIf<eve::Value::Array>();
224 if (array == nullptr)
226 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "suspension wheels must be an array",
227 "suspension.wheels", {}, "vehicle.definition_runtime"));
228 for (std::size_t index = 0; index < array->size(); ++index) {
229 const auto* item = (*array)[index].getIf<eve::Value::Object>();
230 if (item == nullptr)
233 "suspension.wheels", {}, "vehicle.definition_runtime"));
234 SuspensionWheel wheel;
235 if (!readSignedNumber(*item, "x", wheel.x, wheel.x) ||
236 !readSignedNumber(*item, "y", wheel.y, wheel.y) ||
237 !readSignedNumber(*item, "z", wheel.z, wheel.z) ||
238 !readNumber(*item, "radius", wheel.radius, wheel.radius) ||
239 !readNumber(*item, "rest", wheel.restLength, wheel.restLength) ||
240 !readNumber(*item, "stiffness", wheel.stiffness, wheel.stiffness) ||
241 !readNumber(*item, "damping", wheel.damping, wheel.damping) ||
242 !readBool(*item, "drive", wheel.drive, wheel.drive) ||
243 !readBool(*item, "steer", wheel.steer, wheel.steer))
245 eve::DiagnosticCode::InvalidArgument, "wheel definition field is invalid", "suspension.wheels",
246 {}, "vehicle.definition_runtime"));
247 result.suspension.wheels.push_back(wheel);
248 }
249 }
250 }
251
252 if (const auto* seats = field(*object, "seats")) {
253 const auto* array = seats->getIf<eve::Value::Array>();
254 if (array == nullptr)
256 "seats must be an array", "seats", {},
257 "vehicle.definition_runtime"));
258 for (std::size_t index = 0; index < array->size(); ++index) {
259 const auto* item = (*array)[index].getIf<eve::Value::Object>();
260 if (item == nullptr)
262 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "seat must be an object", "seats", {},
263 "vehicle.definition_runtime"));
264 SeatDef seat;
265 seat.name = "passenger" + std::to_string(index);
266 if (!readString(*item, "name", seat.name) || !readString(*item, "driver", seat.driver) ||
267 !readString(*item, "cameraMode", seat.cameraMode))
269 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "seat definition field is invalid",
270 "seats", {}, "vehicle.definition_runtime"));
271 if (const auto* mount = field(*item, "mountIndex")) {
272 const auto* integer = mount->getIf<std::int64_t>();
273 if (integer == nullptr || *integer < std::numeric_limits<int>::min() ||
274 *integer > std::numeric_limits<int>::max())
277 "seats.mountIndex", {}, "vehicle.definition_runtime"));
278 seat.mountIndex = static_cast<int>(*integer);
279 }
280 result.seats.push_back(std::move(seat));
281 }
282 }
283 if (const auto* tags = field(*object, "tags")) {
284 const auto* array = tags->getIf<eve::Value::Array>();
285 if (array == nullptr)
287 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle tags must be an array", "tags",
288 {}, "vehicle.definition_runtime"));
289 for (const auto& item : *array) {
290 const auto* text = item.getIf<std::string>();
291 if (text == nullptr || text->empty())
293 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle tag is invalid", "tags", {},
294 "vehicle.definition_runtime"));
295 result.tags.push_back(*text);
296 }
297 }
298 return eve::Result<VehicleDefinition>::success(std::move(result));
299}
300
301namespace {
302
303eve::Value encodeState(const VehicleRuntimeState& state) {
305 {"destroyed", eve::Value(state.destroyed)},
306 {"faction", eve::Value(state.faction)},
307 {"heading", eve::Value(static_cast<double>(state.heading))},
308 {"health", eve::Value(static_cast<double>(state.health))},
309 {"speed", eve::Value(static_cast<double>(state.speed))},
310 {"x", eve::Value(static_cast<double>(state.x))},
311 {"y", eve::Value(static_cast<double>(state.y))},
312 });
313}
314
316 const auto* object = value.getIf<eve::Value::Object>();
317 if (object == nullptr)
319 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle runtime state must be an object",
320 "state", {}, "vehicle.definition_runtime"));
321 static const std::set<std::string> fields = {"destroyed", "faction", "heading", "health", "speed", "x", "y"};
322 for (const auto& [name, unused] : *object) {
323 (void)unused;
324 if (!fields.contains(name))
326 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "unknown vehicle runtime state field",
327 "state." + name, {}, "vehicle.definition_runtime"));
328 }
329 for (const auto& name : fields)
330 if (!object->contains(name))
331 return eve::Result<VehicleRuntimeState>::failure(
332 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle runtime state is missing a field",
333 "state." + name, {}, "vehicle.definition_runtime"));
334 auto number = [&](std::string_view name, float& output, bool allowNegative) -> bool {
335 const auto* real = object->at(std::string(name)).getIf<double>();
336 if (real == nullptr || !std::isfinite(*real) || (!allowNegative && *real < 0.0) ||
337 *real < -std::numeric_limits<float>::max() || *real > std::numeric_limits<float>::max())
338 return false;
339 output = static_cast<float>(*real);
340 return true;
341 };
342 const auto* destroyed = object->at("destroyed").getIf<bool>();
343 const auto* faction = object->at("faction").getIf<std::string>();
344 VehicleRuntimeState result;
345 if (destroyed == nullptr || faction == nullptr || !number("heading", result.heading, false) ||
346 !number("health", result.health, false) || !number("speed", result.speed, false) ||
347 !number("x", result.x, true) || !number("y", result.y, true))
349 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle runtime state field is invalid",
350 "state", {}, "vehicle.definition_runtime"));
351 result.destroyed = *destroyed;
352 result.faction = *faction;
353 return eve::Result<VehicleRuntimeState>::success(std::move(result));
354}
355
356} // namespace
357
359 eve::DefinitionRef definition,
360 eve::PersistentId instanceId,
362 if (!definition.id().isValid() || definition.id().namespaceName() != "vehicle")
364 eve::DiagnosticCode::InvalidArgument, "vehicle definition reference must use vehicle namespace",
365 "definition", {}, "vehicle.definition_runtime"));
366 auto handle = currentHandle(registry, definition);
368 auto resolved = registry.resolveHandle(handle.value());
369 if (!resolved) return eve::Result<VehicleDefinitionRuntime>::failure(resolved.status());
370 auto typed = parseVehicleDefinition(resolved.value().get());
371 if (!typed) return eve::Result<VehicleDefinitionRuntime>::failure(typed.status());
372 VehicleRuntimeState defaults;
373 defaults.health = typed.value().maxHealth;
375 handle.value().generation, defaults);
376 if (!runtime) return eve::Result<VehicleDefinitionRuntime>::failure(runtime.status());
378 VehicleDefinitionRuntime(registry, std::move(runtime).takeValue(), policy));
379}
380
382 std::string_view definitionId,
383 eve::PersistentId instanceId,
385 auto logical = eve::LogicalId::fromParts("vehicle", definitionId);
386 if (!logical)
388 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle id is not a valid logical name",
389 "definitionId", {}, "vehicle.definition_runtime"));
390 auto reference = eve::DefinitionRef::fromId(*logical);
392 return create(registry, std::move(reference).takeValue(), instanceId, policy);
393}
394
396 eve::PersistentId instanceId,
398 return create(module.definitionRegistry(), definitionId, instanceId, policy);
399}
400
402 return runtime_.identity();
403}
404
405const VehicleRuntimeState& VehicleDefinitionRuntime::state() const noexcept { return runtime_.state(); }
406
407VehicleRuntimeState& VehicleDefinitionRuntime::state() noexcept { return runtime_.state(); }
408
410 return runtime_.identity().definitionHandle();
411}
412
414 if (registry_ == nullptr)
416 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle definition registry is not bound",
417 "registry", {}, "vehicle.definition_runtime"));
418 auto resolved = registry_->resolveHandle(definitionHandle());
419 if (!resolved) return eve::Result<VehicleDefinition>::failure(resolved.status());
420 return parseVehicleDefinition(resolved.value().get());
421}
422
423void VehicleDefinitionRuntime::setActive(bool active) noexcept { runtime_.setActive(active); }
424
425bool VehicleDefinitionRuntime::isActive() const noexcept { return runtime_.isActive(); }
426
428 if (entity == nullptr)
430 eve::DiagnosticCode::InvalidArgument, "vehicle runtime cannot project to a null VehicleEntity", "entity",
431 {}, "vehicle.definition_runtime"));
432 auto typed = definition();
433 if (!typed) return eve::Result<void>::failure(typed.status());
434 try {
435 auto definitionOwner = std::make_shared<const VehicleDefinition>(typed.value());
436 auto identity = *entity->identity();
437 auto definition = *entity->definition();
438 auto binding = *entity->definitionBinding();
439 auto motion = *entity->motion();
440 auto health = *entity->health();
441 auto flags = *entity->stateFlags();
442
443 identity.id = this->identity().instanceId.format();
444 identity.defId = this->identity().definition.id().name();
445 definition.owned = std::move(definitionOwner);
446 definition.def = definition.owned.get();
447 binding.identity = this->identity();
448 binding.reloadPolicy = policy_;
449 binding.active = isActive();
450 motion.x = state().x;
451 motion.y = state().y;
452 motion.heading = state().heading;
453 motion.speed = state().speed;
454 motion.arrived = false;
455 health.maxHp = typed.value().maxHealth;
456 health.hp = std::clamp(state().health, 0.f, health.maxHp);
457 flags.destroyed = state().destroyed;
458
459 using std::swap;
460 swap(*entity->identity(), identity);
461 swap(*entity->definition(), definition);
462 swap(*entity->definitionBinding(), binding);
463 swap(*entity->motion(), motion);
464 swap(*entity->health(), health);
465 swap(*entity->stateFlags(), flags);
467 } catch (const std::exception&) {
469 "vehicle runtime projection allocation failed",
470 "entity", {}, "vehicle.definition_runtime"));
471 }
472}
473
475 if (registry_ == nullptr)
477 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "vehicle definition registry is not bound",
478 "registry", {}, "vehicle.definition_runtime"));
479 auto next = currentHandle(*registry_, identity().definition);
480 if (!next) return eve::Result<eve::definition::ReloadOutcome>::failure(next.status());
481 auto resolved = registry_->resolveHandle(next.value());
482 if (!resolved) return eve::Result<eve::definition::ReloadOutcome>::failure(resolved.status());
483 auto typed = parseVehicleDefinition(resolved.value().get());
484 if (!typed) return eve::Result<eve::definition::ReloadOutcome>::failure(typed.status());
485 VehicleRuntimeState defaults;
486 defaults.health = typed.value().maxHealth;
487 const float maxHealth = typed.value().maxHealth;
488 auto rebuild = [maxHealth](const VehicleRuntimeState& oldState, const eve::definition::InstanceIdentity&,
490 VehicleRuntimeState rebuilt = oldState;
491 rebuilt.health = std::clamp(oldState.health, 0.f, maxHealth);
492 return eve::Result<VehicleRuntimeState>::success(std::move(rebuilt));
493 };
494 auto result = runtime_.reload(next.value(), policy, defaults, std::move(rebuild));
495 if (result.ok()) policy_ = policy;
496 return result;
497}
498
507
509 const eve::SnapshotHashProvider& hashProvider) const {
510 auto result = snapshot(revision, tick, hashProvider);
511 if (!result) return eve::Result<std::string>::failure(result.status());
512 return std::move(result).andThen(
514}
515
517 const eve::SnapshotHashProvider& hashProvider) {
518 if (registry_ == nullptr)
520 "vehicle definition registry is not bound", "registry",
521 {}, "vehicle.definition_runtime"));
522 auto current = currentHandle(*registry_, identity().definition);
523 if (!current) return eve::Result<void>::failure(current.status());
524 if (current.value() != definitionHandle())
526 eve::DiagnosticCode::StaleHandle, "vehicle snapshot cannot restore against a replaced definition",
527 "definitionGeneration", {}, "vehicle.definition_runtime"));
529 return eve::definition::restoreRuntimeInstance(runtime_, snapshotValue, "vehicle.runtime", vehicleSchema(),
530 eve::SchemaVersion(1), hashProvider, decoder);
531}
532
533} // namespace eve::vehicle
double value
bool & active
std::string output
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
std::map< std::string, Var > values
std::string text
bool required
std::string name
std::string error
Definition Package.cpp:60
eve::action::ActionVfxBinding binding
std::uint64_t revision
std::vector< std::string > fields
Definition PlayHost.cpp:111
PrimitiveHandle handle
double number
double current
bool boolean
SimulationTick tick
Json object
int limit
Definition TreeMesh.cpp:164
uint32_t index
const UnitySourceAsset & source
const AssetImportLimits & limits
Owning, renderer-independent dynamic values.
Strongly typed Vehicle definition/entity runtime adapter.
Stable definition reference backed by LogicalId.
Definition ResourceRef.h:85
static Result< DefinitionRef > fromId(LogicalId id)
Build a definition reference from a valid LogicalId.
const LogicalId & id() const noexcept
Return the stable logical definition identity.
Definition ResourceRef.h:97
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
Human-readable, scoped identifier in the form namespace:name.
Definition Identity.h:411
static std::optional< LogicalId > fromParts(std::string_view namespaceName, std::string_view name)
Builds a logical ID from separate namespace and name components.
Definition Identity.cpp:48
static std::optional< LogicalId > parse(std::string_view text)
Parses a scoped logical name.
Definition Identity.cpp:36
std::string_view name() const noexcept
Returns the name component as a view into this object.
Definition Identity.cpp:63
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
static eve::Result< RuntimeInstance > create(eve::PersistentId instanceId, eve::DefinitionRef definition, eve::Generation definitionGeneration, State state, bool active=true)
Construct a runtime instance after validating its identity.
Deterministic registry of topic-neutral, versioned JSON definitions.
Definition Definitions.h:58
eve::ResultRef< const Definition > resolveHandle(const DefinitionHandle &handle) const
Resolves a generation-qualified handle and reports stale identities.
eve::Result< DefinitionHandle > handle(const std::string &type, const std::string &id) const
Returns the current generation-qualified handle through Result.
Id128 public API.
Definition Identity.h:112
std::string format() const
Formats the ID in lower-case canonical UUID text.
Definition Identity.h:173
Binds a VehicleDefinition to a VehicleEntity without a new root type.
eve::Result< std::string > snapshotJson(eve::Revision revision, eve::SimulationTick tick, const eve::SnapshotHashProvider &hashProvider) const
Serialize snapshot() as canonical deterministic JSON.
eve::Result< void > restore(const eve::SnapshotEnvelope &snapshot, const eve::SnapshotHashProvider &hashProvider)
Verify and restore a same-generation vehicle snapshot atomically.
bool isActive() const noexcept
Return the active guard state.
void setActive(bool active) noexcept
Set the active guard used by RejectWhileActive.
eve::Result< eve::SnapshotEnvelope > snapshot(eve::Revision revision, eve::SimulationTick tick, const eve::SnapshotHashProvider &hashProvider) const
Capture mutable entity state in a common SnapshotEnvelope.
eve::definition::DefinitionHandle definitionHandle() const noexcept
Return the generation-qualified definition handle.
const eve::definition::InstanceIdentity & identity() const noexcept
Borrow common instance identity and exact definition generation.
static eve::Result< VehicleDefinitionRuntime > create(eve::definitions::DefinitionRegistry &registry, eve::DefinitionRef definition, eve::PersistentId instanceId, eve::definition::ReloadPolicy policy=eve::definition::ReloadPolicy::RebuildInstance)
Create from a common vehicle:<name> definition.
const VehicleRuntimeState & state() const noexcept
Borrow mutable vehicle entity state.
eve::Result< void > applyTo(VehicleEntity *entity) const
Project typed state and identity into a borrowed VehicleEntity.
eve::Result< VehicleDefinition > definition() const
Resolve and parse the current strongly typed VehicleDefinition.
eve::Result< eve::definition::ReloadOutcome > reload(eve::definition::ReloadPolicy policy)
Reload the registry's current generation using a typed policy.
载具实体:数据全部在组件里,行为在 VehicleSystem。
载具模块(eve.Vehicle)。
Definition Vehicle.h:33
eve::definitions::DefinitionRegistry & definitionRegistry() noexcept
Return the canonical common registry for vehicle definitions.
Definition Vehicle.h:59
ReloadPolicy
Policy used when a live definition is replaced.
eve::Result< eve::SnapshotEnvelope > snapshotRuntimeInstance(const RuntimeInstance< State > &runtime, std::string type, eve::LogicalId schema, eve::SchemaVersion schemaVersion, eve::Revision revision, eve::SimulationTick tick, const eve::SnapshotHashProvider &hashProvider, const RuntimeStateEncoder< State > &encode)
Capture a typed runtime instance in the common snapshot envelope.
eve::Result< void > restoreRuntimeInstance(RuntimeInstance< State > &runtime, const eve::SnapshotEnvelope &snapshot, std::string_view expectedType, const eve::LogicalId &expectedSchema, eve::SchemaVersion expectedVersion, const eve::SnapshotHashProvider &hashProvider, const RuntimeStateDecoder< State > &decode)
Verify and atomically restore a typed runtime instance.
std::function< eve::Result< State >(const eve::Value &)> RuntimeStateDecoder
Decodes one domain-owned runtime state from an owning Value.
std::function< eve::Result< eve::Value >(const State &)> RuntimeStateEncoder
Converts one domain-owned runtime state into an owning Value.
eve::Diagnostic Diagnostic
eve::Result< T > Result
bool readString(const eve::Value::Object &object, const char *name, std::string &output)
const EditorValue * field(const EditorValue &value, const char *name)
bool readNumber(const EditorValue &value, const char *name, float &output)
驾驶者接口与玩家控制状态。
eve::Result< VehicleDefinition > parseVehicleDefinition(const eve::definitions::Definition &source)
Parse one canonical registry definition into a short-lived typed projection.
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
Result< std::string > serializeSnapshotEnvelope(const SnapshotEnvelope &snapshot)
Serialize an envelope as deterministic compact JSON.
Definition Snapshot.cpp:184
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
A generation-qualified reference to one definition incarnation.
Canonical identity carried by every typed runtime instance.
One immutable view of a registered versioned JSON definition.
Definition Definitions.h:31
装甲区(Phase 4 伤害管线使用;Phase 2 仅作为定义数据保留)。
武器挂点声明(载具模板的一部分)。
座位声明(载具模板的一部分,FPS 面)。
float driveForce
驱动轮满油门牵引力(牛顿)。
float lateralGrip
侧向抓地系数(越大越不容易侧滑)。
float maxTravel
悬架最大行程(米)。
std::vector< SuspensionWheel > wheels
3D 悬架车轮配置(raycast 悬架用)。
float x
相对车体原点的局部偏移(米,+Y 向上)。
载具模板(registerVehiclesFromJson 注册,进程级注册表)。
std::vector< MountDef > mounts
std::string mobility
IVehicleMobility 注册名;默认 "kinematic"。
std::vector< std::string > tags
std::vector< ArmorZone > armorZones
std::vector< SeatDef > seats
Mutable state owned by one typed vehicle runtime instance.