载入中...
搜索中...
未找到
UnityVegetationPreset.cpp
浏览该文件的文档.
4
5#include <cctype>
6
7namespace eve::asset_import {
8namespace {
9
10std::string_view trim(std::string_view value) {
11 while (!value.empty() && std::isspace(static_cast<unsigned char>(value.front()))) value.remove_prefix(1);
12 while (!value.empty() && std::isspace(static_cast<unsigned char>(value.back()))) value.remove_suffix(1);
13 return value;
14}
15
16Value::Array words(std::string_view value) {
17 Value::Array result;
18 while (!value.empty()) {
19 const auto split = value.find_first_of(" \t");
20 result.emplace_back(std::string(value.substr(0, split)));
21 if (split == std::string_view::npos) break;
22 value.remove_prefix(split);
23 value = trim(value);
24 }
25 return result;
26}
27
28struct Parser {
29 const UnitySourceAsset& source;
30 const AssetImportLimits& limits;
31 std::vector<std::string_view> lines;
32 std::size_t at = 0;
33 std::uint64_t statements = 0;
34 std::uint32_t depth = 0;
35 std::uint32_t recoveredConditionTypos = 0;
36
37 Result<Value::Array> block(bool nested) {
38 if (++depth > 64)
40 "TVE preset condition nesting exceeds budget",
41 source.path, {}, "asset.import.unity"));
42 Value::Array result;
43 while (at < lines.size()) {
44 auto line = trim(lines[at++]);
45 if (line.empty() || line.starts_with("//") || line.front() == '*') continue;
46 if (line == "}") {
47 --depth;
48 if (!nested)
50 "unexpected TVE preset closing brace",
51 source.path, {}, "asset.import.unity"));
52 return Result<Value::Array>::success(std::move(result));
53 }
54 if (++statements > limits.maximumAssets * 64ull)
56 "TVE preset statement count exceeds budget",
57 source.path, {}, "asset.import.unity"));
58 if (line.starts_with("if ") || line.starts_with("f ")) {
59 const bool recoveredTypo = line.starts_with("f ");
60 if (recoveredTypo) ++recoveredConditionTypos;
61 auto tokens = words(trim(line.substr(recoveredTypo ? 2 : 3)));
62 if (tokens.empty() || at >= lines.size() || trim(lines[at++]) != "{")
64 Diagnostic::error(DiagnosticCode::ParseError, "TVE preset condition requires a following block",
65 source.path, {}, "asset.import.unity"));
66 auto body = block(true);
67 if (!body) return body;
68 auto predicate = tokens.front().asString();
69 const bool negated = !predicate.empty() && predicate.front() == '!';
70 if (negated) predicate.erase(predicate.begin());
71 tokens.erase(tokens.begin());
72 result.emplace_back(Value::Object{{"kind", Value("condition")},
73 {"predicate", Value(predicate)},
74 {"negated", Value(negated)},
75 {"arguments", Value(std::move(tokens))},
76 {"statements", Value(std::move(body).takeValue())}});
77 continue;
78 }
79 if (line == "{")
81 "unexpected TVE preset opening brace",
82 source.path, {}, "asset.import.unity"));
83 const auto split = line.find_first_of(" \t");
84 const auto domain = line.substr(0, split);
85 auto remainder = split == std::string_view::npos ? std::string_view{} : trim(line.substr(split));
86 const auto operationSplit = remainder.find_first_of(" \t");
87 const auto operation = remainder.substr(0, operationSplit);
88 auto arguments = operationSplit == std::string_view::npos ? Value::Array{}
89 : words(trim(remainder.substr(operationSplit)));
90 result.emplace_back(Value::Object{{"kind", Value("command")},
91 {"domain", Value(std::string(domain))},
92 {"operation", Value(std::string(operation))},
93 {"arguments", Value(std::move(arguments))}});
94 }
95 --depth;
96 if (nested)
98 "unterminated TVE preset condition block",
99 source.path, {}, "asset.import.unity"));
100 return Result<Value::Array>::success(std::move(result));
101 }
102};
103
104} // namespace
105
107 const UnitySourceAsset& source) {
108 const auto& bytes = request.files.at(source.path);
109 const std::string_view raw(reinterpret_cast<const char*>(bytes.data()), bytes.size());
112 "TVE preset must be bounded UTF-8 text",
113 source.path, {}, "asset.import.unity"));
114 std::string_view text = raw;
115 if (text.starts_with("\xef\xbb\xbf")) text.remove_prefix(3);
116 Parser parser{source, request.limits};
117 for (std::size_t begin = 0; begin <= text.size();) {
118 auto end = text.find('\n', begin);
119 if (end == std::string_view::npos) end = text.size();
120 auto line = text.substr(begin, end - begin);
121 if (!line.empty() && line.back() == '\r') line.remove_suffix(1);
124 "TVE preset line exceeds string budget",
125 source.path, {}, "asset.import.unity"));
126 parser.lines.push_back(line);
127 if (end == text.size()) break;
128 begin = end + 1;
129 }
130 auto statements = parser.block(false);
132 auto manifest = detail::baseManifest(request.package, "eve.unity-tve-preset/1");
133 if (!manifest) return Result<PreparedAssetImport>::failure(manifest.status());
134 const auto id = request.package.packageId.child("unity:" + source.guid).child("vegetation-preset:default");
135 auto reference = detail::assetRef(id);
137 Value definition(Value::Object{{"schema", Value("eve.vegetation-conversion-preset")},
138 {"schemaVersion", Value(std::int64_t(1))},
139 {"sourcePath", Value(source.path)},
140 {"statements", Value(std::move(statements).takeValue())}});
141 auto json = definition.toJson();
142 if (!json) return Result<PreparedAssetImport>::failure(json.status());
143 std::vector<std::uint8_t> encoded(json.value().begin(), json.value().end());
144 const std::string path = "assets/" + id.format() + "/asset.json";
146 output.manifest = std::move(manifest).takeValue();
147 output.manifest.assets.push_back({reference.value(),
148 "eve.vegetation-conversion-preset",
149 SchemaVersion(1),
150 path,
151 detail::sha256(encoded),
152 {"vegetation", "conversion-preset", "source:unity"}});
153 output.manifest.entrypoints.emplace("default", reference.value());
154 output.entries.push_back({path, std::move(encoded)});
155 output.sourceMappings.push_back({"preset", reference.value()});
156 output.findings.push_back({source.path, "TVE.preset.syntax", ImportDisposition::Translated,
157 "commands, include directives and conditional blocks parsed into a versioned tree"});
158 if (parser.recoveredConditionTypos)
159 output.findings.push_back({source.path, "TVE.preset.conditionTypo", ImportDisposition::Translated,
160 "source 'f' condition typo interpreted as 'if' without changing its predicate"});
162}
163
164} // namespace eve::asset_import
ActionParameterOperation operation
double value
std::string output
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
bool split
Definition CaveMesh.cpp:123
const GltfImportRequest & request
std::unordered_map< const Graphics *, std::shared_ptr< Lifetime > > tokens
std::string text
std::uint64_t bytes
std::string path
Definition PlayHost.cpp:110
float begin
std::string body
Direct Unity text-serialization adapter for TerrainData and Prefab assets.
std::vector< std::string_view > lines
const UnitySourceAsset & source
std::uint32_t depth
std::uint64_t statements
std::uint32_t recoveredConditionTypos
const AssetImportLimits & limits
std::size_t at
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
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
Id128 child(std::string_view role) const noexcept
Derives a deterministic child UUID for a hierarchical identity.
Definition Identity.h:192
std::string sha256(std::span< const std::uint8_t > bytes)
Sha 256.
Result< asset::EvaManifest > baseManifest(const ImportPackageIdentity &package, std::string_view importer)
Base manifest.
Result< AssetRef > assetRef(PersistentId id)
Asset ref.
EVENGINE_API_PLATFORM Result< PreparedAssetImport > prepareUnityVegetationPreset(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Parse one TVE conversion preset into a bounded versioned command tree.
detail::StrongUint64< detail::SchemaVersionTag > SchemaVersion
Persistent data-format version; not a runtime replacement generation.
bool isValidUtf8(std::string_view text, Utf8NullPolicy nullPolicy) noexcept
Validate shortest-form UTF-8, Unicode scalar range and optional NUL exclusion.
std::vector< EvaAssetEntry > assets
Definition EvaManifest.h:69
Owning, validated source archive candidate not yet published to disk/database.
In-memory Unity project slice; keys are normalized project-relative paths.
Immutable-by-convention owning source index entry; no borrowed source addresses.
Definition UnitySource.h:38