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

This commit is contained in:
_Bastler
2021-07-01 12:10:53 +02:00
14 changed files with 764 additions and 7 deletions
+3 -3
View File
@@ -18,7 +18,7 @@ import type { PlaySoundEvent } from "./PlaySoundEvent";
import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent";
import type { MenuItemRegisterEvent } from './ui/MenuItemRegisterEvent';
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
import type { SetTilesEvent } from "./SetTilesEvent";
export interface TypedMessageEvent<T> extends MessageEvent {
data: T
@@ -26,7 +26,6 @@ export interface TypedMessageEvent<T> extends MessageEvent {
export type IframeEventMap = {
//getState: GameStateEvent,
// updateTile: UpdateTileEvent
loadPage: LoadPageEvent
chat: ChatEvent,
openPopup: OpenPopupEvent
@@ -46,7 +45,8 @@ export type IframeEventMap = {
getDataLayer: undefined
loadSound: LoadSoundEvent
playSound: PlaySoundEvent
stopSound: null,
stopSound: null
setTiles: SetTilesEvent
getState: undefined,
registerMenuCommand: MenuItemRegisterEvent
}
+15
View File
@@ -0,0 +1,15 @@
import * as tg from "generic-type-guard";
export const isSetTilesEvent =
tg.isArray(
new tg.IsInterface().withProperties({
x: tg.isNumber,
y: tg.isNumber,
tile: tg.isUnion(tg.isNumber, tg.isString),
layer: tg.isString
}).get()
);
/**
* A message sent from the iFrame to the game to set one or many tiles.
*/
export type SetTilesEvent = tg.GuardedType<typeof isSetTilesEvent>;
+6 -1
View File
@@ -18,7 +18,6 @@ import {
TypedMessageEvent
} from "./Events/IframeEvent";
import type {UserInputChatEvent} from "./Events/UserInputChatEvent";
//import { isLoadPageEvent } from './Events/LoadPageEvent';
import {isPlaySoundEvent, PlaySoundEvent} from "./Events/PlaySoundEvent";
import {isStopSoundEvent, StopSoundEvent} from "./Events/StopSoundEvent";
import {isLoadSoundEvent, LoadSoundEvent} from "./Events/LoadSoundEvent";
@@ -30,6 +29,7 @@ import type {GameStateEvent} from "./Events/GameStateEvent";
import type {HasPlayerMovedEvent} from "./Events/HasPlayerMovedEvent";
import {isLoadPageEvent} from "./Events/LoadPageEvent";
import {handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent} from "./Events/ui/MenuItemRegisterEvent";
import {SetTilesEvent, isSetTilesEvent} from "./Events/SetTilesEvent";
/**
* Listens to messages from iframes and turn those messages into easy to use observables.
@@ -106,6 +106,9 @@ class IframeListener {
private readonly _loadSoundStream: Subject<LoadSoundEvent> = new Subject();
public readonly loadSoundStream = this._loadSoundStream.asObservable();
private readonly _setTilesStream: Subject<SetTilesEvent> = new Subject();
public readonly setTilesStream = this._setTilesStream.asObservable();
private readonly iframes = new Set<HTMLIFrameElement>();
private readonly iframeCloseCallbacks = new Map<HTMLIFrameElement, (() => void)[]>();
private readonly scripts = new Map<string, HTMLIFrameElement>();
@@ -202,6 +205,8 @@ class IframeListener {
this._unregisterMenuCommandStream.next(data);
})
handleMenuItemRegistrationEvent(payload.data)
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
this._setTilesStream.next(payload.data);
}
}
}, false);
+15
View File
@@ -31,6 +31,14 @@ interface User {
tags: string[];
}
interface TileDescriptor {
x: number
y: number
tile: number | string
layer: string
}
function getGameState(): Promise<GameStateEvent> {
if (immutableDataPromise === undefined) {
immutableDataPromise = new Promise<GameStateEvent>((resolver, thrower) => {
@@ -129,6 +137,13 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
return { id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags };
});
}
setTiles(tiles: TileDescriptor[]) {
sendToWorkadventure({
type: 'setTiles',
data: tiles
})
}
}
export default new WorkadventureRoomCommands();
+55 -1
View File
@@ -13,8 +13,9 @@ export class GameMap {
private key: number | undefined;
private lastProperties = new Map<string, string | boolean | number>();
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
private tileNameMap = new Map<string, number>();
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapLayerProperty> } = {}
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapLayerProperty> } = {};
public readonly flatLayers: ITiledMapLayer[];
public readonly phaserLayers: TilemapLayer[] = [];
@@ -36,6 +37,9 @@ export class GameMap {
if (tile.properties) {
this.tileSetPropertyMap[tileset.firstgid + tile.id] = tile.properties
tile.properties.forEach(prop => {
if (prop.name == 'name' && typeof prop.value == "string") {
this.tileNameMap.set(prop.value, tileset.firstgid + tile.id);
}
if (prop.name == "exitUrl" && typeof prop.value == "string") {
this.exitUrls.push(prop.value);
}
@@ -130,6 +134,10 @@ export class GameMap {
return this.map;
}
private getTileProperty(index: number): Array<ITiledMapLayerProperty> {
return this.tileSetPropertyMap[index];
}
private trigger(propName: string, oldValue: string | number | boolean | undefined, newValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) {
const callbacksArray = this.callbacks.get(propName);
if (callbacksArray !== undefined) {
@@ -165,4 +173,50 @@ export class GameMap {
}
}
private putTileInFlatLayer(index: number, x: number, y: number, layer: string): void {
const fLayer = this.findLayer(layer);
if ( fLayer == undefined ) {
console.error("The layer that you want to change doesn't exist.");
return;
}
if (fLayer.type !== 'tilelayer') {
console.error("The layer that you want to change is not a tilelayer. Tile can only be put in tilelayer.");
return;
}
if (typeof fLayer.data === "string") {
console.error("Data of the layer that you want to change is only readable.");
return;
}
fLayer.data[x+y*fLayer.height] = index;
}
public putTile(tile: string | number, x: number, y: number, layer: string): void {
const phaserLayer = this.findPhaserLayer(layer);
if ( phaserLayer ) {
const tileIndex = this.getIndexForTileType(tile);
if ( tileIndex !== undefined ) {
this.putTileInFlatLayer(tileIndex, x, y, layer);
const phaserTile = phaserLayer.putTileAt(tileIndex, x, y);
for (const property of this.getTileProperty(tileIndex)) {
if ( property.name === "collides" && property.value === "true") {
phaserTile.setCollision(true);
}
}
}
else {
console.error("The tile that you want to place doesn't exist.");
}
}
else {
console.error("The layer that you want to change is not a tilelayer. Tile can only be put in tilelayer.");
}
}
private getIndexForTileType(tile: string | number): number | undefined {
if (typeof tile == "number") {
return tile;
}
return this.tileNameMap.get(tile);
}
}
+9 -2
View File
@@ -995,8 +995,8 @@ export class GameScene extends DirtyScene {
})
);
this.iframeSubscriptionList.push(
iframeListener.enablePlayerControlStream.subscribe(() => {
this.iframeSubscriptionList.push(
iframeListener.enablePlayerControlStream.subscribe(()=>{
this.userInputManager.restoreControls();
})
);
@@ -1085,6 +1085,13 @@ export class GameScene extends DirtyScene {
}, this.userInputManager);
}
}));
)
this.iframeSubscriptionList.push(iframeListener.setTilesStream.subscribe((eventTiles) => {
for (const eventTile of eventTiles) {
this.gameMap.putTile(eventTile.tile, eventTile.x, eventTile.y, eventTile.layer);
}
}))
}
private setPropertyLayer(
+2
View File
@@ -16,6 +16,7 @@ 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";
import {sendToWorkadventure} from "./Api/iframe/IframeApiContribution";
const wa = {
ui,
@@ -36,6 +37,7 @@ const wa = {
console.warn('Method WA.sendChatMessage is deprecated. Please use WA.chat.sendChatMessage instead');
chat.sendChatMessage(message, author);
},
/**
* @deprecated Use WA.chat.disablePlayerControls instead
*/