diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 613ae525..a0e7717a 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -88,13 +88,11 @@ export type IframeQueryMap = { getState: { query: undefined, answer: GameStateEvent, - callback: () => GameStateEvent|PromiseLike }, getMapData: { query: undefined, answer: MapDataEvent, - callback: () => MapDataEvent|PromiseLike - } + }, } export interface IframeQuery { diff --git a/front/src/Api/iframe/room.ts b/front/src/Api/iframe/room.ts index 2e4f9fd5..00d974dc 100644 --- a/front/src/Api/iframe/room.ts +++ b/front/src/Api/iframe/room.ts @@ -1,18 +1,12 @@ import {Observable, Subject} from "rxjs"; -import { isMapDataEvent } from "../Events/MapDataEvent"; import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent"; -import { isGameStateEvent } from "../Events/GameStateEvent"; import {IframeApiContribution, queryWorkadventure, sendToWorkadventure} from "./IframeApiContribution"; import { apiCallback } from "./registeredCallbacks"; -import type {LayerEvent} from "../Events/LayerEvent"; -import type {SetPropertyEvent} from "../Events/setPropertyEvent"; import {isSetVariableEvent, SetVariableEvent} from "../Events/SetVariableEvent"; import type { ITiledMap } from "../../Phaser/Map/ITiledMap"; -import type { MapDataEvent } from "../Events/MapDataEvent"; -import type { GameStateEvent } from "../Events/GameStateEvent"; const enterStreams: Map> = new Map>(); const leaveStreams: Map> = new Map>(); @@ -39,6 +33,16 @@ export const setMapURL = (url: string) => { mapURL = url; } +export const initVariables = (_variables: Map): void => { + for (const [name, value] of _variables.entries()) { + // In case the user already decided to put values in the variables (before onInit), let's make sure onInit does not override this. + if (!variables.has(name)) { + variables.set(name, value); + } + } + +} + setVariableResolvers.subscribe((event) => { variables.set(event.key, event.value); const subject = variableSubscribers.get(event.key); diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index a616cf4a..e095dab1 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -1,4 +1,4 @@ -import type { ITiledMap, ITiledMapLayer, ITiledMapLayerProperty } from "../Map/ITiledMap"; +import type { ITiledMap, ITiledMapLayer, ITiledMapProperty } from "../Map/ITiledMap"; import { flattenGroupLayersMap } from "../Map/LayersFlattener"; import TilemapLayer = Phaser.Tilemaps.TilemapLayer; import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes"; @@ -19,7 +19,7 @@ export class GameMap { private callbacks = new Map>(); private tileNameMap = new Map(); - private tileSetPropertyMap: { [tile_index: number]: Array } = {}; + private tileSetPropertyMap: { [tile_index: number]: Array } = {}; public readonly flatLayers: ITiledMapLayer[]; public readonly phaserLayers: TilemapLayer[] = []; @@ -61,7 +61,7 @@ export class GameMap { } } - public getPropertiesForIndex(index: number): Array { + public getPropertiesForIndex(index: number): Array { if (this.tileSetPropertyMap[index]) { return this.tileSetPropertyMap[index]; } @@ -151,7 +151,7 @@ export class GameMap { return this.map; } - private getTileProperty(index: number): Array { + private getTileProperty(index: number): Array { return this.tileSetPropertyMap[index]; } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 1c522703..5d4c6b2b 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -50,7 +50,7 @@ import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectC import type { ITiledMap, ITiledMapLayer, - ITiledMapLayerProperty, + ITiledMapProperty, ITiledMapObject, ITiledTileSet, } from "../Map/ITiledMap"; @@ -1197,12 +1197,12 @@ ${escapedMessage} } private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined { - const properties: ITiledMapLayerProperty[] | undefined = layer.properties; + const properties: ITiledMapProperty[] | undefined = layer.properties; if (!properties) { return undefined; } const obj = properties.find( - (property: ITiledMapLayerProperty) => property.name.toLowerCase() === name.toLowerCase() + (property: ITiledMapProperty) => property.name.toLowerCase() === name.toLowerCase() ); if (obj === undefined) { return undefined; @@ -1211,12 +1211,12 @@ ${escapedMessage} } private getProperties(layer: ITiledMapLayer | ITiledMap, name: string): (string | number | boolean | undefined)[] { - const properties: ITiledMapLayerProperty[] | undefined = layer.properties; + const properties: ITiledMapProperty[] | undefined = layer.properties; if (!properties) { return []; } return properties - .filter((property: ITiledMapLayerProperty) => property.name.toLowerCase() === name.toLowerCase()) + .filter((property: ITiledMapProperty) => property.name.toLowerCase() === name.toLowerCase()) .map((property) => property.value); } diff --git a/front/src/Phaser/Game/SharedVariablesManager.ts b/front/src/Phaser/Game/SharedVariablesManager.ts index abd2474e..aeb26d68 100644 --- a/front/src/Phaser/Game/SharedVariablesManager.ts +++ b/front/src/Phaser/Game/SharedVariablesManager.ts @@ -5,18 +5,28 @@ import type {RoomConnection} from "../../Connexion/RoomConnection"; import {iframeListener} from "../../Api/IframeListener"; import type {Subscription} from "rxjs"; import type {GameMap} from "./GameMap"; -import type {ITiledMapObject} from "../Map/ITiledMap"; +import type {ITile, ITiledMapObject} from "../Map/ITiledMap"; +import type {Var} from "svelte/types/compiler/interfaces"; + +interface Variable { + defaultValue: unknown +} export class SharedVariablesManager { private _variables = new Map(); private iframeListenerSubscription: Subscription; - private variableObjects: Map; + private variableObjects: Map; constructor(private roomConnection: RoomConnection, private gameMap: GameMap) { // We initialize the list of variable object at room start. The objects cannot be edited later // (otherwise, this would cause a security issue if the scripting API can edit this list of objects) this.variableObjects = SharedVariablesManager.findVariablesInMap(gameMap); + // Let's initialize default values + for (const [name, variableObject] of this.variableObjects.entries()) { + this._variables.set(name, variableObject.defaultValue); + } + // When a variable is modified from an iFrame this.iframeListenerSubscription = iframeListener.setVariableStream.subscribe((event) => { const key = event.key; @@ -33,14 +43,14 @@ export class SharedVariablesManager { }); } - private static findVariablesInMap(gameMap: GameMap): Map { - const objects = new Map(); + private static findVariablesInMap(gameMap: GameMap): Map { + const objects = new Map(); for (const layer of gameMap.getMap().layers) { if (layer.type === 'objectgroup') { for (const object of layer.objects) { if (object.type === 'variable') { // We store a copy of the object (to make it immutable) - objects.set(object.name, {...object}); + objects.set(object.name, this.iTiledObjectToVariable(object)); } } } @@ -48,6 +58,21 @@ export class SharedVariablesManager { return objects; } + private static iTiledObjectToVariable(object: ITiledMapObject): Variable { + const variable: Variable = { + defaultValue: undefined + }; + + if (object.properties) { + for (const property of object.properties) { + if (property.name === 'default') { + variable.defaultValue = property.value; + } + } + } + + return variable; + } public close(): void { this.iframeListenerSubscription.unsubscribe(); diff --git a/front/src/Phaser/Game/StartPositionCalculator.ts b/front/src/Phaser/Game/StartPositionCalculator.ts index 7460c81c..a0184d2b 100644 --- a/front/src/Phaser/Game/StartPositionCalculator.ts +++ b/front/src/Phaser/Game/StartPositionCalculator.ts @@ -1,5 +1,5 @@ import type { PositionInterface } from "../../Connexion/ConnexionModels"; -import type { ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapTileLayer } from "../Map/ITiledMap"; +import type { ITiledMap, ITiledMapLayer, ITiledMapProperty, ITiledMapTileLayer } from "../Map/ITiledMap"; import type { GameMap } from "./GameMap"; const defaultStartLayerName = "start"; @@ -112,12 +112,12 @@ export class StartPositionCalculator { } private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined { - const properties: ITiledMapLayerProperty[] | undefined = layer.properties; + const properties: ITiledMapProperty[] | undefined = layer.properties; if (!properties) { return undefined; } const obj = properties.find( - (property: ITiledMapLayerProperty) => property.name.toLowerCase() === name.toLowerCase() + (property: ITiledMapProperty) => property.name.toLowerCase() === name.toLowerCase() ); if (obj === undefined) { return undefined; diff --git a/front/src/Phaser/Map/ITiledMap.ts b/front/src/Phaser/Map/ITiledMap.ts index 0653e83a..c5b96f22 100644 --- a/front/src/Phaser/Map/ITiledMap.ts +++ b/front/src/Phaser/Map/ITiledMap.ts @@ -16,7 +16,7 @@ export interface ITiledMap { * Map orientation (orthogonal) */ orientation: string; - properties?: ITiledMapLayerProperty[]; + properties?: ITiledMapProperty[]; /** * Render order (right-down) @@ -33,7 +33,7 @@ export interface ITiledMap { type?: string; } -export interface ITiledMapLayerProperty { +export interface ITiledMapProperty { name: string; type: string; value: string | boolean | number | undefined; @@ -51,7 +51,7 @@ export interface ITiledMapGroupLayer { id?: number; name: string; opacity: number; - properties?: ITiledMapLayerProperty[]; + properties?: ITiledMapProperty[]; type: "group"; visible: boolean; @@ -69,7 +69,7 @@ export interface ITiledMapTileLayer { height: number; name: string; opacity: number; - properties?: ITiledMapLayerProperty[]; + properties?: ITiledMapProperty[]; encoding?: string; compression?: string; @@ -91,7 +91,7 @@ export interface ITiledMapObjectLayer { height: number; name: string; opacity: number; - properties?: ITiledMapLayerProperty[]; + properties?: ITiledMapProperty[]; encoding?: string; compression?: string; @@ -117,7 +117,7 @@ export interface ITiledMapObject { gid: number; height: number; name: string; - properties: { [key: string]: string }; + properties?: ITiledMapProperty[]; rotation: number; type: string; visible: boolean; @@ -163,7 +163,7 @@ export interface ITiledTileSet { imagewidth: number; margin: number; name: string; - properties: { [key: string]: string }; + properties?: ITiledMapProperty[]; spacing: number; tilecount: number; tileheight: number; @@ -182,7 +182,7 @@ export interface ITile { id: number; type?: string; - properties?: Array; + properties?: ITiledMapProperty[]; } export interface ITiledMapTerrain { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index ee68270e..fb44738f 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -11,7 +11,7 @@ import nav from "./Api/iframe/nav"; import controls from "./Api/iframe/controls"; import ui from "./Api/iframe/ui"; import sound from "./Api/iframe/sound"; -import room, {setMapURL, setRoomId} from "./Api/iframe/room"; +import room, {initVariables, setMapURL, setRoomId} from "./Api/iframe/room"; import player, {setPlayerName, setTags, setUuid} from "./Api/iframe/player"; import type { ButtonDescriptor } from "./Api/iframe/Ui/ButtonDescriptor"; import type { Popup } from "./Api/iframe/Ui/Popup"; @@ -29,6 +29,7 @@ const initPromise = new Promise((resolve) => { setMapURL(state.mapUrl); setTags(state.tags); setUuid(state.uuid); + initVariables(state.variables as Map); resolve(); })); }); diff --git a/maps/tests/Variables/script.js b/maps/tests/Variables/script.js index afd16773..cef9818e 100644 --- a/maps/tests/Variables/script.js +++ b/maps/tests/Variables/script.js @@ -1,11 +1,13 @@ +WA.onInit().then(() => { + console.log('Trying to read variable "doorOpened" whose default property is true. This should display "true".'); + console.log('doorOpened', WA.room.loadVariable('doorOpened')); -console.log('Trying to set variable "not_exists". This should display an error in the console.') -WA.room.saveVariable('not_exists', 'foo'); - -console.log('Trying to set variable "config". This should work.'); -WA.room.saveVariable('config', {'foo': 'bar'}); - -console.log('Trying to read variable "config". This should display a {"foo": "bar"} object.'); -console.log(WA.room.loadVariable('config')); + console.log('Trying to set variable "not_exists". This should display an error in the console.') + WA.room.saveVariable('not_exists', 'foo'); + console.log('Trying to set variable "config". This should work.'); + WA.room.saveVariable('config', {'foo': 'bar'}); + console.log('Trying to read variable "config". This should display a {"foo": "bar"} object.'); + console.log(WA.room.loadVariable('config')); +}); diff --git a/maps/tests/Variables/variables.json b/maps/tests/Variables/variables.json index 93573da8..61067071 100644 --- a/maps/tests/Variables/variables.json +++ b/maps/tests/Variables/variables.json @@ -72,6 +72,24 @@ "template":"config.tx", "x":57.5, "y":111 + }, + { + "height":0, + "id":6, + "name":"doorOpened", + "point":true, + "properties":[ + { + "name":"default", + "type":"bool", + "value":true + }], + "rotation":0, + "type":"variable", + "visible":true, + "width":0, + "x":131.38069962269, + "y":106.004988169086 }], "opacity":1, "type":"objectgroup", @@ -80,7 +98,7 @@ "y":0 }], "nextlayerid":8, - "nextobjectid":6, + "nextobjectid":8, "orientation":"orthogonal", "properties":[ {