载入中...
搜索中...
未找到
DialogueState.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
4
5#include <algorithm>
6#include <string>
7#include <utility>
8#include <vector>
9
10namespace eve::dialogue {
11namespace {
12
13template <class T, class Query>
14std::optional<T> queryProviders(const std::string& subject, eve::IStateQuery* explicitProvider, Query&& query) {
15 if (explicitProvider) {
16 if (auto result = query(explicitProvider, subject); result.has_value()) return result;
17 }
18
19 eve::IStateQuery* service = eve::cap::query<eve::IStateQuery>();
20 if (service && service != explicitProvider) {
21 if (auto result = query(service, subject); result.has_value()) return result;
22 }
23
24 std::optional<T> result;
25 eve::cap::forEach<eve::IStateQuery>([&](eve::IStateQuery* provider) {
26 if (result.has_value() || provider == explicitProvider || provider == service) return;
27 result = query(provider, subject);
28 });
29 return result;
30}
31
32eve::Result<eve::decision::Condition> conditionError(std::string message, std::string path = {}) {
35}
36
37bool readString(const eve::Value& object, std::string_view key, std::string& out) {
38 const eve::Value* value = object.find(std::string(key));
39 if (!value || !value->isString()) return false;
40 out = value->asString();
41 return true;
42}
43
44bool readOperator(std::string_view spelling, eve::decision::CompareOperator& out) {
45 if (spelling == "eq" || spelling == "equal" || spelling == "==") {
47 return true;
48 }
49 if (spelling == "ne" || spelling == "notEqual" || spelling == "!=") {
51 return true;
52 }
53 if (spelling == "lt" || spelling == "<") {
55 return true;
56 }
57 if (spelling == "le" || spelling == "<=") {
59 return true;
60 }
61 if (spelling == "gt" || spelling == ">") {
63 return true;
64 }
65 if (spelling == "ge" || spelling == ">=") {
67 return true;
68 }
69 return false;
70}
71
72eve::Result<eve::decision::Condition> compileCondition(const eve::Value& specification) {
73 if (specification.isArray()) {
74 std::vector<eve::decision::Condition> children;
75 children.reserve(specification.arraySize());
76 for (std::size_t i = 0; i < specification.arraySize(); ++i) {
77 auto child = compileCondition(specification.at(i));
78 if (!child) return eve::Result<eve::decision::Condition>::failure(child.status());
79 children.push_back(std::move(child).takeValue());
80 }
82 }
83 if (!specification.isObject()) return conditionError("dialogue condition must be an object or array");
84
85 if (const eve::Value* all = specification.find("all")) {
86 if (!all->isArray()) return conditionError("condition 'all' must be an array", "all");
87 std::vector<eve::decision::Condition> children;
88 children.reserve(all->arraySize());
89 for (std::size_t i = 0; i < all->arraySize(); ++i) {
90 auto child = compileCondition(all->at(i));
91 if (!child) return eve::Result<eve::decision::Condition>::failure(child.status());
92 children.push_back(std::move(child).takeValue());
93 }
95 }
96 if (const eve::Value* any = specification.find("any")) {
97 if (!any->isArray()) return conditionError("condition 'any' must be an array", "any");
98 std::vector<eve::decision::Condition> children;
99 children.reserve(any->arraySize());
100 for (std::size_t i = 0; i < any->arraySize(); ++i) {
101 auto child = compileCondition(any->at(i));
102 if (!child) return eve::Result<eve::decision::Condition>::failure(child.status());
103 children.push_back(std::move(child).takeValue());
104 }
106 }
107 if (const eve::Value* negated = specification.find("not")) {
108 auto child = compileCondition(*negated);
109 if (!child) return eve::Result<eve::decision::Condition>::failure(child.status());
111 eve::decision::Condition::not_(std::move(child).takeValue()));
112 }
113
114 const eve::Value* tag = specification.find("tag");
115 if (!tag) tag = specification.find("hasTag");
116 if (tag) {
117 if (!tag->isString()) return conditionError("tag condition requires a string tag", "tag");
119 }
120
121 const eve::Value* authority = specification.find("authority");
122 if (authority) {
123 if (!authority->isString()) return conditionError("authority condition requires a string scope", "authority");
126 }
127
128 const eve::Value* policy = specification.find("policy");
129 if (!policy) policy = specification.find("script");
130 if (policy) {
131 if (!policy->isString()) return conditionError("policy condition requires a string name", "policy");
132 eve::Value arguments = eve::Value::Object{};
133 if (const eve::Value* supplied = specification.find("arguments")) arguments = *supplied;
135 eve::decision::Condition::policyCall(policy->asString(), std::move(arguments)));
136 }
137
138 const eve::Value* state = specification.find("state");
139 if (state && state->isString()) {
140 const eve::Value* expected = specification.find("equals");
141 if (!expected) expected = specification.find("value");
142 if (!expected)
146 eve::decision::Condition::stateEquals(state->asString(), *expected));
147 }
148
149 const eve::Value* attribute = specification.find("attribute");
150 const eve::Value* nameValue = specification.find("key");
151 if (!nameValue) nameValue = specification.find("var");
152 if (attribute && attribute->isString()) nameValue = attribute;
153
154 const eve::Value* operation = specification.find("op");
155 if (nameValue && operation) {
156 if (!nameValue->isString() || !operation->isString())
157 return conditionError("comparison condition requires string key and op");
158 const std::string key = nameValue->asString();
159 const std::string op = operation->asString();
160 if (op == "has")
162 if (op == "missing")
166 if (!readOperator(op, parsed)) return conditionError("unknown condition operator: " + op, "op");
167 const eve::Value* expected = specification.find("value");
168 if (!expected) return conditionError("comparison condition is missing value", "value");
170 eve::decision::Condition::compare(key, parsed, *expected));
171 }
172
173 if (attribute && attribute->isString())
176
177 if (state && state->isObject()) {
178 std::string key;
179 if (!readString(*state, "key", key)) return conditionError("state condition is missing key", "state.key");
180 const eve::Value* expected = state->find("equals");
181 if (!expected) expected = state->find("value");
182 if (!expected) return conditionError("state condition is missing value", "state.value");
184 eve::decision::Condition::stateEquals(std::move(key), *expected));
185 }
186
187 if (const eve::Value* compare = specification.find("compare")) {
188 if (!compare->isObject()) return conditionError("compare condition must be an object", "compare");
189 return compileCondition(*compare);
190 }
191
192 return conditionError("unrecognized dialogue condition");
193}
194
195eve::Result<eve::MutationReceipt> mutationUnavailable() {
197 eve::DiagnosticCode::Unsupported, "dialogue world mutation requires an IStateMutation capability",
198 "dialogue.state.mutation"));
199}
200
201} // namespace
202
204 switch (value.kind()) {
211 eve::Value::Array result;
212 result.reserve(value.arraySize());
213 for (std::size_t i = 0; i < value.arraySize(); ++i) result.push_back(toCanonicalValue(value.at(i)));
214 return eve::Value::array(std::move(result));
215 }
217 eve::Value::Object result;
218 for (const auto& key : value.keys()) result.emplace(key, toCanonicalValue(*value.find(key)));
219 return eve::Value::object(std::move(result));
220 }
221 }
222 return eve::Value::null();
223}
224
226 switch (value.type()) {
234 for (std::size_t i = 0; i < value.arraySize(); ++i) result.pushBack(toDialogueStateValue(value.at(i)));
235 return result;
236 }
239 for (const auto& key : value.keys()) result.set(key, toDialogueStateValue(*value.find(key)));
240 return result;
241 }
242 }
243 return eve::StateValue::null();
244}
245
247 : subject_(std::move(subject)), provider_(provider) {}
248
249void StateEvaluationContext::setSubject(std::string subject) { subject_ = std::move(subject); }
250
251std::optional<eve::Value> StateEvaluationContext::value(std::string_view key) const {
252 return queryProviders<eve::Value>(subject_, provider_, [&](eve::IStateQuery* provider, const std::string& subject) {
253 return provider->value(subject, key);
254 });
255}
256
257std::optional<bool> StateEvaluationContext::hasTag(std::string_view tag) const {
258 return queryProviders<bool>(subject_, provider_, [&](eve::IStateQuery* provider, const std::string& subject) {
259 return provider->hasTag(subject, tag);
260 });
261}
262
263std::optional<eve::Value> StateEvaluationContext::attribute(std::string_view key) const {
264 auto result = queryProviders<eve::Value>(
265 subject_, provider_,
266 [&](eve::IStateQuery* provider, const std::string& subject) { return provider->attribute(subject, key); });
267 if (result.has_value()) return result;
268 return value(key);
269}
270
271std::optional<eve::Value> StateEvaluationContext::resource(std::string_view key) const {
272 return queryProviders<eve::Value>(subject_, provider_, [&](eve::IStateQuery* provider, const std::string& subject) {
273 return provider->resource(subject, key);
274 });
275}
276
277std::optional<eve::Value> StateEvaluationContext::state(std::string_view key) const {
278 auto result = queryProviders<eve::Value>(
279 subject_, provider_,
280 [&](eve::IStateQuery* provider, const std::string& subject) { return provider->state(subject, key); });
281 if (result.has_value()) return result;
282 return value(key);
283}
284
285std::optional<bool> StateEvaluationContext::authority(std::string_view scope) const {
286 return queryProviders<bool>(subject_, provider_, [&](eve::IStateQuery* provider, const std::string& subject) {
287 return provider->authority(subject, scope);
288 });
289}
290
291std::optional<eve::decision::ConditionResult> StateEvaluationContext::policy(std::string_view name,
292 const eve::Value& arguments) const {
293 if (!policyEvaluator_) return std::nullopt;
294 return policyEvaluator_(name, arguments);
295}
296
298
299void DialogueStateContext::setSubject(std::string subject) { subject_ = std::move(subject); }
300
301StateEvaluationContext DialogueStateContext::evaluationContext() const {
302 StateEvaluationContext context(subject_, queryProvider_);
303 context.setPolicyEvaluator(policyEvaluator_);
304 return context;
305}
306
307std::optional<eve::Value> DialogueStateContext::value(std::string_view key) const {
308 auto context = evaluationContext();
309 return context.value(key);
310}
311
312std::optional<bool> DialogueStateContext::hasTag(std::string_view tag) const {
313 auto context = evaluationContext();
314 return context.hasTag(tag);
315}
316
317std::optional<eve::Value> DialogueStateContext::attribute(std::string_view key) const {
318 auto context = evaluationContext();
319 return context.attribute(key);
320}
321
322std::optional<eve::Value> DialogueStateContext::resource(std::string_view key) const {
323 auto context = evaluationContext();
324 return context.resource(key);
325}
326
327std::optional<eve::Value> DialogueStateContext::state(std::string_view key) const {
328 auto context = evaluationContext();
329 return context.state(key);
330}
331
333 return ::eve::dialogue::compileCondition(specification);
334}
335
337 auto context = evaluationContext();
338 return condition.evaluate(context);
339}
340
342 auto compiled = compileCondition(specification);
343 if (!compiled) {
344 const eve::Diagnostic* diagnostic = compiled.error();
345 const std::string message = diagnostic ? diagnostic->message() : "invalid dialogue condition";
348 }
349 eve::decision::Condition condition = std::move(compiled).takeValue();
350 return evaluate(condition);
351}
352
353eve::Result<eve::MutationReceipt> DialogueStateContext::apply(std::span<const eve::StateMutation> mutations,
354 const eve::MutationContext& context) const {
355 eve::IStateMutation* provider = mutationProvider_;
356 if (!provider) provider = eve::cap::query<eve::IStateMutation>();
357 if (!provider) return mutationUnavailable();
358 return provider->apply(mutations, context);
359}
360
361} // namespace eve::dialogue
ActionParameterOperation operation
double value
int subject
Definition AnimSmr.cpp:163
void * service
Dialogue's state boundary, condition adapter, and command request protocol.
eve::Value condition
std::string message
std::uint32_t key
JobScope scope
std::string name
const std::string * tag
std::string path
Definition PlayHost.cpp:110
int children
Definition TreeMesh.cpp:295
const VegetationPresetContext & context
A structured explanation of a failed, degraded, or noteworthy result.
Definition Diagnostic.h:94
const std::string & message() const noexcept
Human-readable explanation.
Definition Diagnostic.h:147
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
JSON-compatible state value tree used by state hot reload.
Definition StateValue.h:20
static StateValue object()
Empty object.
Definition StateValue.h:40
static StateValue boolean(bool v)
Boolean value.
static StateValue array()
Empty array.
Definition StateValue.h:38
static StateValue integer(int64_t v)
Integer value.
void pushBack(StateValue v)
Append an element; only valid on arrays.
static StateValue number(double v)
Floating-point value.
static StateValue null()
Null value.
Definition StateValue.h:28
static StateValue string(std::string v)
String value.
void set(const std::string &key, StateValue v)
Insert or replace key; only valid on objects.
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
const std::string & asString() const
Return the string payload; the caller must have checked the kind.
Definition Value.cpp:87
static Value null()
Compatibility factory for a null value.
Definition Value.h:102
std::map< std::string, Value > Object
Definition Value.h:34
bool isArray() const noexcept
Return true when this value is an array.
Definition Value.h:97
static Value number(double value)
Compatibility factory for a Double value.
Definition Value.h:106
bool isString() const noexcept
Return true when this value is a string.
Definition Value.h:95
static Value string(std::string value)
Compatibility factory for a string value.
Definition Value.h:110
static Value array(Array value)
Compatibility factory for an array value.
Definition Value.h:112
std::vector< Value > Array
Definition Value.h:33
static Value integer(std::int64_t value)
Compatibility factory for an Int64 value.
Definition Value.h:104
std::size_t arraySize() const
Return the number of array elements.
Definition Value.cpp:100
static Value boolean(bool value)
Compatibility factory for a boolean value.
Definition Value.h:108
static Value object(Object value)
Compatibility factory for an object value.
Definition Value.h:114
bool isObject() const noexcept
Return true when this value is an object.
Definition Value.h:99
Value & at(std::size_t index)
Return a bounds-checked array element.
Definition Value.cpp:106
Value * find(const std::string &key) noexcept
Return an object member, or nullptr when absent.
Definition Value.cpp:124
Explain one condition evaluation in a UI- and log-friendly form.
Definition Condition.h:129
static ConditionResult failed(ConditionReasonCode reason, Value evidence={}, Value details=Value::Object{})
Construct a rejected result with a stable reason and explanation.
Immutable condition AST node.
Definition Condition.h:195
static Condition hasAttribute(std::string attribute)
Require an attribute to exist.
static Condition all(std::vector< Condition > children)
Construct a conjunction of child conditions.
static Condition not_(Condition child)
Construct a logical negation of one child condition.
static Condition hasTag(std::string tag)
Require a tag to be present.
static Condition stateEquals(std::string key, Value expected)
Require a named state value to equal the expected value.
static Condition policyCall(std::string name, Value arguments=Value::Object{}, std::optional< ScriptConditionDeclaration > scriptDeclaration=std::nullopt)
Call a named read-only policy and use its ConditionResult.
static Condition compare(std::string key, CompareOperator op, Value expected)
Compare a context value against an expected scalar value.
static Condition authorityCheck(std::string scope)
Require read-only authority for a scope.
static Condition any(std::vector< Condition > children)
Construct a disjunction of child conditions.
std::optional< eve::Value > value(std::string_view key) const
Query a canonical world value without creating a local copy in Dialogue.
eve::Result< eve::decision::Condition > compileCondition(const eve::Value &specification) const
Compile a canonical condition specification to decision::Condition.
DialogueStateContext(std::string subject={})
Construct a context for one stable world subject.
eve::Result< eve::MutationReceipt > apply(std::span< const eve::StateMutation > mutations, const eve::MutationContext &context) const
Apply a complete mutation set through one authoritative provider.
eve::decision::ConditionResult evaluate(const eve::decision::Condition &condition) const
Evaluate an already compiled shared condition with explanation.
std::optional< eve::Value > state(std::string_view key) const
Query one persistent state value.
std::optional< eve::Value > resource(std::string_view key) const
Query one resource value.
std::optional< bool > hasTag(std::string_view tag) const
Query exact world tag membership.
std::optional< eve::Value > attribute(std::string_view key) const
Query one attribute or reputation value.
void setSubject(std::string subject)
Set the subject used for all future condition queries.
const std::string & subject() const noexcept
Return the currently selected subject id.
Decision EvaluationContext backed by one dialogue subject.
std::optional< eve::decision::ConditionResult > policy(std::string_view name, const eve::Value &arguments) const override
Evaluate a named read-only policy with owned arguments.
std::optional< bool > authority(std::string_view scope) const override
Query authority without changing grants, leases, or state.
std::optional< eve::Value > resource(std::string_view key) const override
Query a resource amount or resource marker.
std::optional< eve::Value > state(std::string_view key) const override
Query a state value for StateEquals nodes.
std::optional< eve::Value > value(std::string_view key) const override
Query a named scalar or structured value for Compare nodes.
std::optional< eve::Value > attribute(std::string_view key) const override
Query an attribute value; nullopt means the attribute is absent.
void setSubject(std::string subject)
Change the subject used by subsequent synchronous queries.
std::optional< bool > hasTag(std::string_view tag) const override
Query tag membership; nullopt means the tag source is unavailable.
StateEvaluationContext(std::string subject={}, eve::IStateQuery *provider=nullptr)
Construct a context for a stable subject id and optional provider.
All-or-nothing mutation boundary owned by the consumer.
virtual eve::Result< MutationReceipt > apply(std::span< const StateMutation > mutations, const MutationContext &context)=0
Apply a complete mutation set atomically.
Read-only world-state boundary owned by consumers such as Dialogue.
Definition StateAccess.h:79
virtual std::optional< eve::Value > state(std::string_view subject, std::string_view key) const =0
Query a persistent/world state value.
virtual std::optional< bool > hasTag(std::string_view subject, std::string_view tag) const =0
Query exact tag membership.
virtual std::optional< eve::Value > resource(std::string_view subject, std::string_view key) const =0
Query a resource value or marker.
virtual std::optional< bool > authority(std::string_view subject, std::string_view scope) const =0
Query read-only authority for a scope.
virtual std::optional< eve::Value > value(std::string_view subject, std::string_view key) const =0
Query a generic world value.
virtual std::optional< eve::Value > attribute(std::string_view subject, std::string_view key) const =0
Query a numeric or structured attribute.
I * query()
Queries .
Definition Capability.h:88
CompareOperator
Scalar comparison used by a Compare node.
Definition Condition.h:36
eve::Value toCanonicalValue(const eve::StateValue &value)
Convert the legacy reload value into the canonical common value.
eve::StateValue toDialogueStateValue(const eve::Value &value)
Convert a canonical value to the legacy reload representation.
bool readString(const eve::Value::Object &object, const char *name, std::string &output)
WidgetDesc child(std::string id, std::vector< WidgetDesc > children, float width, float height)
Scrollable child region with an explicit size.
Definition Widget.cpp:635
Correlation metadata shared by a mutation transaction.
Definition StateAccess.h:57