diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 01d3e636..889ed3ac 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -370,3 +370,18 @@ WA.registerMenuCommand('help', () => { WA.onChatMessage ... }); ``` + +### Getting the list of tags of the current user +``` +getTagUser(): Promise +``` + +Return the list of all the tags that has the current user. If the current user has no tag, return an empty list. If there is no connection with the room, return nothing. + +Example : +```javascript +WA.getTagUser().then((tagList) => { + ... +}); +``` + diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 8383cfbd..114cbb90 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -15,6 +15,7 @@ import type { UserInputChatEvent } from './UserInputChatEvent'; import type { DataLayerEvent } from "./DataLayerEvent"; import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; +import type { TagEvent } from "./TagEvent"; export interface TypedMessageEvent extends MessageEvent { data: T @@ -36,11 +37,11 @@ export type IframeEventMap = { displayBubble: null removeBubble: null onPlayerMove: undefined - onDataLayerChange: undefined showLayer: LayerEvent hideLayer: LayerEvent setProperty: SetPropertyEvent getDataLayer: undefined + getTag: undefined } export interface IframeEvent { type: T; @@ -60,6 +61,7 @@ export interface IframeResponseEventMap { hasPlayerMoved: HasPlayerMovedEvent dataLayer: DataLayerEvent menuItemClicked: MenuItemClickedEvent + tagList: TagEvent } export interface IframeResponseEvent { type: T; diff --git a/front/src/Api/Events/TagEvent.ts b/front/src/Api/Events/TagEvent.ts new file mode 100644 index 00000000..66665403 --- /dev/null +++ b/front/src/Api/Events/TagEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isTagEvent = + new tg.IsInterface().withProperties({ + list: tg.isArray(tg.isString), + }).get(); +/** + * A message sent from the iFrame to the game to show/hide a layer. + */ +export type TagEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 07246333..35ef6341 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -19,6 +19,7 @@ import { Math } from 'phaser'; import type { DataLayerEvent } from "./Events/DataLayerEvent"; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; +import type { TagEvent } from "./Events/TagEvent"; /** @@ -77,6 +78,10 @@ class IframeListener { private readonly _registerMenuCommandStream: Subject = new Subject(); public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); + + private readonly _tagListStream: Subject = new Subject(); + public readonly tagListStream = this._tagListStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; @@ -145,12 +150,21 @@ class IframeListener { this._dataLayerChangeStream.next(); } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { this._registerMenuCommandStream.next(payload.data.menutItem) + } else if (payload.type == "getTag") { + this._tagListStream.next(); } } }, false); } + sendUserTagList(tagList: TagEvent){ + this.postMessage({ + 'type' : 'tagList', + 'data' : tagList + }) + } + sendDataLayerEvent(dataLayerEvent: DataLayerEvent) { this.postMessage({ 'type' : 'dataLayer', diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 6b2c63af..1cb4a97d 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -598,4 +598,11 @@ export class RoomConnection implements RoomConnection { public isAdmin(): boolean { return this.hasTag('admin'); } + + public getAllTag() : string[] { + this.tags.push('TEST'); + this.tags.push('TEST 2'); + this.tags.push('TEST 3'); + return this.tags; + } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9150b4c1..dee5eb53 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -903,6 +903,13 @@ ${escapedMessage} iframeListener.sendDataLayerEvent({data: this.gameMap.getMap()}); })) + this.iframeSubscriptionList.push(iframeListener.tagListStream.subscribe(()=> { + if (this.connection === undefined) { + return; + } + iframeListener.sendUserTagList({list: this.connection.getAllTag()}); + })) + } private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 00977157..517248ed 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -17,6 +17,7 @@ import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent"; import type { ITiledMap } from "./Phaser/Map/ITiledMap"; import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent"; import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent"; +import {TagEvent, isTagEvent} from "./Api/Events/TagEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -45,10 +46,10 @@ interface WorkAdventureApi { getRoomId(): Promise; getStartLayerName(): Promise; getNickName(): Promise; - + getTagUser(): Promise; + getMap(): Promise onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void - getMap(): Promise } declare global { @@ -128,8 +129,19 @@ function getDataLayer(): Promise { }) } +function getTag(): Promise { + return new Promise((resolver, thrower) => { + tagResolver.push((resolver)); + postToParent({ + type: "getTag", + data: undefined + }) + }) +} + const gameStateResolver: Array<(event: GameStateEvent) => void> = [] const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] +const tagResolver: Array<(event : TagEvent) => void> = [] let immutableData: GameStateEvent; const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} @@ -151,6 +163,11 @@ window.WA = { }) }, + getTagUser(): Promise { + return getTag().then((res) => { + return res.list; + }) + }, getMap(): Promise { return getDataLayer().then((res) => { @@ -389,6 +406,12 @@ window.addEventListener('message', message => { if (callback) { callback(payload.data.menuItem) } + } else { + if (payload.type == "tagList" && isTagEvent(payloadData)) { + tagResolver.forEach(resolver => { + resolver(payloadData); + }) + } } } diff --git a/maps/tests/Metadata/TagList.html b/maps/tests/Metadata/TagList.html new file mode 100644 index 00000000..73bdc368 --- /dev/null +++ b/maps/tests/Metadata/TagList.html @@ -0,0 +1,19 @@ + + + + + + + + +
+ + \ No newline at end of file diff --git a/maps/tests/Metadata/TagList.json b/maps/tests/Metadata/TagList.json new file mode 100644 index 00000000..cced49a3 --- /dev/null +++ b/maps/tests/Metadata/TagList.json @@ -0,0 +1,254 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"TagList.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":131.903791109293, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the grass, an iframe open, click on the 'Get Tag List' button.\nResult : \nThe list of the tag is displayed in the iframe.\n\n\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":14.750638909983, + "y":188.268561247737 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":10, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file