载入中...
搜索中...
未找到
WeaponAction.cpp
浏览该文件的文档.
2
3#include <cmath>
4#include <cstdint>
5#include <limits>
6#include <string>
7#include <utility>
8
9namespace eve::weapon {
10namespace {
11
12eve::Result<eve::LogicalId> weaponActionId(const WeaponDefinition& weapon) {
13 if (weapon.id.empty())
15 eve::DiagnosticCode::InvalidArgument, "weapon definition id must not be empty", "weapon.id"));
16 const auto id = eve::LogicalId::fromParts("weapon", "attack." + weapon.id);
17 if (!id)
19 eve::DiagnosticCode::InvalidArgument, "weapon id cannot form a valid action logical id", "weapon.id"));
21}
22
23eve::Result<eve::Duration> seconds(float value, const char* path) {
24 auto duration = eve::Duration::fromSeconds(static_cast<double>(value));
26 if (duration.value().nanoseconds() < 0)
28 eve::DiagnosticCode::InvalidArgument, "weapon action duration must be non-negative", path));
29 return duration;
30}
31
32const char* resourceName(ResourceKind kind) {
33 switch (kind) {
34 case ResourceKind::Ammo: return "ammo";
35 case ResourceKind::Mana: return "mana";
36 case ResourceKind::Charges: return "charges";
37 case ResourceKind::Stamina: return "stamina";
38 case ResourceKind::None: return "";
39 }
40 return "";
41}
42
43eve::Result<std::optional<eve::resource::CostSpec>> weaponCost(const WeaponDefinition& weapon) {
44 if (weapon.resource.infinite || weapon.resource.kind == ResourceKind::None)
45 return eve::Result<std::optional<eve::resource::CostSpec>>::success(std::nullopt);
46
47 double amount = static_cast<double>(weapon.resource.cost);
48 // Ranged WeaponSystem consumes one magazine unit per trigger even when
49 // the legacy template leaves resource.cost at its zero default.
50 if (weapon.resource.kind == ResourceKind::Ammo && amount <= 0.0) amount = 1.0;
51 if (!std::isfinite(amount) || amount <= 0.0 || std::floor(amount) != amount || amount >= std::ldexp(1.0, 63))
52 return eve::Result<std::optional<eve::resource::CostSpec>>::failure(
54 "weapon resource cost must be a finite positive integer", "resource.cost"));
55
56 auto cost = eve::resource::CostSpec::single(resourceName(weapon.resource.kind), static_cast<std::int64_t>(amount));
57 if (!cost) return eve::Result<std::optional<eve::resource::CostSpec>>::failure(cost.status());
58 return eve::Result<std::optional<eve::resource::CostSpec>>::success(std::move(cost).takeValue());
59}
60
61void put(eve::Value::Object& object, const char* key, float value) {
62 object.emplace(key, eve::Value(static_cast<double>(value)));
63}
64
65void put(eve::Value::Object& object, const char* key, int value) { object.emplace(key, eve::Value(value)); }
66
67} // namespace
68
72
73namespace {
74
78 auto definition = WeaponActionAdapter::makeDefinition(weapon, attack);
79 if (!definition) return eve::Result<eve::transaction::TransactionReceipt>::failure(definition.status());
80 auto request = WeaponActionAdapter::makeRequest(weapon, attack, std::nullopt, tick);
82
83 auto actionDefinition = std::move(definition).takeValue();
84 auto actionRequest = std::move(request).takeValue();
85 if (transactionId.empty()) transactionId = "weapon.fire." + weapon.id;
86 actionRequest.transactionId = std::move(transactionId);
87
89 services.transactionEffect = &effect;
90 services.transactionAccount = &account;
91 action::ActionRuntime runtime(services);
92 auto submitted = runtime.submit(std::move(actionDefinition), std::move(actionRequest));
93 if (!submitted) return eve::Result<eve::transaction::TransactionReceipt>::failure(submitted.status());
94 const auto executionId = std::move(submitted).takeValue();
95 const auto* submittedExecution = runtime.find(executionId);
96 if (submittedExecution == nullptr)
99 "weapon Action execution disappeared after submit", "weapon.fire"));
100
101 auto total = submittedExecution->definition().timing.windup.tryAdd(submittedExecution->definition().timing.active);
102 if (!total) return eve::Result<eve::transaction::TransactionReceipt>::failure(total.status());
103 total = std::move(total).takeValue().tryAdd(submittedExecution->definition().timing.recover);
104 if (!total) return eve::Result<eve::transaction::TransactionReceipt>::failure(total.status());
105
106 auto advanced = runtime.advance(executionId, tick, std::move(total).takeValue());
107 if (!advanced) return eve::Result<eve::transaction::TransactionReceipt>::failure(advanced.status());
108 const auto* execution = runtime.find(executionId);
109 if (execution == nullptr || execution->phase() != action::ActionPhase::Completed ||
110 execution->transactionReceipt() == nullptr)
113 "weapon Action execution completed without a transaction receipt", "weapon.fire"));
114 return eve::Result<eve::transaction::TransactionReceipt>::success(*execution->transactionReceipt(),
115 advanced.status());
116}
117
118} // namespace
119
122 eve::transaction::ITransactionParticipant& effect, std::string transactionId) {
123 return executeActionFire(weapon, AttackRequest{}, account, effect, eve::SimulationTick(1),
124 std::move(transactionId));
125}
126
132
134 const AttackRequest& request) {
135 auto id = weaponActionId(weapon);
137 auto windup = seconds(weapon.stages.windupTime, "stages.windupTime");
138 if (!windup) return eve::Result<action::ActionDefinition>::failure(windup.status());
139 auto active = seconds(weapon.stages.activeTime, "stages.activeTime");
141 auto recover = seconds(weapon.stages.recoverTime, "stages.recoverTime");
142 if (!recover) return eve::Result<action::ActionDefinition>::failure(recover.status());
143 auto cost = resourceCost(weapon);
145
146 action::ActionDefinition definition;
147 definition.id = std::move(id).takeValue();
148 definition.timing.windup = std::move(windup).takeValue();
149 definition.timing.active = std::move(active).takeValue();
150 definition.timing.recover = std::move(recover).takeValue();
151 definition.targetingMode = request.hasTarget ? action::TargetingMode::Explicit : action::TargetingMode::None;
152 definition.cost = std::move(cost).takeValue();
153 // Weapon logic is an Active operation even if its effect ids are resolved
154 // by the weapon logic/event sink rather than the effects registry.
155 definition.activeExecutionRequired = true;
156 definition.metadata.emplace("weaponId", eve::Value(weapon.id));
157 definition.metadata.emplace("logic", eve::Value(weapon.logic));
158 definition.metadata.emplace("kind", eve::Value(static_cast<int>(weapon.kind)));
159
160 auto valid = definition.validate();
162 return eve::Result<action::ActionDefinition>::success(std::move(definition));
163}
164
166 const AttackRequest& attack,
167 std::optional<ecs::EntityHandle> source,
168 eve::SimulationTick requestedTick) {
169 auto definition = makeDefinition(weapon, attack);
170 if (!definition) return eve::Result<action::ActionRequest>::failure(definition.status());
171 auto checkedDefinition = std::move(definition).takeValue();
172
174 request.actionId = checkedDefinition.id;
175 request.source = std::move(source);
176 request.requestedTick = requestedTick;
177 if (attack.hasTarget) request.targetEntities.push_back(attack.targetHandle);
178
179 // The canonical request owns deterministic attack parameters. Weapon
180 // fields remain in WeaponDefinition/WeaponEntity; this is only a
181 // provider-neutral transport envelope for the Active executor.
182 put(request.parameters, "targetX", attack.targetX);
183 put(request.parameters, "targetY", attack.targetY);
184 put(request.parameters, "targetZ", attack.targetZ);
185 request.parameters.emplace("hasTarget", eve::Value(attack.hasTarget));
186 put(request.parameters, "muzzleX", attack.muzzleX);
187 put(request.parameters, "muzzleY", attack.muzzleY);
188 put(request.parameters, "muzzleZ", attack.muzzleZ);
189 put(request.parameters, "yaw", attack.yaw);
190 put(request.parameters, "pitch", attack.pitch);
191 put(request.parameters, "shooterId", attack.shooterId);
192 put(request.parameters, "arcAngle", attack.arcAngle);
193 put(request.parameters, "aoeRadius", attack.aoeRadius);
194 put(request.parameters, "spread", attack.spread);
195 put(request.parameters, "pelletIndex", attack.pelletIndex);
196 put(request.parameters, "pelletCount", attack.pelletCount);
197
198 auto valid = request.validate(checkedDefinition);
201}
202
203} // namespace eve::weapon
double value
bool & active
float duration
eve::action::ActionExecutionId executionId
eve::resource::CostSpec cost
eve::resource::IResourceAccount * account
const GltfImportRequest & request
std::uint32_t key
wgpu::PopErrorScopeStatus status
TokenKind kind
bool valid
std::unique_ptr< ParticleEffect > effect
std::string path
Definition PlayHost.cpp:110
SimulationTick tick
const UnitySourceAsset & source
Weapon Attack to renderer-independent Action adapter.
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 Result< Duration > fromSeconds(double seconds)
Convert finite seconds to the nearest nanosecond.
Definition Time.cpp:16
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
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
std::map< std::string, Value > Object
Definition Value.h:34
Deterministic action lifecycle coordinator.
Definition Action.h:485
static eve::Result< CostSpec > single(std::string_view resource, std::int64_t amount)
Build a one-resource cost.
Provider-neutral resource account contract.
Synchronous participant contract for one coordinator transaction.
static eve::Result< std::optional< eve::resource::CostSpec > > resourceCost(const WeaponDefinition &weapon)
Convert the weapon trigger resource into a canonical cost.
static eve::Result< action::ActionDefinition > makeDefinition(const WeaponDefinition &weapon, const AttackRequest &request)
Build an action definition for one attack request.
static eve::Result< eve::transaction::TransactionReceipt > fire(const WeaponDefinition &weapon, eve::resource::IResourceAccount &account, eve::transaction::ITransactionParticipant &effect, std::string transactionId={})
Execute one already-built weapon effect and charge its resource atomically.
static eve::Result< action::ActionRequest > makeRequest(const WeaponDefinition &weapon, const AttackRequest &attack, std::optional< ecs::EntityHandle > source=std::nullopt, eve::SimulationTick requestedTick=eve::SimulationTick::zero())
Build a request carrying the original weapon attack parameters.
@ None
The action has no target selection.
@ Explicit
The request already owns the selected ECS target handles.
载具模块入口(eve.Vehicle):定义注册 / 实体工厂 / RTS 命令 / 帧调度。 设计文档:docs/dev/通用载具系统设计.md
ResourceKind
触发资源的类型。
Definition WeaponTypes.h:50
detail::StrongUint64< detail::SimulationTickTag > SimulationTick
Deterministic simulation time step; it is not wall-clock time.
Definition Time.h:31
Immutable-by-convention definition of one action kind.
Definition Action.h:90
One caller-owned request to instantiate an action execution.
Definition Action.h:127
LogicalId actionId
Definition identity this request intends to execute.
Definition Action.h:129
Borrowed composition ports used by one ActionRuntime owner.
Definition Action.h:351
transaction::ITransactionParticipant * transactionEffect
Optional common transaction effect participant.
Definition Action.h:367
resource::IResourceAccount * transactionAccount
Account paired with transactionEffect for a cost-bearing action.
Definition Action.h:369
一次攻击请求(C++ 系统 / 脚本发起)。角度均为度。 旧名 FireRequest 保留为别名,向后兼容。
int pelletIndex
多弹丸:本粒序号 / 总粒数(1 = 单弹丸)。
float muzzleX
炮口世界位置(未提供时游戏侧自行推断)。
float spread
本发实际散布(度,散布 bloom 后的当前值)。
int shooterId
游戏侧实体/玩家 id。
ecs::EntityHandle targetHandle
可选目标实体(导弹锁定 / 法杖单目标)。
float yaw
发射方向(度)。
float arcAngle
近战挥击命中弧(度)。
float aoeRadius
法术/导弹爆炸半径。
武器模板(registerWeaponsFromJson 注册,进程级注册表)。
AttackStageSpec stages
阶段机时长(秒)。
std::string logic
IWeaponLogic 注册名;默认 "projectile"。
WeaponKind kind
形态(决定阶段机如何跑)。默认 Ranged。