Migrating WA.player.getCurrentUser and WA.room.getCurrentRoom to direct property access and WA.room.getMap
This commit is contained in:
parent
ea1460abaf
commit
62a4814961
11 changed files with 220 additions and 159 deletions
|
@ -1,6 +1,63 @@
|
||||||
{.section-title.accent.text-primary}
|
{.section-title.accent.text-primary}
|
||||||
# API Player functions Reference
|
# API Player functions Reference
|
||||||
|
|
||||||
|
### Get the player name
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.player.name: string;
|
||||||
|
```
|
||||||
|
|
||||||
|
The player name is available from the `WA.player.name` property.
|
||||||
|
|
||||||
|
{.alert.alert-info}
|
||||||
|
You need to wait for the end of the initialization before accessing `WA.player.name`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Player name: ', WA.player.name);
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get the player ID
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.player.id: string|undefined;
|
||||||
|
```
|
||||||
|
|
||||||
|
The player ID is available from the `WA.player.id` property.
|
||||||
|
This is a unique identifier for a given player. Anonymous player might not have an id.
|
||||||
|
|
||||||
|
{.alert.alert-info}
|
||||||
|
You need to wait for the end of the initialization before accessing `WA.player.id`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Player ID: ', WA.player.id);
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get the tags of the player
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.player.tags: string[];
|
||||||
|
```
|
||||||
|
|
||||||
|
The player tags are available from the `WA.player.tags` property.
|
||||||
|
They represent a set of rights the player acquires after login in.
|
||||||
|
|
||||||
|
{.alert.alert-warn}
|
||||||
|
Tags attributed to a user depend on the authentication system you are using. For the hosted version
|
||||||
|
of WorkAdventure, you can define tags related to the user in the [administration panel](https://workadventu.re/admin-guide/manage-members).
|
||||||
|
|
||||||
|
{.alert.alert-info}
|
||||||
|
You need to wait for the end of the initialization before accessing `WA.player.tags`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Tags: ', WA.player.tags);
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
### Listen to player movement
|
### Listen to player movement
|
||||||
```
|
```
|
||||||
WA.player.onPlayerMove(callback: HasPlayerMovedEventCallback): void;
|
WA.player.onPlayerMove(callback: HasPlayerMovedEventCallback): void;
|
||||||
|
|
|
@ -75,44 +75,58 @@ Example :
|
||||||
WA.room.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/');
|
WA.room.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Getting information on the current room
|
### Get the room id
|
||||||
```
|
|
||||||
WA.room.getCurrentRoom(): Promise<Room>
|
|
||||||
```
|
|
||||||
Return a promise that resolves to a `Room` object with the following attributes :
|
|
||||||
* **id (string) :** ID of the current room
|
|
||||||
* **map (ITiledMap) :** contains the JSON map file with the properties that were set by the script if `setProperty` was called.
|
|
||||||
* **mapUrl (string) :** Url of the JSON map file
|
|
||||||
* **startLayer (string | null) :** Name of the layer where the current user started, only if different from `start` layer
|
|
||||||
|
|
||||||
Example :
|
```
|
||||||
```javascript
|
WA.room.id: string;
|
||||||
WA.room.getCurrentRoom((room) => {
|
```
|
||||||
if (room.id === '42') {
|
|
||||||
console.log(room.map);
|
The ID of the current room is available from the `WA.room.id` property.
|
||||||
window.open(room.mapUrl, '_blank');
|
|
||||||
}
|
{.alert.alert-info}
|
||||||
|
You need to wait for the end of the initialization before accessing `WA.room.id`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Room id: ', WA.room.id);
|
||||||
|
// Will output something like: '/@/myorg/myworld/myroom', or '/_/global/mymap.org/map.json"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Getting information on the current user
|
### Get the map URL
|
||||||
```
|
|
||||||
WA.player.getCurrentUser(): Promise<User>
|
|
||||||
```
|
|
||||||
Return a promise that resolves to a `User` object with the following attributes :
|
|
||||||
* **id (string) :** ID of the current user
|
|
||||||
* **nickName (string) :** name displayed above the current user
|
|
||||||
* **tags (string[]) :** list of all the tags of the current user
|
|
||||||
|
|
||||||
Example :
|
```
|
||||||
```javascript
|
WA.room.mapURL: string;
|
||||||
WA.room.getCurrentUser().then((user) => {
|
```
|
||||||
if (user.nickName === 'ABC') {
|
|
||||||
console.log(user.tags);
|
The URL of the map is available from the `WA.room.mapURL` property.
|
||||||
}
|
|
||||||
|
{.alert.alert-info}
|
||||||
|
You need to wait for the end of the initialization before accessing `WA.room.mapURL`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Map URL: ', WA.room.mapURL);
|
||||||
|
// Will output something like: 'https://mymap.org/map.json"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Getting map data
|
||||||
|
```
|
||||||
|
WA.room.getMap(): Promise<ITiledMap>
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns a promise that resolves to the JSON map file.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const map = await WA.room.getMap();
|
||||||
|
console.log("Map generated with Tiled version ", map.tiledversion);
|
||||||
|
```
|
||||||
|
|
||||||
|
Check the [Tiled documentation to learn more about the format of the JSON map](https://doc.mapeditor.org/en/stable/reference/json-map-format/).
|
||||||
|
|
||||||
### Changing tiles
|
### Changing tiles
|
||||||
```
|
```
|
||||||
WA.room.setTiles(tiles: TileDescriptor[]): void
|
WA.room.setTiles(tiles: TileDescriptor[]): void
|
||||||
|
|
|
@ -4,10 +4,11 @@ export const isGameStateEvent = new tg.IsInterface()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
roomId: tg.isString,
|
roomId: tg.isString,
|
||||||
mapUrl: tg.isString,
|
mapUrl: tg.isString,
|
||||||
nickname: tg.isUnion(tg.isString, tg.isNull),
|
nickname: tg.isString,
|
||||||
uuid: tg.isUnion(tg.isString, tg.isUndefined),
|
uuid: tg.isUnion(tg.isString, tg.isUndefined),
|
||||||
startLayerName: tg.isUnion(tg.isString, tg.isNull),
|
startLayerName: tg.isUnion(tg.isString, tg.isNull),
|
||||||
tags: tg.isArray(tg.isString),
|
tags: tg.isArray(tg.isString),
|
||||||
|
variables: tg.isObject,
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,7 +9,7 @@ import type { OpenCoWebSiteEvent } from "./OpenCoWebSiteEvent";
|
||||||
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
||||||
import type { OpenTabEvent } from "./OpenTabEvent";
|
import type { OpenTabEvent } from "./OpenTabEvent";
|
||||||
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
||||||
import type { DataLayerEvent } from "./DataLayerEvent";
|
import type { MapDataEvent } from "./MapDataEvent";
|
||||||
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";
|
||||||
|
@ -19,8 +19,6 @@ import type { MenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent";
|
||||||
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
||||||
import type { SetTilesEvent } from "./SetTilesEvent";
|
import type { SetTilesEvent } from "./SetTilesEvent";
|
||||||
import type { SetVariableEvent } from "./SetVariableEvent";
|
import type { SetVariableEvent } from "./SetVariableEvent";
|
||||||
import type {InitEvent} from "./InitEvent";
|
|
||||||
|
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
data: T;
|
data: T;
|
||||||
|
@ -46,7 +44,6 @@ export type IframeEventMap = {
|
||||||
showLayer: LayerEvent;
|
showLayer: LayerEvent;
|
||||||
hideLayer: LayerEvent;
|
hideLayer: LayerEvent;
|
||||||
setProperty: SetPropertyEvent;
|
setProperty: SetPropertyEvent;
|
||||||
getDataLayer: undefined;
|
|
||||||
loadSound: LoadSoundEvent;
|
loadSound: LoadSoundEvent;
|
||||||
playSound: PlaySoundEvent;
|
playSound: PlaySoundEvent;
|
||||||
stopSound: null;
|
stopSound: null;
|
||||||
|
@ -54,8 +51,6 @@ export type IframeEventMap = {
|
||||||
registerMenuCommand: MenuItemRegisterEvent;
|
registerMenuCommand: MenuItemRegisterEvent;
|
||||||
setTiles: SetTilesEvent;
|
setTiles: SetTilesEvent;
|
||||||
setVariable: SetVariableEvent;
|
setVariable: SetVariableEvent;
|
||||||
// A script/iframe is ready to receive events
|
|
||||||
ready: null;
|
|
||||||
};
|
};
|
||||||
export interface IframeEvent<T extends keyof IframeEventMap> {
|
export interface IframeEvent<T extends keyof IframeEventMap> {
|
||||||
type: T;
|
type: T;
|
||||||
|
@ -72,10 +67,8 @@ export interface IframeResponseEventMap {
|
||||||
leaveEvent: EnterLeaveEvent;
|
leaveEvent: EnterLeaveEvent;
|
||||||
buttonClickedEvent: ButtonClickedEvent;
|
buttonClickedEvent: ButtonClickedEvent;
|
||||||
hasPlayerMoved: HasPlayerMovedEvent;
|
hasPlayerMoved: HasPlayerMovedEvent;
|
||||||
dataLayer: DataLayerEvent;
|
|
||||||
menuItemClicked: MenuItemClickedEvent;
|
menuItemClicked: MenuItemClickedEvent;
|
||||||
setVariable: SetVariableEvent;
|
setVariable: SetVariableEvent;
|
||||||
init: InitEvent;
|
|
||||||
}
|
}
|
||||||
export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
|
export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
|
||||||
type: T;
|
type: T;
|
||||||
|
@ -94,8 +87,14 @@ export const isIframeResponseEventWrapper = (event: {
|
||||||
export type IframeQueryMap = {
|
export type IframeQueryMap = {
|
||||||
getState: {
|
getState: {
|
||||||
query: undefined,
|
query: undefined,
|
||||||
answer: GameStateEvent
|
answer: GameStateEvent,
|
||||||
|
callback: () => GameStateEvent|PromiseLike<GameStateEvent>
|
||||||
},
|
},
|
||||||
|
getMapData: {
|
||||||
|
query: undefined,
|
||||||
|
answer: MapDataEvent,
|
||||||
|
callback: () => MapDataEvent|PromiseLike<GameStateEvent>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IframeQuery<T extends keyof IframeQueryMap> {
|
export interface IframeQuery<T extends keyof IframeQueryMap> {
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import * as tg from "generic-type-guard";
|
|
||||||
|
|
||||||
export const isInitEvent =
|
|
||||||
new tg.IsInterface().withProperties({
|
|
||||||
variables: tg.isObject
|
|
||||||
}).get();
|
|
||||||
/**
|
|
||||||
* A message sent from the game just after an iFrame opens, to send all important data (like variables)
|
|
||||||
*/
|
|
||||||
export type InitEvent = tg.GuardedType<typeof isInitEvent>;
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
export const isDataLayerEvent = new tg.IsInterface()
|
export const isMapDataEvent = new tg.IsInterface()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
data: tg.isObject,
|
data: tg.isObject,
|
||||||
})
|
})
|
||||||
|
@ -9,4 +9,4 @@ export const isDataLayerEvent = new tg.IsInterface()
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers
|
* A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers
|
||||||
*/
|
*/
|
||||||
export type DataLayerEvent = tg.GuardedType<typeof isDataLayerEvent>;
|
export type MapDataEvent = tg.GuardedType<typeof isMapDataEvent>;
|
|
@ -26,7 +26,7 @@ import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
|
||||||
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
|
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
|
||||||
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
||||||
import { isMenuItemRegisterEvent } from "./Events/ui/MenuItemRegisterEvent";
|
import { isMenuItemRegisterEvent } from "./Events/ui/MenuItemRegisterEvent";
|
||||||
import type { DataLayerEvent } from "./Events/DataLayerEvent";
|
import type { MapDataEvent } from "./Events/MapDataEvent";
|
||||||
import type { GameStateEvent } from "./Events/GameStateEvent";
|
import type { GameStateEvent } from "./Events/GameStateEvent";
|
||||||
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
||||||
import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
||||||
|
@ -34,8 +34,6 @@ import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "
|
||||||
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
||||||
import { isSetVariableIframeEvent, SetVariableEvent } from "./Events/SetVariableEvent";
|
import { isSetVariableIframeEvent, SetVariableEvent } from "./Events/SetVariableEvent";
|
||||||
|
|
||||||
type AnswererCallback<T extends keyof IframeQueryMap> = (query: IframeQueryMap[T]['query']) => IframeQueryMap[T]['answer']|Promise<IframeQueryMap[T]['answer']>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens to messages from iframes and turn those messages into easy to use observables.
|
* Listens to messages from iframes and turn those messages into easy to use observables.
|
||||||
* Also allows to send messages to those iframes.
|
* Also allows to send messages to those iframes.
|
||||||
|
@ -89,9 +87,6 @@ class IframeListener {
|
||||||
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
||||||
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
||||||
|
|
||||||
private readonly _dataLayerChangeStream: Subject<void> = new Subject();
|
|
||||||
public readonly dataLayerChangeStream = this._dataLayerChangeStream.asObservable();
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
@ -118,9 +113,14 @@ class IframeListener {
|
||||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||||
private sendPlayerMove: boolean = false;
|
private sendPlayerMove: boolean = false;
|
||||||
|
|
||||||
private answerers: {
|
|
||||||
[key in keyof IframeQueryMap]?: AnswererCallback<key>
|
// Note: we are forced to type this in "any" because of https://github.com/microsoft/TypeScript/issues/31904
|
||||||
} = {};
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
private answerers: any = {};
|
||||||
|
/*private answerers: {
|
||||||
|
[key in keyof IframeQueryMap]?: (query: IframeQueryMap[key]['query']) => IframeQueryMap[key]['answer']|PromiseLike<IframeQueryMap[key]['answer']>
|
||||||
|
} = {};*/
|
||||||
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
|
@ -194,9 +194,7 @@ class IframeListener {
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (isIframeEventWrapper(payload)) {
|
} else if (isIframeEventWrapper(payload)) {
|
||||||
if (payload.type === 'ready') {
|
if (payload.type === "showLayer" && isLayerEvent(payload.data)) {
|
||||||
this._readyStream.next();
|
|
||||||
} else if (payload.type === "showLayer" && isLayerEvent(payload.data)) {
|
|
||||||
this._showLayerStream.next(payload.data);
|
this._showLayerStream.next(payload.data);
|
||||||
} else if (payload.type === "hideLayer" && isLayerEvent(payload.data)) {
|
} else if (payload.type === "hideLayer" && isLayerEvent(payload.data)) {
|
||||||
this._hideLayerStream.next(payload.data);
|
this._hideLayerStream.next(payload.data);
|
||||||
|
@ -239,8 +237,6 @@ class IframeListener {
|
||||||
this._removeBubbleStream.next();
|
this._removeBubbleStream.next();
|
||||||
} else if (payload.type == "onPlayerMove") {
|
} else if (payload.type == "onPlayerMove") {
|
||||||
this.sendPlayerMove = true;
|
this.sendPlayerMove = true;
|
||||||
} else if (payload.type == "getDataLayer") {
|
|
||||||
this._dataLayerChangeStream.next();
|
|
||||||
} else if (isMenuItemRegisterIframeEvent(payload)) {
|
} else if (isMenuItemRegisterIframeEvent(payload)) {
|
||||||
const data = payload.data.menutItem;
|
const data = payload.data.menutItem;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -269,13 +265,6 @@ class IframeListener {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendDataLayerEvent(dataLayerEvent: DataLayerEvent) {
|
|
||||||
this.postMessage({
|
|
||||||
type: "dataLayer",
|
|
||||||
data: dataLayerEvent,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the passed iFrame to send/receive messages via the API.
|
* Allows the passed iFrame to send/receive messages via the API.
|
||||||
*/
|
*/
|
||||||
|
@ -439,7 +428,7 @@ class IframeListener {
|
||||||
* @param key The "type" of the query we are answering
|
* @param key The "type" of the query we are answering
|
||||||
* @param callback
|
* @param callback
|
||||||
*/
|
*/
|
||||||
public registerAnswerer<T extends keyof IframeQueryMap>(key: T, callback: (query: IframeQueryMap[T]['query']) => IframeQueryMap[T]['answer']|Promise<IframeQueryMap[T]['answer']> ): void {
|
public registerAnswerer<T extends keyof IframeQueryMap>(key: T, callback: (query: IframeQueryMap[T]['query']) => IframeQueryMap[T]['answer']|PromiseLike<IframeQueryMap[T]['answer']> ): void {
|
||||||
this.answerers[key] = callback;
|
this.answerers[key] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,24 @@ import { isHasPlayerMovedEvent } from "../Events/HasPlayerMovedEvent";
|
||||||
|
|
||||||
const moveStream = new Subject<HasPlayerMovedEvent>();
|
const moveStream = new Subject<HasPlayerMovedEvent>();
|
||||||
|
|
||||||
|
let playerName: string|undefined;
|
||||||
|
|
||||||
|
export const setPlayerName = (name: string) => {
|
||||||
|
playerName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tags: string[]|undefined;
|
||||||
|
|
||||||
|
export const setTags = (_tags: string[]) => {
|
||||||
|
tags = _tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uuid: string|undefined;
|
||||||
|
|
||||||
|
export const setUuid = (_uuid: string|undefined) => {
|
||||||
|
uuid = _uuid;
|
||||||
|
}
|
||||||
|
|
||||||
export class WorkadventurePlayerCommands extends IframeApiContribution<WorkadventurePlayerCommands> {
|
export class WorkadventurePlayerCommands extends IframeApiContribution<WorkadventurePlayerCommands> {
|
||||||
callbacks = [
|
callbacks = [
|
||||||
apiCallback({
|
apiCallback({
|
||||||
|
@ -24,6 +42,29 @@ export class WorkadventurePlayerCommands extends IframeApiContribution<Workadven
|
||||||
data: null,
|
data: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get name() : string {
|
||||||
|
if (playerName === undefined) {
|
||||||
|
throw new Error('Player name not initialized yet. You should call WA.player.name within a WA.onInit callback.');
|
||||||
|
}
|
||||||
|
return playerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
get tags() : string[] {
|
||||||
|
if (tags === undefined) {
|
||||||
|
throw new Error('Tags not initialized yet. You should call WA.player.tags within a WA.onInit callback.');
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() : string|undefined {
|
||||||
|
// Note: this is not a type, we are checking if playerName is undefined because playerName cannot be undefined
|
||||||
|
// while uuid could.
|
||||||
|
if (playerName === undefined) {
|
||||||
|
throw new Error('Player id not initialized yet. You should call WA.player.id within a WA.onInit callback.');
|
||||||
|
}
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new WorkadventurePlayerCommands();
|
export default new WorkadventurePlayerCommands();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {Observable, Subject} from "rxjs";
|
import {Observable, Subject} from "rxjs";
|
||||||
|
|
||||||
import { isDataLayerEvent } from "../Events/DataLayerEvent";
|
import { isMapDataEvent } from "../Events/MapDataEvent";
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
||||||
import { isGameStateEvent } from "../Events/GameStateEvent";
|
import { isGameStateEvent } from "../Events/GameStateEvent";
|
||||||
|
|
||||||
|
@ -11,32 +11,15 @@ import type {SetPropertyEvent} from "../Events/setPropertyEvent";
|
||||||
import {isSetVariableEvent, SetVariableEvent} from "../Events/SetVariableEvent";
|
import {isSetVariableEvent, SetVariableEvent} from "../Events/SetVariableEvent";
|
||||||
|
|
||||||
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
||||||
import type { DataLayerEvent } from "../Events/DataLayerEvent";
|
import type { MapDataEvent } from "../Events/MapDataEvent";
|
||||||
import type { GameStateEvent } from "../Events/GameStateEvent";
|
import type { GameStateEvent } from "../Events/GameStateEvent";
|
||||||
|
|
||||||
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
const dataLayerResolver = new Subject<DataLayerEvent>();
|
|
||||||
const stateResolvers = new Subject<GameStateEvent>();
|
|
||||||
const setVariableResolvers = new Subject<SetVariableEvent>();
|
const setVariableResolvers = new Subject<SetVariableEvent>();
|
||||||
const variables = new Map<string, unknown>();
|
const variables = new Map<string, unknown>();
|
||||||
const variableSubscribers = new Map<string, Subject<unknown>>();
|
const variableSubscribers = new Map<string, Subject<unknown>>();
|
||||||
|
|
||||||
let immutableDataPromise: Promise<GameStateEvent> | 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 {
|
interface TileDescriptor {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
@ -44,18 +27,16 @@ interface TileDescriptor {
|
||||||
layer: string;
|
layer: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGameState(): Promise<GameStateEvent> {
|
let roomId: string|undefined;
|
||||||
if (immutableDataPromise === undefined) {
|
|
||||||
immutableDataPromise = queryWorkadventure({ type: "getState", data: undefined });
|
export const setRoomId = (id: string) => {
|
||||||
}
|
roomId = id;
|
||||||
return immutableDataPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataLayer(): Promise<DataLayerEvent> {
|
let mapURL: string|undefined;
|
||||||
return new Promise<DataLayerEvent>((resolver, thrower) => {
|
|
||||||
dataLayerResolver.subscribe(resolver);
|
export const setMapURL = (url: string) => {
|
||||||
sendToWorkadventure({ type: "getDataLayer", data: null });
|
mapURL = url;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setVariableResolvers.subscribe((event) => {
|
setVariableResolvers.subscribe((event) => {
|
||||||
|
@ -82,13 +63,6 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
||||||
leaveStreams.get(payloadData.name)?.next();
|
leaveStreams.get(payloadData.name)?.next();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
apiCallback({
|
|
||||||
type: "dataLayer",
|
|
||||||
typeChecker: isDataLayerEvent,
|
|
||||||
callback: (payloadData) => {
|
|
||||||
dataLayerResolver.next(payloadData);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
apiCallback({
|
apiCallback({
|
||||||
type: "setVariable",
|
type: "setVariable",
|
||||||
typeChecker: isSetVariableEvent,
|
typeChecker: isSetVariableEvent,
|
||||||
|
@ -130,22 +104,9 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getCurrentRoom(): Promise<Room> {
|
async getMap(): Promise<ITiledMap> {
|
||||||
return getGameState().then((gameState) => {
|
const event = await queryWorkadventure({ type: "getMapData", data: undefined });
|
||||||
return getDataLayer().then((mapJson) => {
|
return event.data as ITiledMap;
|
||||||
return {
|
|
||||||
id: gameState.roomId,
|
|
||||||
map: mapJson.data as ITiledMap,
|
|
||||||
mapUrl: gameState.mapUrl,
|
|
||||||
startLayer: gameState.startLayerName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getCurrentUser(): Promise<User> {
|
|
||||||
return getGameState().then((gameState) => {
|
|
||||||
return { id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags };
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setTiles(tiles: TileDescriptor[]) {
|
setTiles(tiles: TileDescriptor[]) {
|
||||||
sendToWorkadventure({
|
sendToWorkadventure({
|
||||||
|
@ -177,6 +138,21 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
||||||
}
|
}
|
||||||
return subject.asObservable();
|
return subject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get id() : string {
|
||||||
|
if (roomId === undefined) {
|
||||||
|
throw new Error('Room id not initialized yet. You should call WA.room.id within a WA.onInit callback.');
|
||||||
|
}
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
get mapURL() : string {
|
||||||
|
if (mapURL === undefined) {
|
||||||
|
throw new Error('mapURL is not initialized yet. You should call WA.room.mapURL within a WA.onInit callback.');
|
||||||
|
}
|
||||||
|
return mapURL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new WorkadventureRoomCommands();
|
export default new WorkadventureRoomCommands();
|
||||||
|
|
|
@ -92,7 +92,6 @@ import { peerStore, screenSharingPeerStore } from "../../Stores/PeerStore";
|
||||||
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||||
import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore";
|
import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore";
|
||||||
import { SharedVariablesManager } from "./SharedVariablesManager";
|
import { SharedVariablesManager } from "./SharedVariablesManager";
|
||||||
import type {InitEvent} from "../../Api/Events/InitEvent";
|
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
|
@ -399,23 +398,6 @@ export class GameScene extends DirtyScene {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.iframeSubscriptionList.push(iframeListener.readyStream.subscribe((iframe) => {
|
|
||||||
this.connectionAnswerPromise.then(connection => {
|
|
||||||
// Generate init message for an iframe
|
|
||||||
// TODO: merge with GameStateEvent
|
|
||||||
const initEvent: InitEvent = {
|
|
||||||
variables: this.sharedVariablesManager.variables
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
// TODO: SEND INIT MESSAGE TO IFRAMES ONLY WHEN CONNECTION IS ESTABLISHED
|
|
||||||
// TODO: SEND INIT MESSAGE TO IFRAMES ONLY WHEN CONNECTION IS ESTABLISHED
|
|
||||||
// TODO: SEND INIT MESSAGE TO IFRAMES ONLY WHEN CONNECTION IS ESTABLISHED
|
|
||||||
// TODO: SEND INIT MESSAGE TO IFRAMES ONLY WHEN CONNECTION IS ESTABLISHED
|
|
||||||
// TODO: SEND INIT MESSAGE TO IFRAMES ONLY WHEN CONNECTION IS ESTABLISHED
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Now, let's load the script, if any
|
// Now, let's load the script, if any
|
||||||
const scripts = this.getScriptUrls(this.mapFile);
|
const scripts = this.getScriptUrls(this.mapFile);
|
||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
|
@ -1061,20 +1043,24 @@ ${escapedMessage}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.iframeSubscriptionList.push(
|
iframeListener.registerAnswerer('getMapData', () => {
|
||||||
iframeListener.dataLayerChangeStream.subscribe(() => {
|
return {
|
||||||
iframeListener.sendDataLayerEvent({ data: this.gameMap.getMap() });
|
data: this.gameMap.getMap()
|
||||||
})
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer('getState', () => {
|
iframeListener.registerAnswerer('getState', async () => {
|
||||||
|
// The sharedVariablesManager is not instantiated before the connection is established. So we need to wait
|
||||||
|
// for the connection to send back the answer.
|
||||||
|
await this.connectionAnswerPromise;
|
||||||
return {
|
return {
|
||||||
mapUrl: this.MapUrlFile,
|
mapUrl: this.MapUrlFile,
|
||||||
startLayerName: this.startPositionCalculator.startLayerName,
|
startLayerName: this.startPositionCalculator.startLayerName,
|
||||||
uuid: localUserStore.getLocalUser()?.uuid,
|
uuid: localUserStore.getLocalUser()?.uuid,
|
||||||
nickname: localUserStore.getName(),
|
nickname: this.playerName,
|
||||||
roomId: this.RoomId,
|
roomId: this.RoomId,
|
||||||
tags: this.connection ? this.connection.getAllTags() : [],
|
tags: this.connection ? this.connection.getAllTags() : [],
|
||||||
|
variables: this.sharedVariablesManager.variables,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
|
|
|
@ -11,12 +11,12 @@ import nav from "./Api/iframe/nav";
|
||||||
import controls from "./Api/iframe/controls";
|
import controls from "./Api/iframe/controls";
|
||||||
import ui from "./Api/iframe/ui";
|
import ui from "./Api/iframe/ui";
|
||||||
import sound from "./Api/iframe/sound";
|
import sound from "./Api/iframe/sound";
|
||||||
import room from "./Api/iframe/room";
|
import room, {setMapURL, setRoomId} from "./Api/iframe/room";
|
||||||
import player from "./Api/iframe/player";
|
import player, {setPlayerName, setTags, setUuid} from "./Api/iframe/player";
|
||||||
import type { ButtonDescriptor } from "./Api/iframe/Ui/ButtonDescriptor";
|
import type { ButtonDescriptor } from "./Api/iframe/Ui/ButtonDescriptor";
|
||||||
import type { Popup } from "./Api/iframe/Ui/Popup";
|
import type { Popup } from "./Api/iframe/Ui/Popup";
|
||||||
import type { Sound } from "./Api/iframe/Sound/Sound";
|
import type { Sound } from "./Api/iframe/Sound/Sound";
|
||||||
import { answerPromises, sendToWorkadventure} from "./Api/iframe/IframeApiContribution";
|
import {answerPromises, queryWorkadventure, sendToWorkadventure} from "./Api/iframe/IframeApiContribution";
|
||||||
|
|
||||||
const wa = {
|
const wa = {
|
||||||
ui,
|
ui,
|
||||||
|
@ -208,7 +208,15 @@ window.addEventListener(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Notify WorkAdventure that we are ready to receive data
|
// Notify WorkAdventure that we are ready to receive data
|
||||||
sendToWorkadventure({
|
queryWorkadventure({
|
||||||
type: 'ready',
|
type: 'getState',
|
||||||
data: null
|
data: undefined
|
||||||
});
|
}).then((state => {
|
||||||
|
setPlayerName(state.nickname);
|
||||||
|
setRoomId(state.roomId);
|
||||||
|
setMapURL(state.mapUrl);
|
||||||
|
setTags(state.tags);
|
||||||
|
setUuid(state.uuid);
|
||||||
|
|
||||||
|
// TODO: remove the WA.room.getRoom method and replace it with WA.room.getMapData and WA.player.nickname, etc...
|
||||||
|
}));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue