11std::string hexEncode(
const std::string&
value) {
12 static constexpr char digits[] =
"0123456789abcdef";
14 result.reserve(
value.size() * 2);
15 for (
const unsigned char byte :
value) {
16 result.push_back(digits[
byte >> 4u]);
17 result.push_back(digits[
byte & 0x0fu]);
22int hexDigit(
char value) {
29bool hexDecode(
const std::string&
value, std::string& result) {
30 if (
value.size() % 2 != 0)
return false;
32 result.reserve(
value.size() / 2);
33 for (
size_t i = 0; i <
value.size(); i += 2) {
34 const int high = hexDigit(
value[i]);
35 const int low = hexDigit(
value[i + 1]);
36 if (high < 0 || low < 0)
return false;
37 result.push_back(
char((high << 4) | low));
45 std::ostringstream out;
46 out <<
"EVPCG_POINT_GRAPH 1\n";
47 out << std::setprecision(9);
48 for (
const auto&
id : nodeOrder_) {
49 const auto&
node = nodes_.at(
id);
50 out <<
"NODE " << std::quoted(
id) <<
' ' << std::quoted(
node.operation) <<
'\n';
51 std::vector<std::string> keys;
52 keys.reserve(
node.floats.size());
54 std::sort(keys.begin(), keys.end());
55 for (
const auto&
key : keys)
56 out <<
"FLOAT " << std::quoted(
id) <<
' ' << std::quoted(
key) <<
' '
59 keys.reserve(
node.ints.size());
61 std::sort(keys.begin(), keys.end());
62 for (
const auto&
key : keys)
63 out <<
"INT " << std::quoted(
id) <<
' ' << std::quoted(
key) <<
' '
66 keys.reserve(
node.strings.size());
68 std::sort(keys.begin(), keys.end());
69 for (
const auto&
key : keys)
70 out <<
"STRING " << std::quoted(
id) <<
' ' << std::quoted(
key) <<
' '
71 << std::quoted(
node.strings.at(
key)) <<
'\n';
73 out <<
"SUBGRAPH " << std::quoted(
id) <<
' ' << std::quoted(
node.subgraphInput) <<
' '
74 << std::quoted(
node.subgraphOutput) <<
' '
75 << std::quoted(hexEncode(
node.subgraph->serializeDefinition())) <<
'\n';
78 std::vector<std::string> parameterNames = parameterOrder_;
79 std::sort(parameterNames.begin(), parameterNames.end());
80 for (
const auto&
name : parameterNames) {
81 const auto& parameter = parameters_.at(
name);
82 out <<
"PARAM " << std::quoted(
name) <<
' ' << std::quoted(parameter.nodeId) <<
' '
83 << std::quoted(parameter.key) <<
'\n';
85 for (
const auto&
id : nodeOrder_) {
86 const auto&
node = nodes_.at(
id);
89 out <<
"EDGE " << std::quoted(
node.inputs[
input]) <<
' ' << std::quoted(
id) <<
' '
98 std::istringstream
input(definition);
101 if (!(
input >> magic >> version) || magic !=
"EVPCG_POINT_GRAPH" || version != 1) {
102 error_ =
"invalid point graph header";
109 if (
line.empty())
continue;
110 std::istringstream record(
line);
118 if (
kind ==
"NODE") {
120 if (!(record >> std::quoted(
id) >> std::quoted(
operation)) ||
122 error_ =
"invalid NODE record";
125 }
else if (
kind ==
"EDGE") {
128 if (!(record >> std::quoted(
id) >> std::quoted(
to) >> slot) ||
130 error_ =
"invalid EDGE record";
133 }
else if (
kind ==
"FLOAT") {
136 if (!(record >> std::quoted(
id) >> std::quoted(
key) >>
value) ||
138 error_ =
"invalid FLOAT record";
141 }
else if (
kind ==
"INT") {
144 if (!(record >> std::quoted(
id) >> std::quoted(
key) >>
value) ||
146 error_ =
"invalid INT record";
149 }
else if (
kind ==
"STRING") {
152 if (!(record >> std::quoted(
id) >> std::quoted(
key) >> std::quoted(
value)) ||
154 error_ =
"invalid STRING record";
157 }
else if (
kind ==
"SUBGRAPH") {
158 std::string nestedInput;
159 std::string nestedOutput;
160 std::string nestedEncoded;
161 std::string nestedDefinition;
162 if (!(record >> std::quoted(
id) >> std::quoted(nestedInput) >>
163 std::quoted(nestedOutput) >> std::quoted(nestedEncoded)) ||
164 !hexDecode(nestedEncoded, nestedDefinition)) {
165 error_ =
"invalid SUBGRAPH record";
170 !replacement.
setNodeSubgraph(
id, &nested, nestedInput, nestedOutput)) {
171 error_ =
"invalid nested graph at " +
id +
": " + nested.
getError();
174 }
else if (
kind ==
"PARAM") {
177 if (!(record >> std::quoted(
id) >> std::quoted(
nodeId) >> std::quoted(
key)) ||
179 error_ =
"invalid PARAM record";
183 error_ =
"unknown graph record: " +
kind;
188 error_ =
"trailing graph record data: " +
kind;
193 error_ =
"point graph END record is missing";
198 std::unordered_map<std::string, int> states;
199 std::function<bool(
const std::string&)> visit = [&](
const std::string&
id) {
200 if (states[
id] == 2)
return true;
201 if (states[
id] == 1)
return false;
203 const auto found = replacement.nodes_.find(
id);
204 if (
found == replacement.nodes_.end())
return false;
205 for (
const auto& dependency :
found->second.inputs)
206 if (!dependency.empty() && !visit(dependency))
return false;
210 for (
const auto&
id : replacement.nodeOrder_) {
212 error_ =
"cycle in serialized graph at node: " +
id;
216 *
this = std::move(replacement);
ActionParameterOperation operation
HexCoordinates to
Cell the unit walks towards on this segment.
EVENGINE_API_DOMAINS public API.
bool setNodeFloat(const std::string &id, const std::string &key, float value)
Sets the node float.
PointGraph * instantiate() const
Create an independent runtime instance without external inputs or overrides.
bool exposeParameter(const std::string &name, const std::string &nodeId, const std::string &key)
Expose one reflected node parameter for per-instance overrides.
bool setNodeString(const std::string &id, const std::string &key, const std::string &value)
Sets the node string.
bool connect(const std::string &fromId, const std::string &toId, int inputIndex=0)
Connect an output to input slot 0 or 1. Replaces that input connection.
std::string serializeDefinition() const
Serialize graph topology, parameters and nested graphs.
bool deserializeDefinition(const std::string &definition)
Transactionally replace this graph from serializeDefinition output.
bool setNodeSubgraph(const std::string &id, PointGraph *graph, const std::string &inputNode, const std::string &outputNode)
Assign an immutable nested graph.
std::string getError() const
Render the last compatibility execute/validate or legacy authoring error; canonical Result calls do n...
bool setNodeInt(const std::string &id, const std::string &key, int value)
Sets the node int.
bool addNode(const std::string &id, const std::string &operation)
Add a node using one of the operations returned by operationAt().