载入中...
搜索中...
未找到
SettlementAdapter.cpp
浏览该文件的文档.
2
4
5#include <algorithm>
6#include <cmath>
7#include <memory>
8#include <string>
9#include <utility>
10
11namespace eve::vehicle {
12namespace {
13
16}
17
18bool isDamageKind(std::string_view kind) noexcept { return kind == "damage"; }
19
20bool isHealingKind(std::string_view kind) noexcept { return kind == "heal" || kind == "healing"; }
21
22} // namespace
23
25 : vehicle_(vehicle), targetRef_(targetRef) {}
26
27const eve::Value* VehicleSettlementAdapter::contextValue(const settlement::SettlementContext& context,
28 std::string_view key) noexcept {
29 const auto* object = context.request().context.getIf<eve::Value::Object>();
30 if (object == nullptr) return nullptr;
31 const auto it = object->find(std::string(key));
32 return it == object->end() ? nullptr : &it->second;
33}
34
35std::optional<double> VehicleSettlementAdapter::numberValue(const eve::Value* value) noexcept {
36 if (value == nullptr) return std::nullopt;
37 if (const auto* number = value->getIf<double>()) return *number;
38 if (const auto* integer = value->getIf<std::int64_t>()) return static_cast<double>(*integer);
39 return std::nullopt;
40}
41
42std::optional<bool> VehicleSettlementAdapter::boolValue(const eve::Value* value) noexcept {
43 if (value == nullptr) return std::nullopt;
44 if (const auto* boolean = value->getIf<bool>()) return *boolean;
45 return std::nullopt;
46}
47
48std::optional<std::string> VehicleSettlementAdapter::stringValue(const eve::Value* value) {
49 if (value == nullptr) return std::nullopt;
50 if (const auto* string = value->getIf<std::string>()) return *string;
51 return std::nullopt;
52}
53
54bool VehicleSettlementAdapter::isDamage(const settlement::SettlementContext& context) const noexcept {
55 return isDamageKind(context.request().kind);
56}
57
58bool VehicleSettlementAdapter::isHealing(const settlement::SettlementContext& context) const noexcept {
59 return isHealingKind(context.request().kind);
60}
61
63 if (!(context.request().target == targetRef_))
66 "Vehicle settlement request target does not match adapter target", "target"));
67 if (!isDamage(context) && !isHealing(context))
70 "Vehicle settlement adapter supports damage and healing kinds only", "kind"));
71 if (vehicle_.health().operator->() == nullptr || vehicle_.stateFlags().operator->() == nullptr)
74 "Vehicle settlement requires health and state components", "vehicle"));
76 if (!hpResult) return eve::Result<void>::failure(hpResult.status());
78 if (!maxHpResult) return eve::Result<void>::failure(maxHpResult.status());
79 const double hp = hpResult.value();
80 const double maxHp = maxHpResult.value();
81 if (!std::isfinite(hp) || !std::isfinite(maxHp) || hp < 0.0 || maxHp < 0.0 || hp > maxHp)
83 eve::DiagnosticCode::InvariantViolation, "Vehicle health component is outside validated bounds", "health"));
84 context.setStageDetail("policy", "vehicle");
85 context.setStageDetail("health_component", "VehicleAttributeAdapter::health");
87}
88
90 double multiplier = numberValue(contextValue(context, "source_multiplier")).value_or(1.0);
91 if (!std::isfinite(multiplier) || multiplier < 0.0)
94 "Vehicle source multiplier must be finite and non-negative", "source_multiplier"));
95 auto scaled = context.setMagnitude(context.magnitude() * multiplier);
96 const bool scaledOk = scaled.ok();
97 if (!scaledOk) {
98 const auto status = scaled.status();
100 }
101
102 const bool critical = boolValue(contextValue(context, "critical")).value_or(false);
103 const double criticalMultiplier = numberValue(contextValue(context, "critical_multiplier")).value_or(1.0);
104 if (!std::isfinite(criticalMultiplier) || criticalMultiplier < 1.0)
106 eve::DiagnosticCode::InvalidArgument, "Vehicle critical multiplier must be finite and at least one",
107 "critical_multiplier"));
108 if (critical) {
109 auto criticalScaled = context.setMagnitude(context.magnitude() * criticalMultiplier);
110 const bool criticalScaledOk = criticalScaled.ok();
111 if (!criticalScaledOk) {
112 const auto status = criticalScaled.status();
114 }
115 }
116 context.setCritical(critical);
117 context.setStageDetail("source_multiplier", multiplier);
118 context.setStageDetail("critical", critical);
119 if (critical) context.setStageDetail("critical_multiplier", criticalMultiplier);
121}
122
124 // Vehicle armor is deliberately handled by the armor/shield phase. This
125 // phase remains a real no-op so every policy shares the same contract.
126 context.setStageDetail("resistance", 0.0);
128}
129
131 if (!isDamage(context)) return eve::Result<void>::success();
132
133 const std::string zone = stringValue(contextValue(context, "armor_zone")).value_or("");
134 double zoneMultiplier = 1.0;
135 if (!zone.empty() && vehicle_.definition().operator->() != nullptr && vehicle_.definition()->def != nullptr) {
136 for (const auto& armor : vehicle_.definition()->def->armorZones) {
137 if (armor.name != zone) continue;
138 if (!std::isfinite(armor.mult) || armor.mult < 0.0)
140 eve::DiagnosticCode::InvariantViolation, "Vehicle armor-zone multiplier is invalid", "armor_zone"));
141 zoneMultiplier = armor.mult;
142 break;
143 }
144 }
145
146 const double penetration = std::clamp(numberValue(contextValue(context, "penetration")).value_or(0.0), 0.0, 1.0);
147 zoneMultiplier += penetration * (1.0 - zoneMultiplier);
148
149 const double incidence = std::clamp(numberValue(contextValue(context, "incidence")).value_or(1.0), 0.0, 1.0);
150 // Incidence 1 is a square hit. A glancing hit at zero receives half the
151 // zone-adjusted amount; it is deterministic and does not require physics.
152 zoneMultiplier *= 0.5 + 0.5 * incidence;
153
155 if (!armorResult) return eve::Result<void>::failure(armorResult.status());
156 const double armor = armorResult.value();
157 if (!std::isfinite(armor) || armor < 0.0)
159 eve::DiagnosticCode::InvariantViolation, "Vehicle armor attribute is outside validated bounds", "armor"));
160 const double armorFactor = armor == 0.0 ? 1.0 : 100.0 / (100.0 + armor);
161 zoneMultiplier *= armorFactor;
162
163 const double before = context.magnitude();
164 auto changed = context.setMagnitude(before * zoneMultiplier);
165 const bool changedOk = changed.ok();
166 if (!changedOk) {
167 const auto status = changed.status();
169 }
170 auto resisted = context.addResisted(before - context.magnitude());
171 const bool resistedOk = resisted.ok();
172 if (!resistedOk) {
173 const auto status = resisted.status();
175 }
176 context.setStageDetail("armor_zone", zone);
177 context.setStageDetail("zone_multiplier", zoneMultiplier);
178 context.setStageDetail("penetration", penetration);
179 context.setStageDetail("incidence", incidence);
180 context.setStageDetail("armor", armor);
181 context.setStageDetail("armor_factor", armorFactor);
182 context.setStageDetail("shield", 0.0);
184}
185
188 if (!hpResult) return eve::Result<void>::failure(hpResult.status());
190 if (!maxHpResult) return eve::Result<void>::failure(maxHpResult.status());
191 const double hp = hpResult.value();
192 const double maxHp = maxHpResult.value();
193 const double bound = isDamage(context) ? hp : maxHp - hp;
194 auto configured = context.setClampMax(std::max(0.0, bound));
195 const bool configuredOk = configured.ok();
196 if (!configuredOk) {
197 const auto status = configured.status();
199 }
200 context.setStageDetail("maximum", bound);
202}
203
207 if (!hpResult) return eve::Result<settlement::PreparedApply>::failure(hpResult.status());
209 if (!maxHpResult) return eve::Result<settlement::PreparedApply>::failure(maxHpResult.status());
210 const double hp = hpResult.value();
211 const double maxHp = maxHpResult.value();
212 const double nextHp = isDamage(context) ? hp - context.magnitude() : hp + context.magnitude();
213 if (!std::isfinite(nextHp) || nextHp < 0.0 || nextHp > maxHp)
216 "Vehicle settlement candidate health is outside its validated bounds", "health"));
217
218 auto beforeSnapshotResult = VehicleAttributeAdapter::snapshot(vehicle_);
219 if (!beforeSnapshotResult) return eve::Result<settlement::PreparedApply>::failure(beforeSnapshotResult.status());
220 auto beforeSnapshot = std::move(beforeSnapshotResult).takeValue();
221
222 struct Pending {
223 VehicleEntity* vehicle = nullptr;
225 bool beforeDestroyed = false;
226 float nextHp = 0.0f;
227 bool nextDestroyed = false;
228 bool published = false;
229 };
230 const bool nextDestroyed = isDamage(context) && nextHp <= 0.0;
231 auto pending =
232 std::make_shared<Pending>(Pending{&vehicle_, std::move(beforeSnapshot), vehicle_.stateFlags()->destroyed,
233 static_cast<float>(nextHp), nextDestroyed, false});
237 pending->nextHp);
238 if (!applied) return applied;
239 pending->vehicle->stateFlags()->destroyed = pending->nextDestroyed;
240 pending->published = true;
241 return success(eve::StatusCode::Applied);
242 },
243 [pending]() {
244 if (!pending->published) return;
245 auto restored = VehicleAttributeAdapter::restore(*pending->vehicle, pending->beforeAttributes,
246 pending->vehicle->attributes()->values.revision());
247 if (!restored) std::terminate();
248 pending->vehicle->stateFlags()->destroyed = pending->beforeDestroyed;
249 }));
250}
251
252} // namespace eve::vehicle
double value
std::vector< QuestEvent > pending
DiagnosticCode code
std::uint32_t key
wgpu::PopErrorScopeStatus status
TokenKind kind
double number
bool boolean
std::string string
const VegetationPresetContext & context
Selective canonical health and armor adapter for vehicles.
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
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
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
Strong, domain-neutral reference to a runtime subject.
Definition SubjectRef.h:26
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
const T * getIf() const noexcept
Return a typed pointer, or nullptr when the kind differs.
Definition Value.h:180
Prepared domain mutation used to make settlement application atomic.
Definition Settlement.h:281
Mutable calculation frame visible to policy and custom stage code.
Definition Settlement.h:338
static constexpr std::string_view healthAttribute
static eve::Result< double > read(VehicleEntity &vehicle, std::string_view attribute)
Read a selected final combat attribute and refresh health projection.
static eve::Result< void > restore(VehicleEntity &vehicle, const eve::attributes::AttributeProjectionSnapshot &snapshot, eve::Revision expectedRevision)
Restore a vehicle attribute snapshot after owner/revision checks.
static eve::Result< void > setBase(VehicleEntity &vehicle, std::string_view attribute, double value)
Set a selected canonical base and refresh the compatibility health fields.
static eve::Result< eve::attributes::AttributeProjectionSnapshot > snapshot(VehicleEntity &vehicle)
Capture health/max_health/armor with owner generation and revision.
static constexpr std::string_view maxHealthAttribute
static constexpr std::string_view armorAttribute
载具实体:数据全部在组件里,行为在 VehicleSystem。
eve::Result< void > sourceModifiers(settlement::SettlementContext &context) override
Apply source-side modifiers such as critical or elemental power.
eve::Result< void > armorShield(settlement::SettlementContext &context) override
Apply armor and shield policy, recording absorbed amount.
VehicleSettlementAdapter(VehicleEntity &vehicle, SubjectRef targetRef)
Bind an existing vehicle health component to a stable subject id.
eve::Result< void > targetMitigation(settlement::SettlementContext &context) override
Apply target mitigation such as resistance or penetration rules.
eve::Result< void > validate(settlement::SettlementContext &context) override
Validate request and target-owned state without mutating it.
eve::Result< settlement::PreparedApply > prepareApply(const settlement::SettlementContext &context) override
Build an atomic candidate mutation without publishing it.
eve::Result< void > clamp(settlement::SettlementContext &context) override
Configure policy-specific amount bounds for the generic clamp.
驾驶者接口与玩家控制状态。
StatusCode
Stable outcome category for an operation.
Definition Status.h:27
Transaction-safe snapshot of selected attributes and their modifiers.
Vehicle health/armor policy adapter for the common settlement pipeline.