correction of adding custom menu

correction of setProperty
updating CHANGELOG
updating api-reference
This commit is contained in:
GRL 2021-05-28 12:13:10 +02:00
parent 5565ddd3f4
commit 858a513569
9 changed files with 87 additions and 42 deletions

View File

@ -19,6 +19,13 @@
- Improved virtual joystick size (adapts to the zoom level) - Improved virtual joystick size (adapts to the zoom level)
- New scripting API features: - New scripting API features:
- Use `WA.loadSound(): Sound` to load / play / stop a sound - Use `WA.loadSound(): Sound` to load / play / stop a sound
- Use `WA.showLayer(): void` to show a layer
- Use `WA.hideLayer(): void` to hide a layer
- Use `WA.setProperty() : void` to add or change existing property of a layer
- Use `WA.onPlayerMove(): void` to track the movement of the current player
- Use `WA.getCurrentUser(): Promise<User>` to get the ID, name and tags of the current player
- Use `WA.getCurrentRoom(): Promise<Room>` to get the ID, JSON map file, url of the map of the current room and the layer where the current player started
- Use `WA.registerMenuCommand(): void` to add a custom menu
### Bug Fixes ### Bug Fixes

View File

@ -323,7 +323,7 @@ WA.getCurrentRoom((room) => {
### Add a custom menu ### Add a custom menu
``` ```
registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void
``` ```
Add a custom menu item containing the text `commandDescriptor`. A click on the menu will trigger the `callback`. Add a custom menu item containing the text `commandDescriptor`. A click on the menu will trigger the `callback`.

View File

@ -15,8 +15,8 @@ import type { UserInputChatEvent } from './UserInputChatEvent';
import type { DataLayerEvent } from "./DataLayerEvent"; import type { DataLayerEvent } from "./DataLayerEvent";
import type { LayerEvent } from './LayerEvent'; import type { LayerEvent } from './LayerEvent';
import type { SetPropertyEvent } from "./setPropertyEvent"; import type { SetPropertyEvent } from "./setPropertyEvent";
import type {LoadSoundEvent} from "./LoadSoundEvent"; import type { LoadSoundEvent } from "./LoadSoundEvent";
import type {PlaySoundEvent} from "./PlaySoundEvent"; import type { PlaySoundEvent } from "./PlaySoundEvent";
export interface TypedMessageEvent<T> extends MessageEvent { export interface TypedMessageEvent<T> extends MessageEvent {
@ -42,7 +42,6 @@ export type IframeEventMap = {
hideLayer: LayerEvent hideLayer: LayerEvent
setProperty: SetPropertyEvent setProperty: SetPropertyEvent
getDataLayer: undefined getDataLayer: undefined
//tilsetEvent: TilesetEvent
loadSound: LoadSoundEvent loadSound: LoadSoundEvent
playSound: PlaySoundEvent playSound: PlaySoundEvent
stopSound: null stopSound: null

View File

@ -20,7 +20,6 @@ import { Math } from 'phaser';
import type { DataLayerEvent } from "./Events/DataLayerEvent"; import type { DataLayerEvent } from "./Events/DataLayerEvent";
import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent';
import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent';
//import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent";
import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent"; import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent";
import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent"; import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent";
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent"; import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
@ -81,8 +80,8 @@ class IframeListener {
private readonly _registerMenuCommandStream: Subject<string> = new Subject(); private readonly _registerMenuCommandStream: Subject<string> = new Subject();
public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable();
/* private readonly _tilesetLoaderStream: Subject<TilesetEvent> = new Subject(); private readonly _unregisterMenuCommandStream: Subject<string> = new Subject();
public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable();*/ public readonly unregisterMenuCommandStream = this._unregisterMenuCommandStream.asObservable();
private readonly _playSoundStream: Subject<PlaySoundEvent> = new Subject(); private readonly _playSoundStream: Subject<PlaySoundEvent> = new Subject();
public readonly playSoundStream = this._playSoundStream.asObservable(); public readonly playSoundStream = this._playSoundStream.asObservable();
@ -94,6 +93,7 @@ class IframeListener {
public readonly loadSoundStream = this._loadSoundStream.asObservable(); public readonly loadSoundStream = this._loadSoundStream.asObservable();
private readonly iframes = new Set<HTMLIFrameElement>(); private readonly iframes = new Set<HTMLIFrameElement>();
private readonly iframeCloseCallbacks = new Map<HTMLIFrameElement, (() => void)[]>();
private readonly scripts = new Map<string, HTMLIFrameElement>(); private readonly scripts = new Map<string, HTMLIFrameElement>();
private sendPlayerMove: boolean = false; private sendPlayerMove: boolean = false;
@ -103,7 +103,8 @@ class IframeListener {
// Let's only accept messages from the iframe that are allowed. // Let's only accept messages from the iframe that are allowed.
// Note: maybe we could restrict on the domain too for additional security (in case the iframe goes to another domain). // Note: maybe we could restrict on the domain too for additional security (in case the iframe goes to another domain).
let foundSrc: string | null = null; let foundSrc: string | null = null;
for (const iframe of this.iframes) { let iframe: HTMLIFrameElement;
for (iframe of this.iframes) {
if (iframe.contentWindow === message.source) { if (iframe.contentWindow === message.source) {
foundSrc = iframe.src; foundSrc = iframe.src;
break; break;
@ -171,9 +172,12 @@ class IframeListener {
} else if (payload.type == "getDataLayer") { } else if (payload.type == "getDataLayer") {
this._dataLayerChangeStream.next(); this._dataLayerChangeStream.next();
} else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) {
const data = payload.data.menutItem;
// @ts-ignore
this.iframeCloseCallbacks.get(iframe).push(() => {
this._unregisterMenuCommandStream.next(data);
})
this._registerMenuCommandStream.next(payload.data.menutItem) this._registerMenuCommandStream.next(payload.data.menutItem)
/* } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) {
this._tilesetLoaderStream.next(payload.data);*/
} }
} }
}, false); }, false);
@ -200,9 +204,13 @@ class IframeListener {
*/ */
registerIframe(iframe: HTMLIFrameElement): void { registerIframe(iframe: HTMLIFrameElement): void {
this.iframes.add(iframe); this.iframes.add(iframe);
this.iframeCloseCallbacks.set(iframe, []);
} }
unregisterIframe(iframe: HTMLIFrameElement): void { unregisterIframe(iframe: HTMLIFrameElement): void {
this.iframeCloseCallbacks.get(iframe)?.forEach(callback => {
callback();
});
this.iframes.delete(iframe); this.iframes.delete(iframe);
} }

View File

@ -1,7 +1,7 @@
import type {ITiledMap, ITiledMapLayer, ITiledMapTileLayer} from "../Map/ITiledMap"; import type { ITiledMap, ITiledMapLayer } from "../Map/ITiledMap";
import { flattenGroupLayersMap } from "../Map/LayersFlattener"; import { flattenGroupLayersMap } from "../Map/LayersFlattener";
import TilemapLayer = Phaser.Tilemaps.TilemapLayer; import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes"; import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) => void; export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) => void;
@ -118,11 +118,11 @@ export class GameMap {
} }
public findLayer(layerName: string): ITiledMapLayer | undefined { public findLayer(layerName: string): ITiledMapLayer | undefined {
return this.flatLayers.find((layer) => layer.name = layerName); return this.flatLayers.find((layer) => layer.name === layerName);
} }
public findPhaserLayer(layerName: string): TilemapLayer | undefined { public findPhaserLayer(layerName: string): TilemapLayer | undefined {
return this.phaserLayers.find((layer) => layer.layer.name = layerName); return this.phaserLayers.find((layer) => layer.layer.name === layerName);
} }
public addTerrain(terrain : Phaser.Tilemaps.Tileset): void { public addTerrain(terrain : Phaser.Tilemaps.Tileset): void {

View File

@ -927,13 +927,6 @@ ${escapedMessage}
}) })
})); }));
/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => {
//this.load.tilemapTiledJSON('logo', tileset.imgUrl);
this.load.image('logo', tileset.imgUrl);
this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing));
this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]);
}))*/
} }
private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {

View File

@ -49,7 +49,10 @@ export class MenuScene extends Phaser.Scene {
this.subscriptions.add(iframeListener.registerMenuCommandStream.subscribe(menuCommand => { this.subscriptions.add(iframeListener.registerMenuCommandStream.subscribe(menuCommand => {
this.addMenuOption(menuCommand); this.addMenuOption(menuCommand);
}))
this.subscriptions.add(iframeListener.unregisterMenuCommandStream.subscribe(menuCommand => {
this.destroyMenu(menuCommand);
})) }))
} }
@ -386,6 +389,10 @@ export class MenuScene extends Phaser.Scene {
} }
} }
public destroyMenu(menu: string) {
this.menuElement.getChildByID(menu).remove();
}
public isDirty(): boolean { public isDirty(): boolean {
return false; return false;
} }

View File

@ -17,9 +17,9 @@ import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent";
import type { ITiledMap } from "./Phaser/Map/ITiledMap"; import type { ITiledMap } from "./Phaser/Map/ITiledMap";
import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent"; import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent";
import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent"; import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent";
import type {PlaySoundEvent} from "./Api/Events/PlaySoundEvent"; import type { PlaySoundEvent } from "./Api/Events/PlaySoundEvent";
import type {StopSoundEvent} from "./Api/Events/StopSoundEvent"; import type { StopSoundEvent } from "./Api/Events/StopSoundEvent";
import type {LoadSoundEvent} from "./Api/Events/LoadSoundEvent"; import type { LoadSoundEvent } from "./Api/Events/LoadSoundEvent";
import SoundConfig = Phaser.Types.Sound.SoundConfig; import SoundConfig = Phaser.Types.Sound.SoundConfig;
interface WorkAdventureApi { interface WorkAdventureApi {
@ -47,8 +47,6 @@ interface WorkAdventureApi {
registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void
getCurrentUser(): Promise<User> getCurrentUser(): Promise<User>
getCurrentRoom(): Promise<Room> getCurrentRoom(): Promise<Room>
//loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void;
onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void
} }
@ -176,7 +174,6 @@ const gameStateResolver: Array<(event: GameStateEvent) => void> = []
const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] const dataLayerResolver: Array<(event: DataLayerEvent) => void> = []
let immutableData: GameStateEvent; let immutableData: GameStateEvent;
//const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {}
const callbackPlayerMoved: Array<(event: HasPlayerMovedEvent) => void> = [] const callbackPlayerMoved: Array<(event: HasPlayerMovedEvent) => void> = []
function postToParent(content: IframeEvent<keyof IframeEventMap>) { function postToParent(content: IframeEvent<keyof IframeEventMap>) {
@ -193,20 +190,6 @@ window.WA = {
}) })
}, },
/* loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void {
postToParent({
type: "tilsetEvent",
data: {
name: name,
imgUrl: imgUrl,
tilewidth: tilewidth,
tileheight: tileheight,
margin: margin,
spacing: spacing
} as TilesetEvent
})
},*/
getCurrentUser(): Promise<User> { getCurrentUser(): Promise<User> {
return getGameState().then((gameState) => { return getGameState().then((gameState) => {
return {id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags}; return {id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags};
@ -353,7 +336,7 @@ window.WA = {
return popup; return popup;
}, },
registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) { registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void {
menuCallbacks.set(commandDescriptor, callback); menuCallbacks.set(commandDescriptor, callback);
window.parent.postMessage({ window.parent.postMessage({
'type': 'registerMenuCommand', 'type': 'registerMenuCommand',

View File

@ -82,6 +82,54 @@
<a href="#" class="testLink" data-testmap="energy.json" target="_blank">Test energy consumption</a> <a href="#" class="testLink" data-testmap="energy.json" target="_blank">Test energy consumption</a>
</td> </td>
</tr> </tr>
<tr>
<td>
<input type="radio" name="test-custom-menu"> Success <input type="radio" name="test-custom-menu"> Failure <input type="radio" name="test-custom-menu" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/customMenu.json" target="_blank">Testing add a custom menu by scripting API</a>
</td>
</tr>
<tr>
<td>
<input type="radio" name="test-getCurrentRoom"> Success <input type="radio" name="test-getCurrentRoom"> Failure <input type="radio" name="test-getCurrentRoom" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/getCurrentRoom.json" target="_blank">Testing return current room attributes by Scripting API (Need to test from current user)</a>
</td>
</tr>
<tr>
<td>
<input type="radio" name="test-getCurrentUser"> Success <input type="radio" name="test-getCurrentUser"> Failure <input type="radio" name="test-getCurrentUser" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/getCurrentUser.json" target="_blank">Testing return current user attributes by Scripting API</a>
</td>
</tr>
<tr>
<td>
<input type="radio" name="test-player-move"> Success <input type="radio" name="test-player-move"> Failure <input type="radio" name="test-player-move" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/playerMove.json" target="_blank">Test listening player movement by Scripting API</a>
</td>
</tr>
<tr>
<td>
<input type="radio" name="test-setProperty"> Success <input type="radio" name="test-setProperty"> Failure <input type="radio" name="test-setProperty" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/setProperty.json" target="_blank">Testing set a property on a layer by Scripting API</a>
</td>
</tr>
<tr>
<td>
<input type="radio" name="test-show-hide"> Success <input type="radio" name="test-show-hide"> Failure <input type="radio" name="test-show-hide" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/showHideLayer.json" target="_blank">Testing show or hide a layer by Scripting API</a>
</td>
</tr>
</table> </table>
<script> <script>