载入中...
搜索中...
未找到
VegetationPreset.cpp
浏览该文件的文档.
2
3#include <cerrno>
4#include <cstdlib>
5#include <cmath>
6
7namespace eve::asset_import {
8namespace {
9
10const Value* member(const Value::Object& object, std::string_view name) {
11 const auto found = object.find(std::string(name));
12 return found == object.end() ? nullptr : &found->second;
13}
14
15Result<std::vector<std::string>> strings(const Value* value, std::string_view path) {
16 const auto* array = value ? value->getIf<Value::Array>() : nullptr;
17 if (!array)
18 return Result<std::vector<std::string>>::failure(
19 Diagnostic::error(DiagnosticCode::ParseError, "arguments must be an array", std::string(path), {},
20 "asset.import.vegetation-preset"));
21 std::vector<std::string> result;
22 result.reserve(array->size());
23 for (const auto& item : *array) {
24 if (!item.isString())
25 return Result<std::vector<std::string>>::failure(
26 Diagnostic::error(DiagnosticCode::ParseError, "argument must be a string", std::string(path), {},
27 "asset.import.vegetation-preset"));
28 result.push_back(item.asString());
29 }
30 return Result<std::vector<std::string>>::success(std::move(result));
31}
32
33std::string joined(std::string_view operation, const std::vector<std::string>& arguments) {
34 std::string value(operation);
35 for (const auto& argument : arguments) {
36 if (!value.empty()) value.push_back(' ');
37 value += argument;
38 }
39 return value;
40}
41
42bool contains(std::string_view text, const std::vector<std::string>& arguments) {
43 return text.find(joined({}, arguments)) != std::string_view::npos;
44}
45
46Result<bool> predicate(std::string_view name, const std::vector<std::string>& arguments,
47 const VegetationPresetContext& context) {
48 if (name == "OUTPUT_OPTION_CONTAINS") {
49 if (arguments.size() != 1)
51 "output predicate requires one argument", {}, {},
52 "asset.import.vegetation-preset"));
53 return Result<bool>::success(context.outputOptions.contains(arguments[0]));
54 }
55 if (name == "SHADER_NAME_CONTAINS") return Result<bool>::success(contains(context.shaderName, arguments));
56 if (name == "MATERIAL_NAME_CONTAINS") return Result<bool>::success(contains(context.materialName, arguments));
57 if (name == "MATERIAL_FLOAT_EQUALS") {
58 if (arguments.size() != 2)
60 "float predicate requires property and value", {}, {},
61 "asset.import.vegetation-preset"));
62 char* end = nullptr;
63 errno = 0;
64 const double value = std::strtod(arguments[1].c_str(), &end);
65 if (errno != 0 || end != arguments[1].c_str() + arguments[1].size() || !std::isfinite(value))
67 "float predicate value is invalid", {}, {},
68 "asset.import.vegetation-preset"));
69 const auto found = context.materialFloats.find(arguments[0]);
70 return Result<bool>::success(found != context.materialFloats.end() && found->second == value);
71 }
72 if (arguments.size() != 1 && name != "SHADER_PIPELINE_IS_HD" && name != "SHADER_PIPELINE_IS_STANDARD" &&
73 name != "SHADER_PIPELINE_IS_UNIVERSAL")
75 "preset predicate requires one argument", std::string(name), {},
76 "asset.import.vegetation-preset"));
77 if (name == "MATERIAL_KEYWORD_ENABLED" || name == "MATERIAL_HAS_KEYWORD")
78 return Result<bool>::success(context.materialKeywords.contains(arguments[0]));
79 if (name == "MATERIAL_HAS_PROP") return Result<bool>::success(context.materialProperties.contains(arguments[0]));
80 if (name == "MATERIAL_HAS_TEX") return Result<bool>::success(context.materialTextures.contains(arguments[0]));
81 if (!arguments.empty())
83 "pipeline predicate takes no arguments", std::string(name), {},
84 "asset.import.vegetation-preset"));
85 if (name == "SHADER_PIPELINE_IS_HD") return Result<bool>::success(context.shaderPipeline == "HD");
86 if (name == "SHADER_PIPELINE_IS_STANDARD") return Result<bool>::success(context.shaderPipeline == "Standard");
87 if (name == "SHADER_PIPELINE_IS_UNIVERSAL") return Result<bool>::success(context.shaderPipeline == "Universal");
88 return Result<bool>::failure(Diagnostic::error(DiagnosticCode::Unsupported, "unknown TVE preset predicate",
89 std::string(name), {}, "asset.import.vegetation-preset"));
90}
91
92struct Evaluator {
93 const std::map<std::string, Value>& definitions;
94 const VegetationPresetContext& context;
95 std::set<std::string> active;
96 std::vector<VegetationPresetCommand> commands;
97
98 Result<void> statements(const Value::Array& values, const std::string& sourcePath) {
99 for (const auto& value : values) {
100 const auto* object = value.getIf<Value::Object>();
101 const auto* kind = object ? member(*object, "kind") : nullptr;
102 if (!object || !kind || !kind->isString())
104 "preset statement is malformed", sourcePath, {},
105 "asset.import.vegetation-preset"));
106 if (kind->asString() == "command") {
107 const auto* domain = member(*object, "domain");
108 const auto* operation = member(*object, "operation");
109 auto arguments = strings(member(*object, "arguments"), sourcePath);
110 if (!domain || !domain->isString() || !operation || !operation->isString() || !arguments)
112 "preset command is malformed", sourcePath, {},
113 "asset.import.vegetation-preset"));
114 if (domain->asString() == "Include") {
115 auto include = evaluate(joined(operation->asString(), arguments.value()));
116 if (!include) return include;
117 } else {
118 commands.push_back(
119 {domain->asString(), operation->asString(), std::move(arguments).takeValue(), sourcePath});
120 }
121 continue;
122 }
123 if (kind->asString() != "condition")
125 "unknown preset statement kind", sourcePath, {},
126 "asset.import.vegetation-preset"));
127 const auto* name = member(*object, "predicate");
128 const auto* negated = member(*object, "negated");
129 const auto* body = member(*object, "statements");
130 auto arguments = strings(member(*object, "arguments"), sourcePath);
131 if (!name || !name->isString() || !negated || !negated->isBool() || !body || !body->isArray() || !arguments)
133 "preset condition is malformed", sourcePath, {},
134 "asset.import.vegetation-preset"));
135 auto result = predicate(name->asString(), arguments.value(), context);
136 if (!result) return Result<void>::failure(result.status());
137 if (result.value() != negated->asBool()) {
138 auto nested = statements(*body->getIf<Value::Array>(), sourcePath);
139 if (!nested) return nested;
140 }
141 }
142 return Result<void>::success();
143 }
144
145 Result<void> evaluate(const std::string& name) {
146 auto found = definitions.find(name);
147 if (found == definitions.end() && name == "Use Default Flower Masks")
148 found = definitions.find("Use Default Flowers Masks");
149 if (found == definitions.end() && name == "Use Default Flower Settings")
150 found = definitions.find("Use Default Flowers Settings");
151 if (found == definitions.end())
152 return Result<void>::failure(Diagnostic::error(DiagnosticCode::NotFound, "TVE preset include is missing",
153 name, {}, "asset.import.vegetation-preset"));
154 if (!active.insert(name).second)
155 return Result<void>::failure(Diagnostic::error(DiagnosticCode::Conflict, "TVE preset include cycle", name,
156 {}, "asset.import.vegetation-preset"));
157 const auto* root = found->second.getIf<Value::Object>();
158 const auto* schema = root ? member(*root, "schema") : nullptr;
159 const auto* version = root ? member(*root, "schemaVersion") : nullptr;
160 const auto* source = root ? member(*root, "sourcePath") : nullptr;
161 const auto* body = root ? member(*root, "statements") : nullptr;
162 if (!root || !schema || !schema->isString() || schema->asString() != "eve.vegetation-conversion-preset" ||
163 !version || !version->isInt64() || version->asInt() != 1 || !source || !source->isString() || !body ||
164 !body->isArray())
166 "TVE preset definition is malformed", name, {},
167 "asset.import.vegetation-preset"));
168 auto result = statements(*body->getIf<Value::Array>(), source->asString());
169 active.erase(name);
170 return result;
171 }
172};
173
174} // namespace
175
176Result<std::vector<VegetationPresetCommand>> evaluateVegetationPreset(const std::map<std::string, Value>& definitions,
177 std::string_view root,
179 Evaluator evaluator{definitions, context};
180 auto result = evaluator.evaluate(std::string(root));
181 if (!result) return Result<std::vector<VegetationPresetCommand>>::failure(result.status());
182 return Result<std::vector<VegetationPresetCommand>>::success(std::move(evaluator.commands));
183}
184
185} // namespace eve::asset_import
ActionParameterOperation operation
double value
bool & active
int root
Definition AnimSmr.cpp:119
std::map< std::string, Var > values
std::string text
TokenKind kind
std::string name
std::string path
Definition PlayHost.cpp:110
bool found
std::string sourcePath
float size
Definition TreeMesh.cpp:156
float(ui::Theme::* member)[4]
std::string body
const UnitySourceAsset & source
std::uint64_t statements
std::vector< VegetationPresetCommand > commands
const VegetationPresetContext & context
const std::map< std::string, Value > & definitions
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
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
Result< std::vector< VegetationPresetCommand > > evaluateVegetationPreset(const std::map< std::string, Value > &definitions, std::string_view root, const VegetationPresetContext &context)
Decode, resolve and evaluate a library of canonical TVE preset definitions.
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
std::vector< OnnxNamedTensor > evaluate(const ModelData &, std::span< const OnnxNamedTensor >, const std::vector< std::string > &, OnnxCompute *, OnnxRunOptions options)
Evaluate.
Immutable source facts used by TVE preset predicates.
std::map< std::string, double > materialFloats