载入中...
搜索中...
未找到
UnityCollection.cpp
浏览该文件的文档.
2
5
6#include <regex>
7
8namespace eve::asset_import {
9namespace {
10
11Result<void> mergeImport(PreparedAssetImport& output, PreparedAssetImport input, const UnitySourceAsset& source,
12 const AssetImportLimits& limits) {
13 if (input.manifest.assets.size() > limits.maximumAssets ||
14 output.manifest.assets.size() > limits.maximumAssets - input.manifest.assets.size())
16 DiagnosticCode::InvalidArgument, "Unity imported asset count exceeds budget", {}, {}, "asset.import"));
17 for (auto& asset : input.manifest.assets) output.manifest.assets.push_back(std::move(asset));
18 for (auto& dependency : input.manifest.dependencies) output.manifest.dependencies.push_back(std::move(dependency));
19 for (auto& entry : input.entries)
20 if (entry.path != "reports/import.json") output.entries.push_back(std::move(entry));
21 for (auto& mapping : input.sourceMappings) {
22 mapping.sourceObject = "unity:" + source.guid + "/" + mapping.sourceObject;
23 output.sourceMappings.push_back(std::move(mapping));
24 }
25 for (auto& finding : input.findings) {
26 finding.sourcePath = source.path;
27 output.findings.push_back(std::move(finding));
28 }
29 for (const auto& [name, entry] : input.manifest.entrypoints)
30 output.manifest.entrypoints.emplace(source.path + (name == "default" ? "" : "#" + name), entry);
31 return Result<void>::success();
32}
33
34Result<PreparedAssetImport> importSource(const UnityProjectImportRequest& request, const UnitySourceAsset& source) {
35 if (source.guid.empty())
37 DiagnosticCode::Unsupported, "a .meta GUID is required for stable collection asset identity", source.path,
38 {}, "asset.import"));
39 const auto ext = detail::extension(source.path);
40 if (ext == "anim") return prepareUnitySpriteAnimation(request, source);
41 if (ext == "asset") {
42 const auto& bytes = request.files.at(source.path);
43 const std::string_view text(reinterpret_cast<const char*>(bytes.data()), bytes.size());
44 if (text.find("\nTexture2D:") != std::string_view::npos) return prepareUnityNativeTexture(request, source);
45 if (text.find("\nTexture3D:") != std::string_view::npos)
48 }
49 if (ext == "fbx") return prepareUnityFbx(request, source);
50 if (ext == "tvepreset") return prepareUnityVegetationPreset(request, source);
53 auto identity = request.package;
54 identity.packageId = request.package.packageId.child("unity:" + source.guid);
55 if (ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "tif" || ext == "tiff" || ext == "tga") {
56 const auto& meta = request.files.at(source.path + ".meta");
57 const std::string text(meta.begin(), meta.end());
58 const std::regex srgb(R"((?:^|\n)\s*sRGBTexture:\s*0(?:\s|$))");
59 const std::regex normal(R"((?:^|\n)\s*textureType:\s*1(?:\s|$))");
60 const bool normalMap = std::regex_search(text, normal);
61 const bool linear = normalMap || std::regex_search(text, srgb);
62 auto result = prepareImageImport({identity, "unity:" + source.guid, request.files.at(source.path),
64 normalMap ? "normal" : "color", request.limits});
65 if (!result) return result;
66 if (std::regex_search(text, std::regex(R"((?:^|\n)\s*spriteMode:\s*[12](?:\s|$))")))
67 result.value().findings.push_back({source.path, "TextureImporter.sprite", ImportDisposition::Unsupported,
68 "standalone Sprite/UI assets are not emitted; converted sprite "
69 "animation clips retain their referenced slicing and pivots"});
70 if (normalMap)
71 result.value().findings.push_back(
72 {source.path, "TextureImporter.normal", ImportDisposition::Unsupported,
73 "source normal pixels are linear; Unity normal processing settings are not baked"});
74 return result;
75 }
76 if (ext == "gltf" || ext == "glb") {
77 std::map<std::string, std::vector<std::uint8_t>> external;
78 const auto slash = source.path.find_last_of('/');
79 const auto prefix = slash == std::string::npos ? std::string{} : source.path.substr(0, slash + 1);
80 for (const auto& [path, bytes] : request.files)
81 if (path.starts_with(prefix) && path != source.path && !path.ends_with(".meta"))
82 external.emplace(path.substr(prefix.size()), bytes);
83 auto result = prepareGltfImport(
84 {identity, "unity:" + source.guid, request.files.at(source.path), std::move(external), request.limits});
85 if (!result) return result;
86 result.value().findings.push_back(
87 {source.path, "Model.rendering", ImportDisposition::Unsupported,
88 "mesh primitives imported; materials, skinning, animation and scene binding are not converted"});
89 return result;
90 }
93 }
96 "source retained; this Unity resource type does not yet have a canonical converter",
97 source.path, {}, "asset.import"));
98}
99} // namespace
100
102 const UnitySourceIndex& index) {
103 auto manifest = detail::baseManifest(request.package, "eve.unity-collection/1");
104 if (!manifest) return Result<PreparedAssetImport>::failure(manifest.status());
106 out.manifest = std::move(manifest).takeValue();
107 out.findings = index.findings;
109 std::uint64_t expandedBytes = 0;
110 for (const auto& source : index.assets) {
111 if (source.kind != UnitySourceKind::Prefab) continue;
112 const auto& bytes = request.files.at(source.path);
113 if (std::string(bytes.begin(), bytes.end()).find("!u!1001 ") == std::string::npos) continue;
114 auto expanded = expandUnityPrefab(request, index, source);
115 if (!expanded) return Result<PreparedAssetImport>::failure(expanded.status());
116 out.findings.insert(out.findings.end(), expanded.value().findings.begin(), expanded.value().findings.end());
117 if (expanded.value().bytes.size() > request.limits.maximumDecodedBytes ||
118 expandedBytes > request.limits.maximumDecodedBytes - expanded.value().bytes.size())
120 DiagnosticCode::InvalidArgument, "aggregate Prefab expansion budget exceeded", {}, {}, "asset.import"));
121 expandedBytes += expanded.value().bytes.size();
122 resolved.files[source.path] = std::move(expanded).takeValue().bytes;
123 }
124 for (const auto& source : index.assets) {
125 if (source.kind == UnitySourceKind::Folder) continue;
126 auto imported = importSource(resolved, source);
127 if (!imported) {
128 const auto* error = imported.status().primaryDiagnostic();
129 const bool missingMaterialDependency =
130 error && error->code() == DiagnosticCode::NotFound &&
132 if (!error || (error->code() != DiagnosticCode::Unsupported && !missingMaterialDependency))
134 out.findings.push_back(
135 {source.path, missingMaterialDependency ? "resource.dependency" : "resource.conversion",
137 continue;
138 }
139 auto merged = mergeImport(out, std::move(imported).takeValue(), source, request.limits);
140 if (!merged) return Result<PreparedAssetImport>::failure(merged.status());
141 }
142 if (out.manifest.assets.empty())
145 "Unity collection has no convertible assets; use asset scan to inspect all resource types", {}, {},
146 "asset.import"));
147 auto bindings = bindUnityRenderers(resolved, index, out);
149 Value::Object sourceHashes;
150 for (const auto& [path, data] : request.files) {
151 out.entries.push_back({"sources/unity/" + path, data});
152 sourceHashes[path] = Value(detail::sha256(data));
153 if (!path.ends_with(".meta"))
154 out.findings.push_back(
155 {path, "source.archive", ImportDisposition::PreservedSource,
156 "original source and available .meta retained under sources/unity; not runtime conversion"});
157 }
158 out.manifest.provenance["sourceCoordinateSystem"] = Value("left-handed-x-right-y-up-z-forward");
159 std::uint64_t total = 0;
160 for (const auto& entry : out.entries) {
161 if (entry.bytes.size() > request.limits.maximumDecodedBytes ||
162 total > request.limits.maximumDecodedBytes - entry.bytes.size())
164 DiagnosticCode::InvalidArgument, "Unity prepared output exceeds byte budget", {}, {}, "asset.import"));
165 total += entry.bytes.size();
166 }
167 auto report = detail::finalizeImportReport(out, request.package, "unity", "source-files",
168 {{"sourceHashes", Value(std::move(sourceHashes))}});
169 if (!report) return Result<PreparedAssetImport>::failure(report.status());
170 if (out.entries.back().bytes.size() > request.limits.maximumDecodedBytes ||
171 total > request.limits.maximumDecodedBytes - out.entries.back().bytes.size())
173 Diagnostic::error(DiagnosticCode::InvalidArgument, "Unity import report exceeds prepared output budget", {},
174 {}, "asset.import"));
175 return Result<PreparedAssetImport>::success(std::move(out));
176}
177} // namespace eve::asset_import
std::string output
std::unordered_map< std::string, QuestRuntime > entries
EvpackChunkInput input
Definition Evpack.cpp:170
const GltfImportRequest & request
std::string text
std::string imported
std::uint64_t bytes
std::string name
Texture * normal
std::vector< std::shared_ptr< DeviceBytes > > bindings
Definition OnnxGpgpu.cpp:38
std::string error
Definition Package.cpp:60
std::string path
Definition PlayHost.cpp:110
float size
Definition TreeMesh.cpp:156
Direct Unity text-serialization adapter for TerrainData and Prefab assets.
std::vector< ImportFinding > findings
uint32_t index
const UnitySourceAsset & source
const AssetImportLimits & limits
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
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.
std::string extension(std::string_view name)
Extension.
EVENGINE_API_PLATFORM Result< void > finalizeImportReport(PreparedAssetImport &prepared, const ImportPackageIdentity &package, std::string_view sourceEngine, std::string_view sourceVersion, Value::Object options={})
Append the deterministic mandatory import report and bind it from provenance.
Result< asset::EvaManifest > baseManifest(const ImportPackageIdentity &package, std::string_view importer)
Base manifest.
Result< PreparedAssetImport > prepareUnityPrefab(const UnityProjectImportRequest &request, const std::string &path)
Prepare one prefab without copying or re-indexing the source collection.
Result< PreparedAssetImport > prepareUnityMaterial(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Dispatch built-in Standard and admitted vegetation materials to canonical PBR data.
Result< PreparedAssetImport > prepareUnityCollection(const UnityProjectImportRequest &request, const UnitySourceIndex &index)
Prepare an owning collection candidate using a validated source index.
Result< PreparedAssetImport > prepareUnityVegetationScene(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Convert a complete TVE manager component set from one Unity scene.
Result< PreparedAssetImport > prepareUnityNativeVolumeTexture(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Convert embedded linear R8 Unity Texture3D to an owning canonical volume candidate.
EVENGINE_API_PLATFORM Result< PreparedAssetImport > prepareUnityVegetationPreset(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Parse one TVE conversion preset into a bounded versioned command tree.
ImageColorSpace
Explicit source color semantics; importers never infer platform defaults.
Result< PreparedAssetImport > prepareUnityNativeTexture(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Convert embedded BC3 text Texture2D to an owning image candidate.
Result< PreparedAssetImport > prepareUnitySpriteAnimation(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Convert an explicit SpriteRenderer timeline and referenced metadata into an owning canonical candidat...
Result< PreparedAssetImport > prepareUnityFbx(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Convert a static FBX with explicit Unity importer settings and hashed subasset identities.
Definition UnityFbx.cpp:210
Result< UnityExpandedPrefab > expandUnityPrefab(const UnityProjectImportRequest &request, const UnitySourceIndex &index, const UnitySourceAsset &source)
Resolve bounded nested prefab references into an unpublished owning text candidate.
Result< void > bindUnityRenderers(const UnityProjectImportRequest &request, const UnitySourceIndex &index, PreparedAssetImport &out)
Resolve renderer references after all collection assets are prepared; unpublished candidate only.
EVENGINE_API_PLATFORM Result< PreparedAssetImport > prepareImageImport(const ImageImportRequest &request)
Decode image metadata and prepare one canonical eve.image source asset.
Result< PreparedAssetImport > prepareUnityNativeMesh(const UnityProjectImportRequest &request, const UnitySourceAsset &source)
Decode a bounded static Unity text Mesh into owning canonical submesh candidates.
EVENGINE_API_PLATFORM Result< PreparedAssetImport > prepareGltfImport(const GltfImportRequest &request)
Decode triangle primitives from glTF 2.0 into canonical typed mesh blobs.
std::vector< EvaAssetEntry > assets
Definition EvaManifest.h:69
Value::Object provenance
Definition EvaManifest.h:72
Owning, validated source archive candidate not yet published to disk/database.
std::vector< ImportFinding > findings
std::vector< asset::EvaArchiveEntry > entries
In-memory Unity project slice; keys are normalized project-relative paths.
std::map< std::string, std::vector< std::uint8_t > > files
Owning deterministic index sorted by path, plus missing-reference diagnostics.
Definition UnitySource.h:47