game state can be read out by the client APIs

# Conflicts:
#	front/src/Api/IframeListener.ts
#	front/src/Phaser/Game/GameScene.ts
#	front/src/iframe_api.ts
This commit is contained in:
jonny 2021-04-21 15:51:01 +02:00
parent 5dc2f0ac47
commit 3836d5037c
5 changed files with 74 additions and 0 deletions

View File

@ -0,0 +1,11 @@
import * as tg from "generic-type-guard";
export const isGameStateEvent =
new tg.IsInterface().withProperties({
roomId: tg.isString,
data:tg.isObject
}).get();
/**
* A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property.
*/
export type GameStateEvent = tg.GuardedType<typeof isGameStateEvent>;

View File

@ -12,6 +12,8 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent";
import {scriptUtils} from "./ScriptUtils";
import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent";
import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent";
import { GameStateEvent } from './Events/ApiGameStateEvent';
import { deepFreezeClone as deepFreezeClone } from '../utility';
/**
@ -52,6 +54,10 @@ class IframeListener {
private readonly _removeBubbleStream: Subject<void> = new Subject();
public readonly removeBubbleStream = this._removeBubbleStream.asObservable();
private readonly _gameStateStream: Subject<void> = new Subject();
public readonly gameStateStream = this._gameStateStream.asObservable();
private readonly iframes = new Set<HTMLIFrameElement>();
private readonly scripts = new Map<string, HTMLIFrameElement>();
@ -103,6 +109,8 @@ class IframeListener {
}
else if (payload.type === 'removeBubble'){
this._removeBubbleStream.next();
}else if(payload.type=="getState"){
this._gameStateStream.next();
}
}
@ -111,6 +119,14 @@ class IframeListener {
}
sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) {
this.postMessage({
'type': 'gameState',
'data': deepFreezeClone(gameStateEvent)
});
}
/**
* Allows the passed iFrame to send/receive messages via the API.
*/

View File

@ -841,6 +841,13 @@ ${escapedMessage}
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{
this.userInputManager.restoreControls();
}));
this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(()=>{
iframeListener.sendFrozenGameStateEvent({
roomId:this.RoomId,
data: this.mapFile
})
}));
let scriptedBubbleSprite : Sprite;
this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{
scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white');

View File

@ -9,6 +9,7 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent";
import {OpenTabEvent} from "./Api/Events/OpenTabEvent";
import {GoToPageEvent} from "./Api/Events/GoToPageEvent";
import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent";
import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent';
interface WorkAdventureApi {
sendChatMessage(message: string, author: string): void;
@ -24,6 +25,7 @@ interface WorkAdventureApi {
restorePlayerControl() : void;
displayBubble() : void;
removeBubble() : void;
getGameState():Promise<unknown>
}
declare global {
@ -74,7 +76,23 @@ class Popup {
}
}
const stateResolvers:Array<(event:GameStateEvent)=>void> =[]
window.WA = {
getGameState(){
return new Promise<GameStateEvent>((resolver,thrower)=>{
stateResolvers.push(resolver);
window.parent.postMessage({
type:"getState"
},"*")
})
},
/**
* Send a message in the chat.
* Only the local user will receive this message.
@ -224,6 +242,10 @@ window.addEventListener('message', message => {
if (callback) {
callback(popup);
}
}else if(payload.type=="gameState" && isGameStateEvent(payloadData)){
stateResolvers.forEach(resolver=>{
resolver(payloadData);
})
}
}

18
front/src/utility.ts Normal file
View File

@ -0,0 +1,18 @@
export function deepFreezeClone<T> (obj:T):Readonly<T> {
return deepFreeze(JSON.parse(JSON.stringify(obj)));
}
function deepFreeze<T> (obj:T):T{
Object.freeze(obj);
if (obj === undefined) {
return obj;
}
const propertyNames = Object.getOwnPropertyNames(obj) as Array<keyof T>;
propertyNames.forEach(function (prop) {
if (obj[prop] !== null&& (typeof obj[prop] === "object" || typeof obj[prop] === "function") && !Object.isFrozen(obj[prop])) {
deepFreezeClone(obj[prop]);
}
});
return obj;
}