From 63516d0267a6b450445d1065a32e401e6c4efd9f Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Mon, 14 Apr 2025 15:42:37 +0200 Subject: [PATCH] WIP: Fix and improve interaction scenes --- backend/main.ts | 1 + backend/scene-types/interaction.ts | 38 +++++-- frontend/scene-types/base.ts | 2 +- .../choice/{DuoView.vue => CrewView.vue} | 0 frontend/scene-types/choice/index.ts | 4 +- .../interaction/CrewInteractionCard.vue | 57 ++++++++++ .../interaction/CrewObjectCard.vue | 42 +++++++ .../interaction/{DuoView.vue => CrewView.vue} | 39 ++++--- ...eItemCard.vue => InteractionQueueItem.vue} | 16 --- .../scene-types/interaction/PlayerView.vue | 8 +- frontend/scene-types/interaction/QueueTab.vue | 7 +- frontend/scene-types/interaction/index.ts | 105 ++++++++++++++++-- .../text/{DuoView.vue => CrewView.vue} | 0 frontend/scene-types/text/index.ts | 4 +- frontend/screens/DuoScreen.vue | 2 +- shared/scene-types/interaction.ts | 1 + 16 files changed, 260 insertions(+), 66 deletions(-) rename frontend/scene-types/choice/{DuoView.vue => CrewView.vue} (100%) create mode 100644 frontend/scene-types/interaction/CrewInteractionCard.vue create mode 100644 frontend/scene-types/interaction/CrewObjectCard.vue rename frontend/scene-types/interaction/{DuoView.vue => CrewView.vue} (53%) rename frontend/scene-types/interaction/{InteractionQueueItemCard.vue => InteractionQueueItem.vue} (86%) rename frontend/scene-types/text/{DuoView.vue => CrewView.vue} (100%) diff --git a/backend/main.ts b/backend/main.ts index 942f0b2..137601c 100644 --- a/backend/main.ts +++ b/backend/main.ts @@ -21,6 +21,7 @@ const stop = () => { console.log("Received stop signal") server.closeAllConnections() server.close() + server.unref() } process.on("SIGTERM", stop) diff --git a/backend/scene-types/interaction.ts b/backend/scene-types/interaction.ts index d6dbb4b..9bff4be 100644 --- a/backend/scene-types/interaction.ts +++ b/backend/scene-types/interaction.ts @@ -17,6 +17,7 @@ export class InteractionSceneState implements SceneState private suggestedInteractionIdBySessionId: Map = new Map() private ongoingInteractionExecution: SuggestedInteraction | null = null private objectVisibilityById = new Map() + private objectCompletionStepById = new Map() constructor(private game: Game, private definition: InteractionSceneDefinition) { definition.objectsById.entries().forEach(([id, o]) => this.setObjectVisibility(id, o.reveal)) @@ -27,6 +28,7 @@ export class InteractionSceneState implements SceneState events.push(this.getVotesChangedEvent()) this.objectVisibilityById.entries().forEach(([id, isVisible]) => events.push({ type: "object-visibility-changed", objectId: id, isVisible })) + this.objectCompletionStepById.entries().forEach(([id, step]) => events.push({ type: "object-completion-step-changed", objectId: id, step })) if (this.ongoingInteractionExecution !== null) events.push({ type: "interaction-execution-started", interaction: this.ongoingInteractionExecution }) @@ -95,19 +97,19 @@ export class InteractionSceneState implements SceneState this.emit({ type: "interaction-execution-started", interaction }) } - finishInteractionExecution(id: string, onlyIfOngoing: boolean = true) { - if (onlyIfOngoing && (this.ongoingInteractionExecution === null || id !== getSuggestedInteractionId(this.ongoingInteractionExecution))) return + finishInteractionExecution(interactionId: string, onlyIfOngoing: boolean = true) { + if (onlyIfOngoing && (this.ongoingInteractionExecution === null || interactionId !== getSuggestedInteractionId(this.ongoingInteractionExecution))) return this.ongoingInteractionExecution = null this.emit({ type: "interaction-execution-finished" }) - this.removeInteractionFromQueue(id) + this.removeInteractionFromQueue(interactionId) - const interaction = this.definition.interactionsById.get(id) + const interaction = this.definition.interactionsById.get(interactionId) if (interaction === undefined) return switch (interaction.type) { case "use": if (interaction.consume) { - this.emit({ type: "object-visibility-changed", objectId: interaction.objectId, isVisible: false }) + this.setObjectVisibility(interaction.objectId, false) } break @@ -117,14 +119,34 @@ export class InteractionSceneState implements SceneState if (consume) this.setObjectVisibility(id, false) }) - interaction.outputObjectIds.forEach(id => this.setObjectVisibility(id, true)) + interaction.outputObjectIds.forEach(id => { + const object = this.definition.objectsById.get(id)! + this.setObjectVisibility(id, true) + + if (object.completion !== undefined) { + let step = (this.objectCompletionStepById.get(id) ?? -1) + if (interaction.inputObjects.get(id)?.consume === true) { + step = 0 + } else { + step = Math.min(step + 1, object.completion.steps) + } + + this.objectCompletionStepById.set(id, step) + this.emit({ type: "object-completion-step-changed", objectId: id, step }) + + if (step === object.completion.steps) { + this.objectVisibilityById.set(id, false) + this.objectVisibilityById.set(object.completion.replaceWith, true) + } + } + }) break } } - cancelInteractionExecution(id: string, onlyIfOngoing: boolean = true) { - if (onlyIfOngoing && (this.ongoingInteractionExecution === null || id !== getSuggestedInteractionId(this.ongoingInteractionExecution))) return + cancelInteractionExecution(interactionId: string, onlyIfOngoing: boolean = true) { + if (onlyIfOngoing && (this.ongoingInteractionExecution === null || interactionId !== getSuggestedInteractionId(this.ongoingInteractionExecution))) return this.ongoingInteractionExecution = null this.emit({ type: "interaction-execution-cancelled" }) } diff --git a/frontend/scene-types/base.ts b/frontend/scene-types/base.ts index 78037ba..07b9bc9 100644 --- a/frontend/scene-types/base.ts +++ b/frontend/scene-types/base.ts @@ -4,7 +4,7 @@ import type { Component } from "vue" export interface SceneType { id: DefinitionT["type"] playerView: Component<{ controller: ControllerT, definition: DefinitionT }>, - duoView: Component<{ controller: ControllerT, definition: DefinitionT }> + crewView: Component<{ controller: ControllerT, definition: DefinitionT }> createController(definition: DefinitionT): ControllerT } diff --git a/frontend/scene-types/choice/DuoView.vue b/frontend/scene-types/choice/CrewView.vue similarity index 100% rename from frontend/scene-types/choice/DuoView.vue rename to frontend/scene-types/choice/CrewView.vue diff --git a/frontend/scene-types/choice/index.ts b/frontend/scene-types/choice/index.ts index 683cfec..3b29dd2 100644 --- a/frontend/scene-types/choice/index.ts +++ b/frontend/scene-types/choice/index.ts @@ -2,12 +2,12 @@ import type { SceneController, SceneType } from "../base" import type { ChoiceSceneDefinition } from "../../../shared/script/types" import PlayerView from "./PlayerView.vue" import type { ChoiceSceneEvent } from "../../../shared/scene-types/choice" -import DuoView from "./DuoView.vue" +import CrewView from "./CrewView.vue" export const ChoiceSceneType: SceneType = { id: "choice", playerView: PlayerView, - duoView: DuoView, + crewView: CrewView, createController(definition: ChoiceSceneDefinition): ChoiceSceneController { return { handleEvent(event: ChoiceSceneEvent) { diff --git a/frontend/scene-types/interaction/CrewInteractionCard.vue b/frontend/scene-types/interaction/CrewInteractionCard.vue new file mode 100644 index 0000000..08210ef --- /dev/null +++ b/frontend/scene-types/interaction/CrewInteractionCard.vue @@ -0,0 +1,57 @@ + + + + + \ No newline at end of file diff --git a/frontend/scene-types/interaction/CrewObjectCard.vue b/frontend/scene-types/interaction/CrewObjectCard.vue new file mode 100644 index 0000000..8bc20da --- /dev/null +++ b/frontend/scene-types/interaction/CrewObjectCard.vue @@ -0,0 +1,42 @@ + + + + + \ No newline at end of file diff --git a/frontend/scene-types/interaction/DuoView.vue b/frontend/scene-types/interaction/CrewView.vue similarity index 53% rename from frontend/scene-types/interaction/DuoView.vue rename to frontend/scene-types/interaction/CrewView.vue index e17e467..29e543a 100644 --- a/frontend/scene-types/interaction/DuoView.vue +++ b/frontend/scene-types/interaction/CrewView.vue @@ -1,33 +1,32 @@ - + diff --git a/shared/scene-types/interaction.ts b/shared/scene-types/interaction.ts index 25d740b..4616a34 100644 --- a/shared/scene-types/interaction.ts +++ b/shared/scene-types/interaction.ts @@ -25,6 +25,7 @@ export type InteractionSceneEvent = | { type: "interaction-queued"; interaction: SuggestedInteraction } | { type: "votes-changed"; votesByInteractionId: Record } | { type: "object-visibility-changed"; objectId: string; isVisible: boolean } + | { type: "object-completion-step-changed"; objectId: string; step: number } | { type: "interaction-execution-started"; interaction: SuggestedInteraction } | { type: "interaction-execution-finished" } | { type: "interaction-execution-cancelled" } \ No newline at end of file