auto-git:
[unlink] playwright.config.js [unlink] src/app/App.js [unlink] src/app/editor-store.js [unlink] src/app/use-editor-store.js [unlink] src/assets/audio-assets.js [unlink] src/assets/gltf-model-import.js [unlink] src/assets/image-assets.js [unlink] src/assets/model-instance-labels.js [unlink] src/assets/model-instance-rendering.js [unlink] src/assets/model-instances.js [unlink] src/assets/project-asset-storage.js [unlink] src/assets/project-assets.js [unlink] src/commands/brush-command-helpers.js [unlink] src/commands/command-history.js [unlink] src/commands/command.js [unlink] src/commands/commit-transform-session-command.js [unlink] src/commands/create-box-brush-command.js [unlink] src/commands/delete-box-brush-command.js [unlink] src/commands/delete-entity-command.js [unlink] src/commands/delete-interaction-link-command.js [unlink] src/commands/delete-model-instance-command.js [unlink] src/commands/duplicate-selection-command.js [unlink] src/commands/import-audio-asset-command.js [unlink] src/commands/import-background-image-asset-command.js [unlink] src/commands/import-model-asset-command.js [unlink] src/commands/move-box-brush-command.js [unlink] src/commands/resize-box-brush-command.js [unlink] src/commands/rotate-box-brush-command.js [unlink] src/commands/set-box-brush-face-material-command.js [unlink] src/commands/set-box-brush-face-uv-state-command.js [unlink] src/commands/set-box-brush-name-command.js [unlink] src/commands/set-box-brush-transform-command.js [unlink] src/commands/set-box-brush-volume-settings-command.js [unlink] src/commands/set-entity-name-command.js [unlink] src/commands/set-model-instance-name-command.js [unlink] src/commands/set-player-start-command.js [unlink] src/commands/set-scene-name-command.js [unlink] src/commands/set-world-settings-command.js [unlink] src/commands/upsert-entity-command.js [unlink] src/commands/upsert-interaction-link-command.js [unlink] src/commands/upsert-model-instance-command.js [unlink] src/core/ids.js [unlink] src/core/selection.js [unlink] src/core/tool-mode.js [unlink] src/core/transform-session.js [unlink] src/core/vector.js [unlink] src/core/whitebox-selection-feedback.js [unlink] src/core/whitebox-selection-mode.js [unlink] src/document/brushes.js [unlink] src/document/migrate-scene-document.js [unlink] src/document/scene-document-validation.js [unlink] src/document/scene-document.js [unlink] src/document/world-settings.js [unlink] src/entities/entity-instances.js [unlink] src/entities/entity-labels.js [unlink] src/geometry/box-brush-components.js [unlink] src/geometry/box-brush-mesh.js [unlink] src/geometry/box-brush.js [unlink] src/geometry/box-face-uvs.js [unlink] src/geometry/grid-snapping.js [unlink] src/geometry/model-instance-collider-debug-mesh.js [unlink] src/geometry/model-instance-collider-generation.js [unlink] src/interactions/interaction-links.js [unlink] src/main.js [unlink] src/materials/starter-material-library.js [unlink] src/materials/starter-material-textures.js [unlink] src/rendering/advanced-rendering.js [unlink] src/rendering/fog-material.js [unlink] src/rendering/planar-reflection.js [unlink] src/rendering/water-material.js [unlink] src/runner-web/RunnerCanvas.js [unlink] src/runtime-three/first-person-navigation-controller.js [unlink] src/runtime-three/navigation-controller.js [unlink] src/runtime-three/orbit-visitor-navigation-controller.js [unlink] src/runtime-three/player-collision.js [unlink] src/runtime-three/rapier-collision-world.js [unlink] src/runtime-three/runtime-audio-system.js [unlink] src/runtime-three/runtime-host.js [unlink] src/runtime-three/runtime-interaction-system.js [unlink] src/runtime-three/runtime-scene-build.js [unlink] src/runtime-three/runtime-scene-validation.js [unlink] src/runtime-three/underwater-fog.js [unlink] src/serialization/local-draft-storage.js [unlink] src/serialization/scene-document-json.js [unlink] src/shared-ui/HierarchicalMenu.js [unlink] src/shared-ui/Panel.js [unlink] src/shared-ui/world-background-style.js [unlink] src/viewport-three/ViewportCanvas.js [unlink] src/viewport-three/ViewportPanel.js [unlink] src/viewport-three/viewport-entity-markers.js [unlink] src/viewport-three/viewport-focus.js [unlink] src/viewport-three/viewport-host.js [unlink] src/viewport-three/viewport-layout.js [unlink] src/viewport-three/viewport-transient-state.js [unlink] src/viewport-three/viewport-view-modes.js [unlink] vite.config.js [unlink] vitest.config.js
This commit is contained in:
@@ -1,189 +0,0 @@
|
||||
import { createOpaqueId } from "../core/ids";
|
||||
export const INTERACTION_TRIGGER_KINDS = ["enter", "exit", "click"];
|
||||
function assertNonEmptyString(value, label) {
|
||||
if (value.trim().length === 0) {
|
||||
throw new Error(`${label} must be non-empty.`);
|
||||
}
|
||||
}
|
||||
function cloneAction(action) {
|
||||
switch (action.type) {
|
||||
case "teleportPlayer":
|
||||
return {
|
||||
type: "teleportPlayer",
|
||||
targetEntityId: action.targetEntityId
|
||||
};
|
||||
case "toggleVisibility":
|
||||
return {
|
||||
type: "toggleVisibility",
|
||||
targetBrushId: action.targetBrushId,
|
||||
visible: action.visible
|
||||
};
|
||||
case "playAnimation":
|
||||
return {
|
||||
type: "playAnimation",
|
||||
targetModelInstanceId: action.targetModelInstanceId,
|
||||
clipName: action.clipName,
|
||||
loop: action.loop
|
||||
};
|
||||
case "stopAnimation":
|
||||
return {
|
||||
type: "stopAnimation",
|
||||
targetModelInstanceId: action.targetModelInstanceId
|
||||
};
|
||||
case "playSound":
|
||||
return {
|
||||
type: "playSound",
|
||||
targetSoundEmitterId: action.targetSoundEmitterId
|
||||
};
|
||||
case "stopSound":
|
||||
return {
|
||||
type: "stopSound",
|
||||
targetSoundEmitterId: action.targetSoundEmitterId
|
||||
};
|
||||
}
|
||||
}
|
||||
export function isInteractionTriggerKind(value) {
|
||||
return value === "enter" || value === "exit" || value === "click";
|
||||
}
|
||||
export function createTeleportPlayerInteractionLink(options) {
|
||||
assertNonEmptyString(options.sourceEntityId, "Interaction source entity id");
|
||||
assertNonEmptyString(options.targetEntityId, "Teleport target entity id");
|
||||
return {
|
||||
id: options.id ?? createOpaqueId("interaction-link"),
|
||||
sourceEntityId: options.sourceEntityId,
|
||||
trigger: options.trigger ?? "enter",
|
||||
action: {
|
||||
type: "teleportPlayer",
|
||||
targetEntityId: options.targetEntityId
|
||||
}
|
||||
};
|
||||
}
|
||||
export function createToggleVisibilityInteractionLink(options) {
|
||||
assertNonEmptyString(options.sourceEntityId, "Interaction source entity id");
|
||||
assertNonEmptyString(options.targetBrushId, "Visibility target brush id");
|
||||
if (options.visible !== undefined && typeof options.visible !== "boolean") {
|
||||
throw new Error("Visibility action visible must be a boolean when authored.");
|
||||
}
|
||||
return {
|
||||
id: options.id ?? createOpaqueId("interaction-link"),
|
||||
sourceEntityId: options.sourceEntityId,
|
||||
trigger: options.trigger ?? "enter",
|
||||
action: {
|
||||
type: "toggleVisibility",
|
||||
targetBrushId: options.targetBrushId,
|
||||
visible: options.visible
|
||||
}
|
||||
};
|
||||
}
|
||||
export function createPlayAnimationInteractionLink(options) {
|
||||
assertNonEmptyString(options.sourceEntityId, "Interaction source entity id");
|
||||
assertNonEmptyString(options.targetModelInstanceId, "Play animation target model instance id");
|
||||
assertNonEmptyString(options.clipName, "Play animation clip name");
|
||||
return {
|
||||
id: options.id ?? createOpaqueId("interaction-link"),
|
||||
sourceEntityId: options.sourceEntityId,
|
||||
trigger: options.trigger ?? "enter",
|
||||
action: {
|
||||
type: "playAnimation",
|
||||
targetModelInstanceId: options.targetModelInstanceId,
|
||||
clipName: options.clipName,
|
||||
loop: options.loop
|
||||
}
|
||||
};
|
||||
}
|
||||
export function createStopAnimationInteractionLink(options) {
|
||||
assertNonEmptyString(options.sourceEntityId, "Interaction source entity id");
|
||||
assertNonEmptyString(options.targetModelInstanceId, "Stop animation target model instance id");
|
||||
return {
|
||||
id: options.id ?? createOpaqueId("interaction-link"),
|
||||
sourceEntityId: options.sourceEntityId,
|
||||
trigger: options.trigger ?? "enter",
|
||||
action: {
|
||||
type: "stopAnimation",
|
||||
targetModelInstanceId: options.targetModelInstanceId
|
||||
}
|
||||
};
|
||||
}
|
||||
export function createPlaySoundInteractionLink(options) {
|
||||
assertNonEmptyString(options.sourceEntityId, "Interaction source entity id");
|
||||
assertNonEmptyString(options.targetSoundEmitterId, "Play sound target sound emitter id");
|
||||
return {
|
||||
id: options.id ?? createOpaqueId("interaction-link"),
|
||||
sourceEntityId: options.sourceEntityId,
|
||||
trigger: options.trigger ?? "enter",
|
||||
action: {
|
||||
type: "playSound",
|
||||
targetSoundEmitterId: options.targetSoundEmitterId
|
||||
}
|
||||
};
|
||||
}
|
||||
export function createStopSoundInteractionLink(options) {
|
||||
assertNonEmptyString(options.sourceEntityId, "Interaction source entity id");
|
||||
assertNonEmptyString(options.targetSoundEmitterId, "Stop sound target sound emitter id");
|
||||
return {
|
||||
id: options.id ?? createOpaqueId("interaction-link"),
|
||||
sourceEntityId: options.sourceEntityId,
|
||||
trigger: options.trigger ?? "enter",
|
||||
action: {
|
||||
type: "stopSound",
|
||||
targetSoundEmitterId: options.targetSoundEmitterId
|
||||
}
|
||||
};
|
||||
}
|
||||
export function cloneInteractionLink(link) {
|
||||
return {
|
||||
id: link.id,
|
||||
sourceEntityId: link.sourceEntityId,
|
||||
trigger: link.trigger,
|
||||
action: cloneAction(link.action)
|
||||
};
|
||||
}
|
||||
export function areInteractionLinksEqual(left, right) {
|
||||
if (left.id !== right.id || left.sourceEntityId !== right.sourceEntityId || left.trigger !== right.trigger) {
|
||||
return false;
|
||||
}
|
||||
if (left.action.type !== right.action.type) {
|
||||
return false;
|
||||
}
|
||||
switch (left.action.type) {
|
||||
case "teleportPlayer":
|
||||
return left.action.targetEntityId === right.action.targetEntityId;
|
||||
case "toggleVisibility":
|
||||
return (left.action.targetBrushId === right.action.targetBrushId &&
|
||||
left.action.visible === right.action.visible);
|
||||
case "playAnimation":
|
||||
return (left.action.targetModelInstanceId === right.action.targetModelInstanceId &&
|
||||
left.action.clipName === right.action.clipName &&
|
||||
left.action.loop === right.action.loop);
|
||||
case "stopAnimation":
|
||||
return left.action.targetModelInstanceId === right.action.targetModelInstanceId;
|
||||
case "playSound":
|
||||
return left.action.targetSoundEmitterId === right.action.targetSoundEmitterId;
|
||||
case "stopSound":
|
||||
return left.action.targetSoundEmitterId === right.action.targetSoundEmitterId;
|
||||
default: {
|
||||
// Exhaustive check — TypeScript should never reach here
|
||||
const _exhaustive = left.action;
|
||||
void _exhaustive;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
export function cloneInteractionLinkRegistry(links) {
|
||||
return Object.fromEntries(Object.entries(links).map(([linkId, link]) => [linkId, cloneInteractionLink(link)]));
|
||||
}
|
||||
export function compareInteractionLinks(left, right) {
|
||||
if (left.sourceEntityId !== right.sourceEntityId) {
|
||||
return left.sourceEntityId.localeCompare(right.sourceEntityId);
|
||||
}
|
||||
if (left.trigger !== right.trigger) {
|
||||
return left.trigger.localeCompare(right.trigger);
|
||||
}
|
||||
return left.id.localeCompare(right.id);
|
||||
}
|
||||
export function getInteractionLinks(links) {
|
||||
return Object.values(links).sort(compareInteractionLinks);
|
||||
}
|
||||
export function getInteractionLinksForSource(links, sourceEntityId) {
|
||||
return getInteractionLinks(links).filter((link) => link.sourceEntityId === sourceEntityId);
|
||||
}
|
||||
Reference in New Issue
Block a user