import { Subject } from "rxjs"; import { isDataLayerEvent } from "../Events/DataLayerEvent"; import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent"; import { isGameStateEvent } from "../Events/GameStateEvent"; import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution"; import { apiCallback } from "./registeredCallbacks"; import type { ITiledMap } from "../../Phaser/Map/ITiledMap"; import type { DataLayerEvent } from "../Events/DataLayerEvent"; import type { GameStateEvent } from "../Events/GameStateEvent"; const enterStreams: Map> = new Map>(); const leaveStreams: Map> = new Map>(); const dataLayerResolver = new Subject(); const stateResolvers = new Subject(); let immutableDataPromise: Promise | undefined = undefined; interface Room { id: string; mapUrl: string; map: ITiledMap; startLayer: string | null; } interface User { id: string | undefined; nickName: string | null; tags: string[]; } interface TileDescriptor { x: number; y: number; tile: number | string; layer: string; } function getGameState(): Promise { if (immutableDataPromise === undefined) { immutableDataPromise = queryWorkadventure({ type: "getState", data: undefined }); } return immutableDataPromise; } function getDataLayer(): Promise { return new Promise((resolver, thrower) => { dataLayerResolver.subscribe(resolver); sendToWorkadventure({ type: "getDataLayer", data: null }); }); } export class WorkadventureRoomCommands extends IframeApiContribution { callbacks = [ apiCallback({ callback: (payloadData: EnterLeaveEvent) => { enterStreams.get(payloadData.name)?.next(); }, type: "enterEvent", typeChecker: isEnterLeaveEvent, }), apiCallback({ type: "leaveEvent", typeChecker: isEnterLeaveEvent, callback: (payloadData) => { leaveStreams.get(payloadData.name)?.next(); }, }), apiCallback({ type: "dataLayer", typeChecker: isDataLayerEvent, callback: (payloadData) => { dataLayerResolver.next(payloadData); }, }), ]; onEnterZone(name: string, callback: () => void): void { let subject = enterStreams.get(name); if (subject === undefined) { subject = new Subject(); enterStreams.set(name, subject); } subject.subscribe(callback); } onLeaveZone(name: string, callback: () => void): void { let subject = leaveStreams.get(name); if (subject === undefined) { subject = new Subject(); leaveStreams.set(name, subject); } subject.subscribe(callback); } showLayer(layerName: string): void { sendToWorkadventure({ type: "showLayer", data: { name: layerName } }); } hideLayer(layerName: string): void { sendToWorkadventure({ type: "hideLayer", data: { name: layerName } }); } setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { sendToWorkadventure({ type: "setProperty", data: { layerName: layerName, propertyName: propertyName, propertyValue: propertyValue, }, }); } getCurrentRoom(): Promise { return getGameState().then((gameState) => { return getDataLayer().then((mapJson) => { return { id: gameState.roomId, map: mapJson.data as ITiledMap, mapUrl: gameState.mapUrl, startLayer: gameState.startLayerName, }; }); }); } getCurrentUser(): Promise { return getGameState().then((gameState) => { return { id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags }; }); } setTiles(tiles: TileDescriptor[]) { sendToWorkadventure({ type: "setTiles", data: tiles, }); } } export default new WorkadventureRoomCommands();