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:
parent
5dc2f0ac47
commit
3836d5037c
5 changed files with 74 additions and 0 deletions
11
front/src/Api/Events/ApiGameStateEvent.ts
Normal file
11
front/src/Api/Events/ApiGameStateEvent.ts
Normal 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>;
|
|
@ -12,6 +12,8 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent";
|
||||||
import {scriptUtils} from "./ScriptUtils";
|
import {scriptUtils} from "./ScriptUtils";
|
||||||
import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent";
|
import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent";
|
||||||
import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent";
|
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();
|
private readonly _removeBubbleStream: Subject<void> = new Subject();
|
||||||
public readonly removeBubbleStream = this._removeBubbleStream.asObservable();
|
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 iframes = new Set<HTMLIFrameElement>();
|
||||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||||
|
|
||||||
|
@ -103,6 +109,8 @@ class IframeListener {
|
||||||
}
|
}
|
||||||
else if (payload.type === 'removeBubble'){
|
else if (payload.type === 'removeBubble'){
|
||||||
this._removeBubbleStream.next();
|
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.
|
* Allows the passed iFrame to send/receive messages via the API.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -841,6 +841,13 @@ ${escapedMessage}
|
||||||
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{
|
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{
|
||||||
this.userInputManager.restoreControls();
|
this.userInputManager.restoreControls();
|
||||||
}));
|
}));
|
||||||
|
this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(()=>{
|
||||||
|
iframeListener.sendFrozenGameStateEvent({
|
||||||
|
roomId:this.RoomId,
|
||||||
|
data: this.mapFile
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
let scriptedBubbleSprite : Sprite;
|
let scriptedBubbleSprite : Sprite;
|
||||||
this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{
|
this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{
|
||||||
scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white');
|
scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white');
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent";
|
||||||
import {OpenTabEvent} from "./Api/Events/OpenTabEvent";
|
import {OpenTabEvent} from "./Api/Events/OpenTabEvent";
|
||||||
import {GoToPageEvent} from "./Api/Events/GoToPageEvent";
|
import {GoToPageEvent} from "./Api/Events/GoToPageEvent";
|
||||||
import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent";
|
import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent";
|
||||||
|
import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent';
|
||||||
|
|
||||||
interface WorkAdventureApi {
|
interface WorkAdventureApi {
|
||||||
sendChatMessage(message: string, author: string): void;
|
sendChatMessage(message: string, author: string): void;
|
||||||
|
@ -24,6 +25,7 @@ interface WorkAdventureApi {
|
||||||
restorePlayerControl() : void;
|
restorePlayerControl() : void;
|
||||||
displayBubble() : void;
|
displayBubble() : void;
|
||||||
removeBubble() : void;
|
removeBubble() : void;
|
||||||
|
getGameState():Promise<unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -74,7 +76,23 @@ class Popup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const stateResolvers:Array<(event:GameStateEvent)=>void> =[]
|
||||||
|
|
||||||
window.WA = {
|
window.WA = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getGameState(){
|
||||||
|
return new Promise<GameStateEvent>((resolver,thrower)=>{
|
||||||
|
stateResolvers.push(resolver);
|
||||||
|
window.parent.postMessage({
|
||||||
|
type:"getState"
|
||||||
|
},"*")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message in the chat.
|
* Send a message in the chat.
|
||||||
* Only the local user will receive this message.
|
* Only the local user will receive this message.
|
||||||
|
@ -224,6 +242,10 @@ window.addEventListener('message', message => {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(popup);
|
callback(popup);
|
||||||
}
|
}
|
||||||
|
}else if(payload.type=="gameState" && isGameStateEvent(payloadData)){
|
||||||
|
stateResolvers.forEach(resolver=>{
|
||||||
|
resolver(payloadData);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
18
front/src/utility.ts
Normal file
18
front/src/utility.ts
Normal 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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue