载入中...
搜索中...
未找到
ConversationText.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cctype>
5#include <iomanip>
6#include <sstream>
7
8namespace eve::dialogue {
9namespace {
10std::string scalarText(const eve::Value* value) {
11 if (!value || value->isNull()) return {};
12 if (value->isString()) return value->asString();
13 if (value->isBool()) return value->asBool() ? "true" : "false";
14 if (value->isInt64()) return std::to_string(value->asInt());
15 if (value->isDouble()) {
16 std::ostringstream output;
17 output << std::setprecision(12) << value->asDouble();
18 return output.str();
19 }
20 return {};
21}
22std::string transform(std::string value, const std::string& operation) {
23 if (operation == "upper")
24 std::transform(value.begin(), value.end(), value.begin(),
25 [](unsigned char c) { return static_cast<char>(std::toupper(c)); });
26 else if (operation == "lower")
27 std::transform(value.begin(), value.end(), value.begin(),
28 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
29 else if (operation == "capitalize" && !value.empty())
30 value[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(value[0])));
31 return value;
32}
33
34const eve::Value* findPath(const eve::Value& root, const std::string& path) {
35 const eve::Value* current = &root;
36 std::size_t begin = 0;
37 while (begin <= path.size()) {
38 const std::size_t separator = path.find('.', begin);
39 const std::string key =
40 path.substr(begin, separator == std::string::npos ? std::string::npos : separator - begin);
41 current = current->find(key);
42 if (!current || separator == std::string::npos) return current;
43 begin = separator + 1;
44 }
45 return current;
46}
47
48std::string renderToken(std::string token, const eve::Value& bindings, const eve::Value& locals) {
49 std::string operation;
50 if (const size_t separator = token.find('|'); separator != std::string::npos) {
51 operation = token.substr(separator + 1);
52 token.resize(separator);
53 }
54 std::string fallback;
55 if (const size_t separator = token.find("??"); separator != std::string::npos) {
56 fallback = token.substr(separator + 2);
57 token.resize(separator);
58 }
59 const eve::Value* value = findPath(locals, token);
61 std::string rendered = scalarText(value);
62 if (rendered.empty()) rendered = std::move(fallback);
63 return transform(std::move(rendered), operation);
64}
65void replaceAll(std::string& text, const std::string& find, const std::string& replacement) {
66 if (find.empty()) return;
67 for (size_t position = 0; (position = text.find(find, position)) != std::string::npos;
68 position += replacement.size())
69 text.replace(position, find.size(), replacement);
70}
71} // namespace
72
73std::string ConversationTextRenderer::render(const std::string& text, const eve::Value& bindings,
74 const eve::Value& locals, const Evaluator& evaluate) const {
75 std::string output;
76 output.reserve(text.size());
77 for (size_t cursor = 0; cursor < text.size();) {
78 if (text[cursor] != '{') {
79 output.push_back(text[cursor++]);
80 continue;
81 }
82 const size_t close = text.find('}', cursor + 1);
83 if (close == std::string::npos) {
84 output.append(text, cursor, std::string::npos);
85 break;
86 }
87 const std::string value = renderToken(text.substr(cursor + 1, close - cursor - 1), bindings, locals);
88 if (value.empty())
89 output.append(text, cursor, close - cursor + 1);
90 else
91 output += value;
92 cursor = close + 1;
93 }
94 for (const auto& rule : rules_) {
95 if (!rule.expression.empty() && (!evaluate || !evaluate(rule.expression))) continue;
96 replaceAll(output, rule.find, rule.replacement);
97 output = rule.prefix + output + rule.suffix;
98 }
99 return output;
100}
101
102void ConversationTextRenderer::addToneRule(std::string expression, std::string prefix, std::string suffix,
103 std::string find, std::string replacement) {
104 rules_.push_back(
105 {std::move(expression), std::move(prefix), std::move(suffix), std::move(find), std::move(replacement)});
106}
107} // namespace eve::dialogue
ActionParameterOperation operation
double value
int root
Definition AnimSmr.cpp:119
std::string output
std::uint32_t key
std::int32_t c
std::string text
std::array< float, 3 > position
std::vector< std::shared_ptr< DeviceBytes > > bindings
Definition OnnxGpgpu.cpp:38
std::string path
Definition PlayHost.cpp:110
float begin
uint64_t token
double current
std::size_t cursor
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
void addToneRule(std::string expression, std::string prefix, std::string suffix, std::string find, std::string replacement)
Append a state-dependent character voice rule.
std::function< bool(const std::string &)> Evaluator
std::string render(const std::string &text, const eve::Value &bindings, const eve::Value &locals, const Evaluator &evaluate={}) const
Render placeholders from locals first, then bindings, and apply matching tone rules.
Result< HexPath > findPath(const HexMap &map, HexSearchContext &scratch, HexCoordinates from, HexCoordinates to, const HexMoveRules &rules, const HexOccupancyQuery &occupied)
Finds the cheapest path between two cells.
WidgetDesc separator(std::string id)
Horizontal separator line.
Definition Widget.cpp:345