载入中...
搜索中...
未找到
AttributeSystem.cpp
浏览该文件的文档.
2#include "rpg/RPGActor.h"
3
4#include <algorithm>
5#include <atomic>
6
7namespace eve::rpg {
8
9void AttributeOpTable::registerOp(const std::string &name, Fn fn) { ops_[name] = std::move(fn); }
10
11void AttributeOpTable::unregisterOp(const std::string &name) { ops_.erase(name); }
12
13bool AttributeOpTable::has(const std::string &name) const { return ops_.find(name) != ops_.end(); }
14
15double AttributeOpTable::apply(const std::string &name, double current, double value) const {
16 auto it = ops_.find(name);
17 if (it == ops_.end()) return current;
18 return it->second(current, value);
19}
20
21double computeAttributeValue(const AttributeValue &attr, const AttributeOpTable *customOps) {
22 double addSum = 0.0;
23 double mulAddSum = 0.0;
24 double mulMulProduct = 1.0;
25 std::vector<const AttributeModifier *> sequential;
26 sequential.reserve(attr.modifiers.size());
27
28 for (const auto &m : attr.modifiers) {
29 if (m.op == "add")
30 addSum += m.value;
31 else if (m.op == "mulAdd")
32 mulAddSum += m.value;
33 else if (m.op == "mulMul")
34 mulMulProduct *= (1.0 + m.value);
35 else
36 sequential.push_back(&m);
37 }
38
39 double result = attr.base + addSum;
40 result *= (1.0 + mulAddSum);
41 result *= mulMulProduct;
42
43 // override / clampMin / clampMax / custom ops are order-sensitive: apply by
44 // ascending priority (stable, so equal-priority keeps insertion order).
45 std::stable_sort(sequential.begin(), sequential.end(),
46 [](const AttributeModifier *a, const AttributeModifier *b) {
47 return a->priority < b->priority;
48 });
49
50 for (const AttributeModifier *m : sequential) {
51 if (m->op == "override")
52 result = m->value;
53 else if (m->op == "clampMin")
54 result = std::max(result, m->value);
55 else if (m->op == "clampMax")
56 result = std::min(result, m->value);
57 else if (customOps && customOps->has(m->op))
58 result = customOps->apply(m->op, result, m->value);
59 // unknown op names are silently ignored (forward-compat: data may
60 // reference ops from a newer game build not registered here).
61 }
62 return result;
63}
64
66 static AttributeOpTable table;
67 return table;
68}
69
70std::string AttributeSystem::nextModifierId() {
71 static std::atomic<uint64_t> counter{0};
72 return "mod#" + std::to_string(++counter);
73}
74
75void AttributeSystem::setBase(RPGActor *actor, const std::string &attribute, double value) {
76 if (!actor) return;
77 auto &av = actor->attributes()->values[attribute];
78 av.base = value;
79 av.dirty = true;
80}
81
82double AttributeSystem::getBase(RPGActor *actor, const std::string &attribute) {
83 if (!actor) return 0.0;
84 auto &values = actor->attributes()->values;
85 auto it = values.find(attribute);
86 return it == values.end() ? 0.0 : it->second.base;
87}
88
89void AttributeSystem::modifyBase(RPGActor *actor, const std::string &attribute, double delta) {
90 if (!actor) return;
91 auto &av = actor->attributes()->values[attribute];
92 av.base += delta;
93 av.dirty = true;
94}
95
96bool AttributeSystem::hasAttribute(RPGActor *actor, const std::string &attribute) {
97 if (!actor) return false;
98 auto &values = actor->attributes()->values;
99 return values.find(attribute) != values.end();
100}
101
102std::string AttributeSystem::addModifier(RPGActor *actor, const std::string &attribute,
103 const std::string &source, const std::string &op,
104 double value, int priority) {
105 if (!actor) return {};
106 std::string id = nextModifierId();
107 auto &av = actor->attributes()->values[attribute];
109 mod.id = id;
110 mod.source = source;
111 mod.op = op;
112 mod.value = value;
113 mod.priority = priority;
114 av.modifiers.push_back(std::move(mod));
115 av.dirty = true;
116 return id;
117}
118
119bool AttributeSystem::removeModifier(RPGActor *actor, const std::string &attribute,
120 const std::string &modifierId) {
121 if (!actor) return false;
122 auto &values = actor->attributes()->values;
123 auto it = values.find(attribute);
124 if (it == values.end()) return false;
125 auto &mods = it->second.modifiers;
126 auto mit = std::find_if(mods.begin(), mods.end(),
127 [&](const AttributeModifier &m) { return m.id == modifierId; });
128 if (mit == mods.end()) return false;
129 mods.erase(mit);
130 it->second.dirty = true;
131 return true;
132}
133
134int AttributeSystem::removeModifiersBySource(RPGActor *actor, const std::string &attribute,
135 const std::string &source) {
136 if (!actor) return 0;
137 auto &values = actor->attributes()->values;
138 auto it = values.find(attribute);
139 if (it == values.end()) return 0;
140 auto &mods = it->second.modifiers;
141 size_t before = mods.size();
142 mods.erase(std::remove_if(mods.begin(), mods.end(),
143 [&](const AttributeModifier &m) { return m.source == source; }),
144 mods.end());
145 int removed = int(before - mods.size());
146 if (removed > 0) it->second.dirty = true;
147 return removed;
148}
149
150int AttributeSystem::removeAllModifiersBySource(RPGActor *actor, const std::string &source) {
151 if (!actor) return 0;
152 int total = 0;
153 for (auto &kv : actor->attributes()->values) {
154 auto &mods = kv.second.modifiers;
155 size_t before = mods.size();
156 mods.erase(std::remove_if(mods.begin(), mods.end(),
157 [&](const AttributeModifier &m) { return m.source == source; }),
158 mods.end());
159 int removed = int(before - mods.size());
160 if (removed > 0) {
161 kv.second.dirty = true;
162 total += removed;
163 }
164 }
165 return total;
166}
167
168double AttributeSystem::getFinal(RPGActor *actor, const std::string &attribute) {
169 if (!actor) return 0.0;
170 auto &av = actor->attributes()->values[attribute];
171 if (av.dirty) {
172 av.cached = computeAttributeValue(av, &customOps());
173 av.dirty = false;
174 }
175 return av.cached;
176}
177
178void AttributeSystem::invalidate(RPGActor *actor, const std::string &attribute) {
179 if (!actor) return;
180 auto &values = actor->attributes()->values;
181 auto it = values.find(attribute);
182 if (it != values.end()) it->second.dirty = true;
183}
184
185} // namespace eve::rpg
int priority
std::string value
std::map< std::string, Var > values
bool removed
std::string id
uint32_t a
uint32_t b
const char * name
Definition RockMesh.cpp:21
SettlementPipeline::Stage fn
float m[16]
自定义 op 注册表:opName -> f(currentResult, modifierValue) -> newResult。
bool has(const std::string &name) const
void unregisterOp(const std::string &name)
void registerOp(const std::string &name, Fn fn)
std::function< double(double current, double value)> Fn
double apply(const std::string &name, double current, double value) const
static std::string addModifier(RPGActor *actor, const std::string &attribute, const std::string &source, const std::string &op, double value, int priority=0)
添加一条修改器,返回自动生成的唯一 id(用于之后精确移除)。 空字符串 id 表示失败(actor 为空)。
static void setBase(RPGActor *actor, const std::string &attribute, double value)
设置基础值(不存在则创建该属性)。
static bool removeModifier(RPGActor *actor, const std::string &attribute, const std::string &modifierId)
按 id 精确移除;返回是否命中。
static bool hasAttribute(RPGActor *actor, const std::string &attribute)
static void modifyBase(RPGActor *actor, const std::string &attribute, double delta)
增量修改基础值(如自然回蓝、升级加点)。
static void invalidate(RPGActor *actor, const std::string &attribute)
标记某个属性需要在下次 getFinal 时重新计算(内部使用;一般不需要手动调用)。
static double getBase(RPGActor *actor, const std::string &attribute)
static int removeAllModifiersBySource(RPGActor *actor, const std::string &source)
按来源标签批量移除该 actor 所有属性上的修改器;返回移除数量。
static double getFinal(RPGActor *actor, const std::string &attribute)
计算并返回最终值(内部带缓存,属性未变化时不会重复计算)。
static int removeModifiersBySource(RPGActor *actor, const std::string &attribute, const std::string &source)
按来源标签批量移除某个属性上的修改器;返回移除数量。
static AttributeOpTable & customOps()
全局自定义 op 注册表(进程生命周期内有效)。
属性 / 状态 / 技能三表合一的 ECS 实体。
Definition RPGActor.h:28
RPG 模块入口:属性 / 效果 / 状态 / 技能 / 结算五套系统的脚本绑定与帧调度点。
double computeAttributeValue(const AttributeValue &attr, const AttributeOpTable *customOps)
单条修改器。附加在某个属性上,参与最终值计算。
std::string source
来源标签(如 "effect:12" / "skill:fireball" / 自定义),用于批量移除
std::string id
唯一 id(由 AttributeSystem 生成),用于精确移除
int priority
计算顺序,数值小的先应用;同优先级按插入顺序
单个属性的完整状态:基础值 + 修改器列表 + 计算结果缓存。
std::vector< AttributeModifier > modifiers