43 lines
2.6 KiB
JavaScript
43 lines
2.6 KiB
JavaScript
|
|
import { getModelInstances } from "../assets/model-instances";
|
||
|
|
import { assertSceneDocumentIsValid, createDiagnostic, formatSceneDiagnosticSummary } from "../document/scene-document-validation";
|
||
|
|
import { getPrimaryPlayerStartEntity } from "../entities/entity-instances";
|
||
|
|
import { buildGeneratedModelCollider, ModelColliderGenerationError } from "../geometry/model-instance-collider-generation";
|
||
|
|
export function validateRuntimeSceneBuild(document, options) {
|
||
|
|
const diagnostics = [];
|
||
|
|
if (options.navigationMode === "firstPerson" && getPrimaryPlayerStartEntity(document.entities) === null) {
|
||
|
|
diagnostics.push(createDiagnostic("error", "missing-player-start", "First-person run requires an authored Player Start. Place one or switch to Orbit Visitor.", "entities", "build"));
|
||
|
|
}
|
||
|
|
for (const modelInstance of getModelInstances(document.modelInstances)) {
|
||
|
|
const path = `modelInstances.${modelInstance.id}.collision.mode`;
|
||
|
|
const asset = document.assets[modelInstance.assetId];
|
||
|
|
if (modelInstance.collision.mode === "none" || asset === undefined || asset.kind !== "model") {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const generatedCollider = buildGeneratedModelCollider(modelInstance, asset, options.loadedModelAssets?.[modelInstance.assetId]);
|
||
|
|
if (generatedCollider?.mode === "dynamic") {
|
||
|
|
diagnostics.push(createDiagnostic("warning", "dynamic-model-collider-fixed-query-only", "Dynamic model collision currently generates convex compound pieces for Rapier queries, but the runner still uses them as fixed world collision rather than fully simulated rigid bodies.", path, "build"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (error) {
|
||
|
|
const message = error instanceof Error ? error.message : "Imported model collision generation failed.";
|
||
|
|
const code = error instanceof ModelColliderGenerationError
|
||
|
|
? error.code
|
||
|
|
: "invalid-model-instance-collision-mode";
|
||
|
|
diagnostics.push(createDiagnostic("error", code, message, path, "build"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
diagnostics,
|
||
|
|
errors: diagnostics.filter((diagnostic) => diagnostic.severity === "error"),
|
||
|
|
warnings: diagnostics.filter((diagnostic) => diagnostic.severity === "warning")
|
||
|
|
};
|
||
|
|
}
|
||
|
|
export function assertRuntimeSceneBuildable(document, options) {
|
||
|
|
assertSceneDocumentIsValid(document);
|
||
|
|
const validation = validateRuntimeSceneBuild(document, options);
|
||
|
|
if (validation.errors.length > 0) {
|
||
|
|
throw new Error(`Runtime build is blocked: ${formatSceneDiagnosticSummary(validation.errors)}`);
|
||
|
|
}
|
||
|
|
}
|