Merge branch 'develop' of github.com:thecodingmachine/workadventure into twemojiEmoteMenu

This commit is contained in:
Lurkars 2021-06-29 08:37:08 +02:00
commit 81f2c8b746
5 changed files with 89 additions and 60 deletions

View File

@ -199,4 +199,4 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
msg: Environment deployed at https://play-${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re msg: "Environment deployed at https://play-${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re \nTests available at https://maps-${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re/tests"

View File

@ -123,11 +123,18 @@ class IframeListener {
} }
} }
const payload = message.data;
if (foundSrc === undefined) { if (foundSrc === undefined) {
if (isIframeEventWrapper(payload)) {
console.warn('It seems an iFrame is trying to communicate with WorkAdventure but was not explicitly granted the permission to do so. ' +
'If you are looking to use the WorkAdventure Scripting API inside an iFrame, you should allow the ' +
'iFrame to communicate with WorkAdventure by using the "openWebsiteAllowApi" property in your map (or passing "true" as a second' +
'parameter to WA.nav.openCoWebSite())');
}
return; return;
} }
const payload = message.data;
if (isIframeEventWrapper(payload)) { if (isIframeEventWrapper(payload)) {
if (payload.type === 'showLayer' && isLayerEvent(payload.data)) { if (payload.type === 'showLayer' && isLayerEvent(payload.data)) {
this._showLayerStream.next(payload.data); this._showLayerStream.next(payload.data);

View File

@ -1,53 +1,51 @@
import { Subject } from "rxjs"; import { Subject } from "rxjs";
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent';
import {IframeApiContribution, sendToWorkadventure} from './IframeApiContribution'; import { isDataLayerEvent } from "../Events/DataLayerEvent";
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
import { isGameStateEvent } from "../Events/GameStateEvent";
import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution";
import { apiCallback } from "./registeredCallbacks"; import { apiCallback } from "./registeredCallbacks";
import type {LayerEvent} from "../Events/LayerEvent";
import type {SetPropertyEvent} from "../Events/setPropertyEvent"; import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
import type {GameStateEvent} from "../Events/GameStateEvent"; import type { DataLayerEvent } from "../Events/DataLayerEvent";
import type {ITiledMap} from "../../Phaser/Map/ITiledMap"; import type { GameStateEvent } from "../Events/GameStateEvent";
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 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 dataLayerResolver = new Subject<DataLayerEvent>();
const stateResolvers = new Subject<GameStateEvent>(); const stateResolvers = new Subject<GameStateEvent>();
let immutableData: GameStateEvent; let immutableDataPromise: Promise<GameStateEvent> | undefined = undefined;
interface Room { interface Room {
id: string, id: string;
mapUrl: string, mapUrl: string;
map: ITiledMap, map: ITiledMap;
startLayer: string | null startLayer: string | null;
} }
interface User { interface User {
id: string | undefined, id: string | undefined;
nickName: string | null, nickName: string | null;
tags: string[] tags: string[];
} }
function getGameState(): Promise<GameStateEvent> { function getGameState(): Promise<GameStateEvent> {
if (immutableData) { if (immutableDataPromise === undefined) {
return Promise.resolve(immutableData); immutableDataPromise = new Promise<GameStateEvent>((resolver, thrower) => {
}
else {
return new Promise<GameStateEvent>((resolver, thrower) => {
stateResolvers.subscribe(resolver); stateResolvers.subscribe(resolver);
sendToWorkadventure({type: "getState", data: null}); sendToWorkadventure({ type: "getState", data: null });
}) });
} }
return immutableDataPromise;
} }
function getDataLayer(): Promise<DataLayerEvent> { function getDataLayer(): Promise<DataLayerEvent> {
return new Promise<DataLayerEvent>((resolver, thrower) => { return new Promise<DataLayerEvent>((resolver, thrower) => {
dataLayerResolver.subscribe(resolver); dataLayerResolver.subscribe(resolver);
sendToWorkadventure({type: "getDataLayer", data: null}) sendToWorkadventure({ type: "getDataLayer", data: null });
}) });
} }
class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomCommands> { class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomCommands> {
@ -57,31 +55,30 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
enterStreams.get(payloadData.name)?.next(); enterStreams.get(payloadData.name)?.next();
}, },
type: "enterEvent", type: "enterEvent",
typeChecker: isEnterLeaveEvent typeChecker: isEnterLeaveEvent,
}), }),
apiCallback({ apiCallback({
type: "leaveEvent", type: "leaveEvent",
typeChecker: isEnterLeaveEvent, typeChecker: isEnterLeaveEvent,
callback: (payloadData) => { callback: (payloadData) => {
leaveStreams.get(payloadData.name)?.next(); leaveStreams.get(payloadData.name)?.next();
} },
}), }),
apiCallback({ apiCallback({
type: "gameState", type: "gameState",
typeChecker: isGameStateEvent, typeChecker: isGameStateEvent,
callback: (payloadData) => { callback: (payloadData) => {
stateResolvers.next(payloadData); stateResolvers.next(payloadData);
} },
}), }),
apiCallback({ apiCallback({
type: "dataLayer", type: "dataLayer",
typeChecker: isDataLayerEvent, typeChecker: isDataLayerEvent,
callback: (payloadData) => { callback: (payloadData) => {
dataLayerResolver.next(payloadData); dataLayerResolver.next(payloadData);
} },
}), }),
] ];
onEnterZone(name: string, callback: () => void): void { onEnterZone(name: string, callback: () => void): void {
let subject = enterStreams.get(name); let subject = enterStreams.get(name);
@ -90,7 +87,6 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
enterStreams.set(name, subject); enterStreams.set(name, subject);
} }
subject.subscribe(callback); subject.subscribe(callback);
} }
onLeaveZone(name: string, callback: () => void): void { onLeaveZone(name: string, callback: () => void): void {
let subject = leaveStreams.get(name); let subject = leaveStreams.get(name);
@ -101,35 +97,38 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
subject.subscribe(callback); subject.subscribe(callback);
} }
showLayer(layerName: string): void { showLayer(layerName: string): void {
sendToWorkadventure({type: 'showLayer', data: {'name': layerName}}); sendToWorkadventure({ type: "showLayer", data: { name: layerName } });
} }
hideLayer(layerName: string): void { hideLayer(layerName: string): void {
sendToWorkadventure({type: 'hideLayer', data: {'name': layerName}}); sendToWorkadventure({ type: "hideLayer", data: { name: layerName } });
} }
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
sendToWorkadventure({ sendToWorkadventure({
type: 'setProperty', type: "setProperty",
data: { data: {
'layerName': layerName, layerName: layerName,
'propertyName': propertyName, propertyName: propertyName,
'propertyValue': propertyValue, propertyValue: propertyValue,
} },
}) });
} }
getCurrentRoom(): Promise<Room> { getCurrentRoom(): Promise<Room> {
return getGameState().then((gameState) => { return getGameState().then((gameState) => {
return getDataLayer().then((mapJson) => { return getDataLayer().then((mapJson) => {
return {id: gameState.roomId, map: mapJson.data as ITiledMap, mapUrl: gameState.mapUrl, startLayer: gameState.startLayerName}; return {
}) id: gameState.roomId,
}) map: mapJson.data as ITiledMap,
mapUrl: gameState.mapUrl,
startLayer: gameState.startLayerName,
};
});
});
} }
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 };
}) });
} }
} }
export default new WorkadventureRoomCommands(); export default new WorkadventureRoomCommands();

View File

@ -1,22 +1,30 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<script src="http://play.workadventure.localhost/iframe_api.js"></script> <script>
var script = document.createElement('script');
// Don't do this at home kids! The "document.referrer" part is actually inserting a XSS security.
// We are OK in this precise case because the HTML page is hosted on the "maps" domain that contains only static files.
script.setAttribute('src', document.referrer + 'iframe_api.js');
document.head.appendChild(script);
</script>
</head> </head>
<body> <body>
<button id="sendchat">Send chat message</button> <button id="sendchat">Send chat message</button>
<script> <script>
document.getElementById('sendchat').onclick = () => { document.getElementById('sendchat').onclick = () => {
WA.sendChatMessage('Hello world!', 'Mr ROBOT'); WA.chat.sendChatMessage('Hello world!', 'Mr ROBOT');
} }
</script> </script>
<div id="chatSent"></div> <div id="chatSent"></div>
<script> <script>
WA.onChatMessage((message => { window.addEventListener('load', () => {
const chatDiv = document.createElement('p'); WA.chat.onChatMessage((message => {
chatDiv.innerText = message; const chatDiv = document.createElement('p');
document.getElementById('chatSent').append(chatDiv); chatDiv.innerText = message;
})); document.getElementById('chatSent').append(chatDiv);
}));
})
</script> </script>
</body> </body>
</html> </html>

View File

@ -4,7 +4,7 @@
</head> </head>
<body> <body>
<label>Base test URL:</label> <label>Base test URL:</label>
<input id="baseurl" type="text" value="http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/" /> <input id="baseurl" type="text" value="" />
<table> <table>
<tr> <tr>
<th>Result</th> <th>Result</th>
@ -166,6 +166,21 @@
<script> <script>
const baseInput = document.getElementById('baseurl'); const baseInput = document.getElementById('baseurl');
let host = window.location.host;
let playHost;
if (host.startsWith('maps-')) {
playHost = 'play-'+host.substr(5);
} else if (host.startsWith('maps.')) {
playHost = 'play.'+host.substr(5);
} else {
playHost = 'localhost';
}
let completeUrl = window.location.protocol + '//' + playHost + '/_/global/' + host + window.location.pathname;
baseInput.value = completeUrl;
baseInput.addEventListener('change', init); baseInput.addEventListener('change', init);
function init() { function init() {