New methods refactored

This commit is contained in:
GRL 2021-06-23 11:32:11 +02:00
parent b50df10a49
commit bdb32a29e1
16 changed files with 246 additions and 141 deletions

View file

@ -6,6 +6,14 @@
- Enabled outlines on actionable item again (they were disabled when migrating to Phaser 3.50) #1218
- Enabled outlines on player names (when the mouse hovers on a player you can interact with) #1219
- Migrated the admin console to Svelte, and redesigned the console #1211
- New scripting API features :
- Use `WA.room.showLayer(): void` to show a layer
- Use `WA.room.hideLayer(): void` to hide a layer
- Use `WA.room.setProperty() : void` to add or change existing property of a layer
- Use `WA.player.onPlayerMove(): void` to track the movement of the current player
- Use `WA.room.getCurrentUser(): Promise<User>` to get the ID, name and tags of the current player
- Use `WA.room.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.ui.registerMenuCommand(): void` to add a custom menu
## Version 1.4.1
@ -48,13 +56,7 @@
- Added a new `DISPLAY_TERMS_OF_USE` environment variable to trigger the display of terms of use
- New scripting API features:
- 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

21
docs/maps/api-player.md Normal file
View file

@ -0,0 +1,21 @@
{.section-title.accent.text-primary}
# API Player functions Reference
### Listen to player movement
```
WA.player.onPlayerMove(callback: HasPlayerMovedEventCallback): void;
```
Listens to the movement of the current user and calls the callback. Sends an event when the user stops moving, changes direction and every 200ms when moving in the same direction.
The event has the following attributes :
* **moving (boolean):** **true** when the current player is moving, **false** otherwise.
* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving.
* **x (number):** coordinate X of the current player.
* **y (number):** coordinate Y of the current player.
**callback:** the function that will be called when the current player is moving. It contains the event.
Example :
```javascript
WA.player.onPlayerMove(console.log);
```

View file

@ -4,123 +4,9 @@
- [Navigation functions](api-nav.md)
- [Chat functions](api-chat.md)
- [Room functions](api-room.md)
- [Player functions](api-player.md)
- [UI functions](api-ui.md)
- [Sound functions](api-sound.md)
- [Controls functions](api-controls.md)
- [List of deprecated functions](api-deprecated.md)
### Show / Hide a layer
```
WA.showLayer(layerName : string): void
WA.hideLayer(layerName : string) : void
```
These 2 methods can be used to show and hide a layer.
Example :
```javascript
WA.showLayer('bottom');
//...
WA.hideLayer('bottom');
```
### Set/Create properties in a layer
```
WA.setProperty(layerName : string, propertyName : string, propertyValue : string | number | boolean | undefined) : void;
```
Set the value of the `propertyName` property of the layer `layerName` at `propertyValue`. If the property doesn't exist, create the property `propertyName` and set the value of the property at `propertyValue`.
Example :
```javascript
WA.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/');
```
### Listen to player movement
```
onPlayerMove(callback: HasPlayerMovedEventCallback): void;
```
Listens to the movement of the current user and calls the callback. Sends an event when the user stops moving, changes direction and every 200ms when moving in the same direction.
The event has the following attributes :
* **moving (boolean):** **true** when the current player is moving, **false** otherwise.
* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving.
* **x (number):** coordinate X of the current player.
* **y (number):** coordinate Y of the current player.
**callback:** the function that will be called when the current player is moving. It contains the event.
Example :
```javascript
WA.onPlayerMove(console.log);
```
### Getting informations on the current user
```
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.getCurrentUser().then((user) => {
if (user.nickName === 'ABC') {
console.log(user.tags);
}
})
```
### Getting informations on the current 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 setted 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.getCurrentRoom((room) => {
if (room.id === '42') {
console.log(room.map);
window.open(room.mapUrl, '_blank');
}
})
```
### Add a custom menu
```
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`.
Example :
```javascript
WA.registerMenuCommand('About', () => {
console.log("The About menu was clicked");
});
```
### Working with group layers
If you use group layers in your map, to reference a layer in a group you will need to use a `/` to join layer names together.
Example :
<div class="row">
<div class="col">
<img src="https://workadventu.re/img/docs/groupLayer.png" class="figure-img img-fluid rounded" alt="" />
</div>
</div>
The name of the layers of this map are :
* `entries/start`
* `bottom/ground/under`
* `bottom/build/carpet`
* `wall`
- [List of deprecated functions](api-deprecated.md)

View file

@ -1,6 +1,22 @@
{.section-title.accent.text-primary}
# API Room functions Reference
### Working with group layers
If you use group layers in your map, to reference a layer in a group you will need to use a `/` to join layer names together.
Example :
<div class="row">
<div class="col">
<img src="https://workadventu.re/img/docs/groupLayer.png" class="figure-img img-fluid rounded" alt="" />
</div>
</div>
The name of the layers of this map are :
* `entries/start`
* `bottom/ground/under`
* `bottom/build/carpet`
* `wall`
### Detecting when the user enters/leaves a zone
```
@ -31,3 +47,68 @@ WA.room.onLeaveZone('myZone', () => {
WA.chat.sendChatMessage("Goodbye!", 'Mr Robot');
})
```
### Show / Hide a layer
```
WA.room.showLayer(layerName : string): void
WA.room.hideLayer(layerName : string) : void
```
These 2 methods can be used to show and hide a layer.
Example :
```javascript
WA.room.showLayer('bottom');
//...
WA.room.hideLayer('bottom');
```
### Set/Create properties in a layer
```
WA.room.setProperty(layerName : string, propertyName : string, propertyValue : string | number | boolean | undefined) : void;
```
Set the value of the `propertyName` property of the layer `layerName` at `propertyValue`. If the property doesn't exist, create the property `propertyName` and set the value of the property at `propertyValue`.
Example :
```javascript
WA.room.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/');
```
### Getting information on the current room
```
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 setted 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.getCurrentRoom((room) => {
if (room.id === '42') {
console.log(room.map);
window.open(room.mapUrl, '_blank');
}
})
```
### Getting information on the current user
```
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.getCurrentUser().then((user) => {
if (user.nickName === 'ABC') {
console.log(user.tags);
}
})
```

View file

@ -66,16 +66,15 @@ WA.room.onLeaveZone('myZone', () => {
});
```
### register additional menu entries
adds an additional Entry to the main menu , these exist until the map is unloaded
### Add custom menu
```typescript
WA.ui.registerMenuCommand(menuCommand: string, callback: (menuCommand: string) => void): void
```
Example:
Add a custom menu item containing the text `commandDescriptor` in the main menu. A click on the menu will trigger the `callback`.
Custom menu exist only until the map is unloaded, or you leave the iframe zone of the script.
Example:
```javascript

View file

@ -101,7 +101,7 @@ You can now start by testing this with a simple message sent to the chat.
```html
...
<script>
WA.sendChatMessage('Hello world', 'Mr Robot');
WA.chat.sendChatMessage('Hello world', 'Mr Robot');
</script>
...
```

View file

@ -204,7 +204,7 @@ class IframeListener {
}
sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) {
sendGameStateEvent(gameStateEvent: GameStateEvent) {
this.postMessage({
'type': 'gameState',
'data': gameStateEvent

View file

@ -0,0 +1,29 @@
import {IframeApiContribution, sendToWorkadventure} from "./IframeApiContribution";
import type {HasPlayerMovedEvent, HasPlayerMovedEventCallback} from "../Events/HasPlayerMovedEvent";
import {Subject} from "rxjs";
import {apiCallback} from "./registeredCallbacks";
import {isHasPlayerMovedEvent} from "../Events/HasPlayerMovedEvent";
const moveStream = new Subject<HasPlayerMovedEvent>();
class WorkadventurePlayerCommands extends IframeApiContribution<WorkadventurePlayerCommands> {
callbacks = [
apiCallback({
type: 'hasPlayerMoved',
typeChecker: isHasPlayerMovedEvent,
callback: (payloadData) => {
moveStream.next(payloadData);
}
}),
]
onPlayerMove(callback: HasPlayerMovedEventCallback): void {
moveStream.subscribe(callback);
sendToWorkadventure({
type: 'onPlayerMove',
data: null
})
}
}
export default new WorkadventurePlayerCommands();

View file

@ -1,10 +1,54 @@
import { Subject } from "rxjs";
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent';
import { IframeApiContribution } from './IframeApiContribution';
import {IframeApiContribution, sendToWorkadventure} from './IframeApiContribution';
import { apiCallback } from "./registeredCallbacks";
import type {LayerEvent} from "../Events/LayerEvent";
import type {SetPropertyEvent} from "../Events/setPropertyEvent";
import type {GameStateEvent} from "../Events/GameStateEvent";
import type {ITiledMap} from "../../Phaser/Map/ITiledMap";
import type {DataLayerEvent} from "../Events/DataLayerEvent";
import {isGameStateEvent} from "../Events/GameStateEvent";
import {isDataLayerEvent} from "../Events/DataLayerEvent";
const enterStreams: 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>();
let immutableData: GameStateEvent;
interface Room {
id: string,
mapUrl: string,
map: ITiledMap,
startLayer: string | null
}
interface User {
id: string | undefined,
nickName: string | null,
tags: string[]
}
function getGameState(): Promise<GameStateEvent> {
if (immutableData) {
return Promise.resolve(immutableData);
}
else {
return new Promise<GameStateEvent>((resolver, thrower) => {
stateResolvers.subscribe(resolver);
sendToWorkadventure({type: "getState", data: null});
})
}
}
function getDataLayer(): Promise<DataLayerEvent> {
return new Promise<DataLayerEvent>((resolver, thrower) => {
dataLayerResolver.subscribe(resolver);
sendToWorkadventure({type: "getDataLayer", data: null})
})
}
class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomCommands> {
callbacks = [
@ -21,8 +65,21 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
callback: (payloadData) => {
leaveStreams.get(payloadData.name)?.next();
}
})
}),
apiCallback({
type: "gameState",
typeChecker: isGameStateEvent,
callback: (payloadData) => {
stateResolvers.next(payloadData);
}
}),
apiCallback({
type: "dataLayer",
typeChecker: isDataLayerEvent,
callback: (payloadData) => {
dataLayerResolver.next(payloadData);
}
}),
]
@ -43,6 +100,34 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
}
subject.subscribe(callback);
}
showLayer(layerName: string): void {
sendToWorkadventure({type: 'showLayer', data: {'name': layerName} as LayerEvent});
}
hideLayer(layerName: string): void {
sendToWorkadventure({type: 'hideLayer', data: {'name': layerName} as LayerEvent});
}
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
sendToWorkadventure({
type: 'setProperty',
data: {
'layerName': layerName,
'propertyName': propertyName,
'propertyValue': propertyValue,
} as SetPropertyEvent
})
}
getCurrentRoom(): Promise<Room> {
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<User> {
return getGameState().then((gameState) => {
return {id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags};
})
}
}

View file

@ -945,7 +945,7 @@ ${escapedMessage}
}))
this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => {
iframeListener.sendFrozenGameStateEvent({
iframeListener.sendGameStateEvent({
mapUrl: this.MapUrlFile,
startLayerName: this.startLayerName,
uuid: localUserStore.getLocalUser()?.uuid,

View file

@ -12,6 +12,7 @@ import controls from "./Api/iframe/controls";
import ui from "./Api/iframe/ui";
import sound from "./Api/iframe/sound";
import room from "./Api/iframe/room";
import player from "./Api/iframe/player";
import type { ButtonDescriptor } from "./Api/iframe/Ui/ButtonDescriptor";
import type { Popup } from "./Api/iframe/Ui/Popup";
import type { Sound } from "./Api/iframe/Sound/Sound";
@ -23,6 +24,7 @@ const wa = {
chat,
sound,
room,
player,
// All methods below are deprecated and should not be used anymore.
// They are kept here for backward compatibility.

View file

@ -5,7 +5,7 @@
</head>
<body>
<script>
WA.getCurrentRoom().then((room) => {
WA.room.getCurrentRoom().then((room) => {
console.log('id : ', room.id);
console.log('map : ', room.map);
console.log('mapUrl : ', room.mapUrl);

View file

@ -5,7 +5,7 @@
</head>
<body>
<script>
WA.getCurrentUser().then((user) => {
WA.room.getCurrentUser().then((user) => {
console.log('id : ', user.id);
console.log('nickName : ', user.nickName);
console.log('tags : ', user.tags);

View file

@ -6,7 +6,7 @@
<body>
<div id="playerMovement"></div>
<script>
WA.onPlayerMove(console.log);
WA.player.onPlayerMove(console.log);
</script>
</body>
</html>

View file

@ -5,8 +5,8 @@
</head>
<body>
<script>
WA.setProperty('iframeTest', 'openWebsite', 'https://www.wikipedia.org/');
WA.setProperty('metadata', 'openWebsite', 'https://www.wikipedia.org/');
WA.room.setProperty('iframeTest', 'openWebsite', 'https://www.wikipedia.org/');
WA.room.setProperty('metadata', 'openWebsite', 'https://www.wikipedia.org/');
</script>
</body>
</html>

View file

@ -10,10 +10,10 @@
<script>
document.getElementById('show/hideLayer').onclick = () => {
if (document.getElementById('show/hideLayer').checked) {
WA.showLayer('crystal');
WA.room.showLayer('crystal');
}
else {
WA.hideLayer('crystal');
WA.room.hideLayer('crystal');
}
}
</script>