auto-git:

[add] src/geometry/model-instance-collider-generation.ts
 [add] src/runtime-three/rapier-collision-world.ts
 [change] AGENTS.md
 [change] CHAT_CONTEXT.md
 [change] architecture.md
 [change] package.json
 [change] prompts-lite.txt
 [change] prompts.txt
 [change] roadmap.md
 [change] src/assets/model-instances.ts
 [change] src/document/migrate-scene-document.ts
 [change] src/document/scene-document-validation.ts
 [change] src/document/scene-document.ts
 [change] src/runtime-three/first-person-navigation-controller.ts
 [change] src/runtime-three/navigation-controller.ts
 [change] src/runtime-three/runtime-host.ts
 [change] src/runtime-three/runtime-scene-build.ts
 [change] src/runtime-three/runtime-scene-validation.ts
 [change] src/viewport-three/viewport-host.ts
 [change] testing.md
This commit is contained in:
2026-04-04 07:51:38 +02:00
parent d82e37861e
commit 3d1dd3fe63
20 changed files with 1553 additions and 31 deletions

View File

@@ -1,3 +1,5 @@
import type { LoadedModelAsset } from "../assets/gltf-model-import";
import { getModelInstances } from "../assets/model-instances";
import type { SceneDocument } from "../document/scene-document";
import {
assertSceneDocumentIsValid,
@@ -6,6 +8,7 @@ import {
type SceneDiagnostic
} from "../document/scene-document-validation";
import { getPrimaryPlayerStartEntity } from "../entities/entity-instances";
import { buildGeneratedModelCollider, ModelColliderGenerationError } from "../geometry/model-instance-collider-generation";
export interface RuntimeSceneBuildValidationResult {
diagnostics: SceneDiagnostic[];
@@ -13,13 +16,18 @@ export interface RuntimeSceneBuildValidationResult {
warnings: SceneDiagnostic[];
}
interface ValidateRuntimeSceneBuildOptions {
navigationMode: "firstPerson" | "orbitVisitor";
loadedModelAssets?: Record<string, LoadedModelAsset>;
}
export function validateRuntimeSceneBuild(
document: SceneDocument,
navigationMode: "firstPerson" | "orbitVisitor"
options: ValidateRuntimeSceneBuildOptions
): RuntimeSceneBuildValidationResult {
const diagnostics: SceneDiagnostic[] = [];
if (navigationMode === "firstPerson" && getPrimaryPlayerStartEntity(document.entities) === null) {
if (options.navigationMode === "firstPerson" && getPrimaryPlayerStartEntity(document.entities) === null) {
diagnostics.push(
createDiagnostic(
"error",
@@ -31,6 +39,39 @@ export function validateRuntimeSceneBuild(
);
}
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"),
@@ -38,10 +79,10 @@ export function validateRuntimeSceneBuild(
};
}
export function assertRuntimeSceneBuildable(document: SceneDocument, navigationMode: "firstPerson" | "orbitVisitor") {
export function assertRuntimeSceneBuildable(document: SceneDocument, options: ValidateRuntimeSceneBuildOptions) {
assertSceneDocumentIsValid(document);
const validation = validateRuntimeSceneBuild(document, navigationMode);
const validation = validateRuntimeSceneBuild(document, options);
if (validation.errors.length > 0) {
throw new Error(`Runtime build is blocked: ${formatSceneDiagnosticSummary(validation.errors)}`);