Merge pull request #1320 from thecodingmachine/loadTileset

Load a json file that describe a tileset in Tile format.
This commit is contained in:
grégoire parant 2021-08-02 22:19:49 +02:00 committed by GitHub
commit fbe7440e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 474 additions and 75 deletions

View File

@ -1,10 +1,10 @@
## Version develop ## Version develop
### Updates ### Updates
- New scripting API features :
- Use `WA.room.loadTileset(url: string) : Promise<number>` to load a tileset from a JSON file.
- Rewrote the way authentification works: the auth jwt token can now contains an email instead of an uuid - Rewrote the way authentification works: the auth jwt token can now contains an email instead of an uuid
- Added an OpenId login flow than can be plugged to any OIDC provider. - Added an OpenId login flow than can be plugged to any OIDC provider.
-
## Version 1.4.10 ## Version 1.4.10

View File

@ -163,3 +163,17 @@ WA.room.setTiles([
{x: 9, y: 4, tile: 'blue', layer: 'setTiles'} {x: 9, y: 4, tile: 'blue', layer: 'setTiles'}
]); ]);
``` ```
### Loading a tileset
```
WA.room.loadTileset(url: string): Promise<number>
```
Load a tileset in JSON format from an url and return the id of the first tile of the loaded tileset.
You can create a tileset file in Tile Editor.
```javascript
WA.room.loadTileset("Assets/Tileset.json").then((firstId) => {
WA.room.setTiles([{x: 4, y: 4, tile: firstId, layer: 'bottom'}]);
})
```

View File

@ -1,5 +1,4 @@
import * as tg from "generic-type-guard"; import * as tg from "generic-type-guard";
import type { GameStateEvent } from "./GameStateEvent";
import type { ButtonClickedEvent } from "./ButtonClickedEvent"; import type { ButtonClickedEvent } from "./ButtonClickedEvent";
import type { ChatEvent } from "./ChatEvent"; import type { ChatEvent } from "./ChatEvent";
import type { ClosePopupEvent } from "./ClosePopupEvent"; import type { ClosePopupEvent } from "./ClosePopupEvent";
@ -10,7 +9,6 @@ import type { OpenCoWebSiteEvent } from "./OpenCoWebSiteEvent";
import type { OpenPopupEvent } from "./OpenPopupEvent"; import type { OpenPopupEvent } from "./OpenPopupEvent";
import type { OpenTabEvent } from "./OpenTabEvent"; import type { OpenTabEvent } from "./OpenTabEvent";
import type { UserInputChatEvent } from "./UserInputChatEvent"; import type { UserInputChatEvent } from "./UserInputChatEvent";
import type { MapDataEvent } from "./MapDataEvent";
import type { LayerEvent } from "./LayerEvent"; import type { LayerEvent } from "./LayerEvent";
import type { SetPropertyEvent } from "./setPropertyEvent"; import type { SetPropertyEvent } from "./setPropertyEvent";
import type { LoadSoundEvent } from "./LoadSoundEvent"; import type { LoadSoundEvent } from "./LoadSoundEvent";
@ -20,9 +18,11 @@ import type { MenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent";
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent"; import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
import type { SetTilesEvent } from "./SetTilesEvent"; import type { SetTilesEvent } from "./SetTilesEvent";
import type { SetVariableEvent } from "./SetVariableEvent"; import type { SetVariableEvent } from "./SetVariableEvent";
import {isGameStateEvent} from "./GameStateEvent"; import { isGameStateEvent } from "./GameStateEvent";
import {isMapDataEvent} from "./MapDataEvent"; import { isMapDataEvent } from "./MapDataEvent";
import {isSetVariableEvent} from "./SetVariableEvent"; import { isSetVariableEvent } from "./SetVariableEvent";
import type { LoadTilesetEvent } from "./LoadTilesetEvent";
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
export interface TypedMessageEvent<T> extends MessageEvent { export interface TypedMessageEvent<T> extends MessageEvent {
data: T; data: T;
@ -52,6 +52,7 @@ export type IframeEventMap = {
playSound: PlaySoundEvent; playSound: PlaySoundEvent;
stopSound: null; stopSound: null;
getState: undefined; getState: undefined;
loadTileset: LoadTilesetEvent;
registerMenuCommand: MenuItemRegisterEvent; registerMenuCommand: MenuItemRegisterEvent;
setTiles: SetTilesEvent; setTiles: SetTilesEvent;
}; };
@ -83,7 +84,6 @@ export const isIframeResponseEventWrapper = (event: {
type?: string; type?: string;
}): event is IframeResponseEvent<keyof IframeResponseEventMap> => typeof event.type === "string"; }): event is IframeResponseEvent<keyof IframeResponseEventMap> => typeof event.type === "string";
/** /**
* List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame. * List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame.
* Types are defined using Type guards that will actually bused to enforce and check types. * Types are defined using Type guards that will actually bused to enforce and check types.
@ -101,22 +101,26 @@ export const iframeQueryMapTypeGuards = {
query: isSetVariableEvent, query: isSetVariableEvent,
answer: tg.isUndefined, answer: tg.isUndefined,
}, },
} loadTileset: {
query: isLoadTilesetEvent,
answer: tg.isNumber,
},
};
type GuardedType<T> = T extends (x: unknown) => x is (infer T) ? T : never; type GuardedType<T> = T extends (x: unknown) => x is infer T ? T : never;
type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards; type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards;
type UnknownToVoid<T> = undefined extends T ? void : T; type UnknownToVoid<T> = undefined extends T ? void : T;
export type IframeQueryMap = { export type IframeQueryMap = {
[key in keyof IframeQueryMapTypeGuardsType]: { [key in keyof IframeQueryMapTypeGuardsType]: {
query: GuardedType<IframeQueryMapTypeGuardsType[key]['query']> query: GuardedType<IframeQueryMapTypeGuardsType[key]["query"]>;
answer: UnknownToVoid<GuardedType<IframeQueryMapTypeGuardsType[key]['answer']>> answer: UnknownToVoid<GuardedType<IframeQueryMapTypeGuardsType[key]["answer"]>>;
} };
} };
export interface IframeQuery<T extends keyof IframeQueryMap> { export interface IframeQuery<T extends keyof IframeQueryMap> {
type: T; type: T;
data: IframeQueryMap[T]['query']; data: IframeQueryMap[T]["query"];
} }
export interface IframeQueryWrapper<T extends keyof IframeQueryMap> { export interface IframeQueryWrapper<T extends keyof IframeQueryMap> {
@ -126,30 +130,34 @@ export interface IframeQueryWrapper<T extends keyof IframeQueryMap> {
export const isIframeQueryKey = (type: string): type is keyof IframeQueryMap => { export const isIframeQueryKey = (type: string): type is keyof IframeQueryMap => {
return type in iframeQueryMapTypeGuards; return type in iframeQueryMapTypeGuards;
} };
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQueryMap> => { export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQueryMap> => {
const type = event.type; const type = event.type;
if (typeof type !== 'string') { if (typeof type !== "string") {
return false; return false;
} }
if (!isIframeQueryKey(type)) { if (!isIframeQueryKey(type)) {
return false; return false;
} }
return iframeQueryMapTypeGuards[type].query(event.data); return iframeQueryMapTypeGuards[type].query(event.data);
} };
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper<keyof IframeQueryMap> => typeof event.id === 'number' && isIframeQuery(event.query); export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper<keyof IframeQueryMap> =>
typeof event.id === "number" && isIframeQuery(event.query);
export interface IframeAnswerEvent<T extends keyof IframeQueryMap> { export interface IframeAnswerEvent<T extends keyof IframeQueryMap> {
id: number; id: number;
type: T; type: T;
data: IframeQueryMap[T]['answer']; data: IframeQueryMap[T]["answer"];
} }
export const isIframeAnswerEvent = (event: { type?: string, id?: number }): event is IframeAnswerEvent<keyof IframeQueryMap> => typeof event.type === 'string' && typeof event.id === 'number'; export const isIframeAnswerEvent = (event: {
type?: string;
id?: number;
}): event is IframeAnswerEvent<keyof IframeQueryMap> => typeof event.type === "string" && typeof event.id === "number";
export interface IframeErrorAnswerEvent { export interface IframeErrorAnswerEvent {
id: number; id: number;
@ -157,4 +165,9 @@ export interface IframeErrorAnswerEvent {
error: string; error: string;
} }
export const isIframeErrorAnswerEvent = (event: { type?: string, id?: number, error?: string }): event is IframeErrorAnswerEvent => typeof event.type === 'string' && typeof event.id === 'number' && typeof event.error === 'string'; export const isIframeErrorAnswerEvent = (event: {
type?: string;
id?: number;
error?: string;
}): event is IframeErrorAnswerEvent =>
typeof event.type === "string" && typeof event.id === "number" && typeof event.error === "string";

View File

@ -0,0 +1,12 @@
import * as tg from "generic-type-guard";
export const isLoadTilesetEvent = new tg.IsInterface()
.withProperties({
url: tg.isString,
})
.get();
/**
* A message sent from the iFrame to the game to add a message in the chat.
*/
export type LoadTilesetEvent = tg.GuardedType<typeof isLoadTilesetEvent>;

View File

@ -12,7 +12,8 @@ import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent
import { import {
IframeErrorAnswerEvent, IframeErrorAnswerEvent,
IframeEvent, IframeEvent,
IframeEventMap, IframeQueryMap, IframeEventMap,
IframeQueryMap,
IframeResponseEvent, IframeResponseEvent,
IframeResponseEventMap, IframeResponseEventMap,
isIframeEventWrapper, isIframeEventWrapper,
@ -25,16 +26,16 @@ import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent";
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent"; import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent"; import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent"; import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
import { isMenuItemRegisterEvent } from "./Events/ui/MenuItemRegisterEvent";
import type { MapDataEvent } from "./Events/MapDataEvent";
import type { GameStateEvent } from "./Events/GameStateEvent";
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent"; import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
import { isLoadPageEvent } from "./Events/LoadPageEvent"; import { isLoadPageEvent } from "./Events/LoadPageEvent";
import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "./Events/ui/MenuItemRegisterEvent"; import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "./Events/ui/MenuItemRegisterEvent";
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent"; import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
import type { SetVariableEvent } from "./Events/SetVariableEvent"; import type { SetVariableEvent } from "./Events/SetVariableEvent";
type AnswererCallback<T extends keyof IframeQueryMap> = (query: IframeQueryMap[T]["query"], source: MessageEventSource | null) => IframeQueryMap[T]["answer"] | PromiseLike<IframeQueryMap[T]["answer"]>; type AnswererCallback<T extends keyof IframeQueryMap> = (
query: IframeQueryMap[T]["query"],
source: MessageEventSource | null
) => IframeQueryMap[T]["answer"] | PromiseLike<IframeQueryMap[T]["answer"]>;
/** /**
* Listens to messages from iframes and turn those messages into easy to use observables. * Listens to messages from iframes and turn those messages into easy to use observables.
@ -112,13 +113,11 @@ class IframeListener {
private readonly scripts = new Map<string, HTMLIFrameElement>(); private readonly scripts = new Map<string, HTMLIFrameElement>();
private sendPlayerMove: boolean = false; private sendPlayerMove: boolean = false;
// Note: we are forced to type this in unknown and later cast with "as" because of https://github.com/microsoft/TypeScript/issues/31904 // Note: we are forced to type this in unknown and later cast with "as" because of https://github.com/microsoft/TypeScript/issues/31904
private answerers: { private answerers: {
[str in keyof IframeQueryMap]?: unknown [str in keyof IframeQueryMap]?: unknown;
} = {}; } = {};
init() { init() {
window.addEventListener( window.addEventListener(
"message", "message",
@ -158,42 +157,56 @@ class IframeListener {
const answerer = this.answerers[query.type] as AnswererCallback<keyof IframeQueryMap> | undefined; const answerer = this.answerers[query.type] as AnswererCallback<keyof IframeQueryMap> | undefined;
if (answerer === undefined) { if (answerer === undefined) {
const errorMsg = 'The iFrame sent a message of type "'+query.type+'" but there is no service configured to answer these messages.'; const errorMsg =
'The iFrame sent a message of type "' +
query.type +
'" but there is no service configured to answer these messages.';
console.error(errorMsg); console.error(errorMsg);
iframe.contentWindow?.postMessage({ iframe.contentWindow?.postMessage(
id: queryId, {
type: query.type, id: queryId,
error: errorMsg type: query.type,
} as IframeErrorAnswerEvent, '*'); error: errorMsg,
} as IframeErrorAnswerEvent,
"*"
);
return; return;
} }
const errorHandler = (reason: unknown) => { const errorHandler = (reason: unknown) => {
console.error('An error occurred while responding to an iFrame query.', reason); console.error("An error occurred while responding to an iFrame query.", reason);
let reasonMsg: string = ''; let reasonMsg: string = "";
if (reason instanceof Error) { if (reason instanceof Error) {
reasonMsg = reason.message; reasonMsg = reason.message;
} else if (typeof reason === 'object') { } else if (typeof reason === "object") {
reasonMsg = reason ? reason.toString() : ''; reasonMsg = reason ? reason.toString() : "";
} else if (typeof reason === 'string') { } else if (typeof reason === "string") {
reasonMsg = reason; reasonMsg = reason;
} }
iframe?.contentWindow?.postMessage({ iframe?.contentWindow?.postMessage(
id: queryId, {
type: query.type, id: queryId,
error: reasonMsg type: query.type,
} as IframeErrorAnswerEvent, '*'); error: reasonMsg,
} as IframeErrorAnswerEvent,
"*"
);
}; };
try { try {
Promise.resolve(answerer(query.data, message.source)).then((value) => { Promise.resolve(answerer(query.data, message.source))
iframe?.contentWindow?.postMessage({ .then((value) => {
id: queryId, iframe?.contentWindow?.postMessage(
type: query.type, {
data: value id: queryId,
}, '*'); type: query.type,
}).catch(errorHandler); data: value,
},
"*"
);
})
.catch(errorHandler);
} catch (reason) { } catch (reason) {
errorHandler(reason); errorHandler(reason);
} }
@ -238,7 +251,7 @@ class IframeListener {
} else if (payload.type === "displayBubble") { } else if (payload.type === "displayBubble") {
this._displayBubbleStream.next(); this._displayBubbleStream.next();
} else if (payload.type === "removeBubble") { } else if (payload.type === "removeBubble") {
this._removeBubbleStream.next(); this._removeBubbleStream.next();
} else if (payload.type == "onPlayerMove") { } else if (payload.type == "onPlayerMove") {
this.sendPlayerMove = true; this.sendPlayerMove = true;
} else if (isMenuItemRegisterIframeEvent(payload)) { } else if (isMenuItemRegisterIframeEvent(payload)) {
@ -398,8 +411,8 @@ class IframeListener {
setVariable(setVariableEvent: SetVariableEvent) { setVariable(setVariableEvent: SetVariableEvent) {
this.postMessage({ this.postMessage({
'type': 'setVariable', type: "setVariable",
'data': setVariableEvent data: setVariableEvent,
}); });
} }
@ -420,7 +433,7 @@ class IframeListener {
* @param key The "type" of the query we are answering * @param key The "type" of the query we are answering
* @param callback * @param callback
*/ */
public registerAnswerer<T extends keyof IframeQueryMap>(key: T, callback: AnswererCallback<T> ): void { public registerAnswerer<T extends keyof IframeQueryMap>(key: T, callback: AnswererCallback<T>): void {
this.answerers[key] = callback; this.answerers[key] = callback;
} }
@ -432,13 +445,16 @@ class IframeListener {
// Let's dispatch the message to the other iframes // Let's dispatch the message to the other iframes
for (const iframe of this.iframes) { for (const iframe of this.iframes) {
if (iframe.contentWindow !== source) { if (iframe.contentWindow !== source) {
iframe.contentWindow?.postMessage({ iframe.contentWindow?.postMessage(
'type': 'setVariable', {
'data': { type: "setVariable",
key, data: {
value, key,
} value,
}, '*'); },
},
"*"
);
} }
} }
} }

View File

@ -1,4 +1,4 @@
import { Observable, Subject } from "rxjs"; import { Subject } from "rxjs";
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent"; import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
@ -105,6 +105,14 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
} }
return mapURL; return mapURL;
} }
async loadTileset(url: string): Promise<number> {
return await queryWorkadventure({
type: "loadTileset",
data: {
url: url,
},
});
}
} }
export default new WorkadventureRoomCommands(); export default new WorkadventureRoomCommands();

View File

@ -64,11 +64,8 @@ class ConnectionManager {
); );
localUserStore.setAuthToken(authToken); localUserStore.setAuthToken(authToken);
this.authToken = authToken; this.authToken = authToken;
room = await Room.createRoom( room = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
new URL(localUserStore.getLastRoomUrl())
);
urlManager.pushRoomIdToUrl(room); urlManager.pushRoomIdToUrl(room);
} else if (connexionType === GameConnexionTypes.register) { } else if (connexionType === GameConnexionTypes.register) {
//@deprecated //@deprecated
const organizationMemberToken = urlManager.getOrganizationToken(); const organizationMemberToken = urlManager.getOrganizationToken();

View File

@ -75,8 +75,6 @@ import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey }
import { waScaleManager } from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import { EmoteManager } from "./EmoteManager"; import { EmoteManager } from "./EmoteManager";
import EVENT_TYPE = Phaser.Scenes.Events; import EVENT_TYPE = Phaser.Scenes.Events;
import RenderTexture = Phaser.GameObjects.RenderTexture;
import Tilemap = Phaser.Tilemaps.Tilemap;
import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent"; import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent";
import AnimatedTiles from "phaser-animated-tiles"; import AnimatedTiles from "phaser-animated-tiles";
@ -88,6 +86,7 @@ import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStor
import { SharedVariablesManager } from "./SharedVariablesManager"; import { SharedVariablesManager } from "./SharedVariablesManager";
import { playersStore } from "../../Stores/PlayersStore"; import { playersStore } from "../../Stores/PlayersStore";
import { chatVisibilityStore } from "../../Stores/ChatStore"; import { chatVisibilityStore } from "../../Stores/ChatStore";
import Tileset = Phaser.Tilemaps.Tileset;
import { userIsAdminStore } from "../../Stores/GameStore"; import { userIsAdminStore } from "../../Stores/GameStore";
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
@ -222,6 +221,9 @@ export class GameScene extends DirtyScene {
//hook preload scene //hook preload scene
preload(): void { preload(): void {
//initialize frame event of scripting API
this.listenToIframeEvents();
const localUser = localUserStore.getLocalUser(); const localUser = localUserStore.getLocalUser();
const textures = localUser?.textures; const textures = localUser?.textures;
if (textures) { if (textures) {
@ -550,7 +552,6 @@ export class GameScene extends DirtyScene {
); );
this.triggerOnMapLayerPropertyChange(); this.triggerOnMapLayerPropertyChange();
this.listenToIframeEvents();
if (!this.room.isDisconnected()) { if (!this.room.isDisconnected()) {
this.connect(); this.connect();
@ -1084,8 +1085,74 @@ ${escapedMessage}
for (const eventTile of eventTiles) { for (const eventTile of eventTiles) {
this.gameMap.putTile(eventTile.tile, eventTile.x, eventTile.y, eventTile.layer); this.gameMap.putTile(eventTile.tile, eventTile.x, eventTile.y, eventTile.layer);
} }
this.markDirty();
}) })
); );
iframeListener.registerAnswerer("loadTileset", (eventTileset) => {
return this.connectionAnswerPromise.then(() => {
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
let newFirstgid = 1;
const lastTileset = this.mapFile.tilesets[this.mapFile.tilesets.length - 1];
if (lastTileset) {
//If there is at least one tileset in the tilemap then calculate the firstgid of the new tileset
newFirstgid = lastTileset.firstgid + lastTileset.tilecount;
}
return new Promise((resolve, reject) => {
this.load.on("filecomplete-json-" + eventTileset.url, () => {
let jsonTileset = this.cache.json.get(eventTileset.url);
const imageUrl = jsonTilesetDir + "/" + jsonTileset.image;
this.load.image(imageUrl, imageUrl);
this.load.on("filecomplete-image-" + imageUrl, () => {
//Add the firstgid of the tileset to the json file
jsonTileset = { ...jsonTileset, firstgid: newFirstgid };
this.mapFile.tilesets.push(jsonTileset);
this.Map.tilesets.push(
new Tileset(
jsonTileset.name,
jsonTileset.firstgid,
jsonTileset.tileWidth,
jsonTileset.tileHeight,
jsonTileset.margin,
jsonTileset.spacing,
jsonTileset.tiles
)
);
this.Terrains.push(
this.Map.addTilesetImage(
jsonTileset.name,
imageUrl,
jsonTileset.tilewidth,
jsonTileset.tileheight,
jsonTileset.margin,
jsonTileset.spacing
)
);
//destroy the tilemapayer because they are unique and we need to reuse their key and layerdData
for (const layer of this.Map.layers) {
layer.tilemapLayer.destroy(false);
}
//Create a new GameMap with the changed file
this.gameMap = new GameMap(this.mapFile, this.Map, this.Terrains);
//Destroy the colliders of the old tilemapLayer
this.physics.add.world.colliders.destroy();
//Create new colliders with the new GameMap
this.createCollisionWithPlayer();
//Create new trigger with the new GameMap
this.triggerOnMapLayerPropertyChange();
resolve(newFirstgid);
});
});
this.load.on("loaderror", () => {
console.error("Error while loading " + eventTileset.url + ".");
reject(-1);
});
this.load.json(eventTileset.url, eventTileset.url);
this.load.start();
});
});
});
} }
private setPropertyLayer( private setPropertyLayer(
@ -1153,7 +1220,7 @@ ${escapedMessage}
let targetRoom: Room; let targetRoom: Room;
try { try {
targetRoom = await Room.createRoom(roomUrl); targetRoom = await Room.createRoom(roomUrl);
} catch (e: unknown) { } catch (e) {
console.error('Error while fetching new room "' + roomUrl.toString() + '"', e); console.error('Error while fetching new room "' + roomUrl.toString() + '"', e);
this.mapTransitioning = false; this.mapTransitioning = false;
return; return;
@ -1207,6 +1274,7 @@ ${escapedMessage}
this.chatVisibilityUnsubscribe(); this.chatVisibilityUnsubscribe();
this.biggestAvailableAreaStoreUnsubscribe(); this.biggestAvailableAreaStoreUnsubscribe();
iframeListener.unregisterAnswerer("getState"); iframeListener.unregisterAnswerer("getState");
iframeListener.unregisterAnswerer("loadTileset");
this.sharedVariablesManager?.close(); this.sharedVariablesManager?.close();
mediaManager.hideGameOverlay(); mediaManager.hideGameOverlay();
@ -1279,7 +1347,7 @@ ${escapedMessage}
try { try {
const room = await Room.createRoom(exitRoomPath); const room = await Room.createRoom(exitRoomPath);
return gameManager.loadMap(room, this.scene); return gameManager.loadMap(room, this.scene);
} catch (e: unknown) { } catch (e) {
console.warn('Error while pre-loading exit room "' + exitRoomPath.toString() + '"', e); console.warn('Error while pre-loading exit room "' + exitRoomPath.toString() + '"', e);
} }
} }

View File

@ -0,0 +1,159 @@
{ "compressionlevel":-1,
"height":10,
"infinite":false,
"layers":[
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":10,
"id":1,
"name":"start",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[33, 34, 33, 34, 34, 34, 35, 37, 38, 39, 41, 42, 41, 42, 42, 42, 43, 45, 46, 47, 33, 34, 60, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 49, 50, 50, 50, 50, 50, 51, 53, 54, 55],
"height":10,
"id":2,
"name":"bottom",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":10,
"id":3,
"name":"openwebsite",
"opacity":1,
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/fr.wikipedia.org\/wiki\/Wikip%C3%A9dia:Accueil_principal"
}],
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
}],
"nextlayerid":4,
"nextobjectid":1,
"orientation":"orthogonal",
"properties":[
{
"name":"script",
"type":"string",
"value":"scriptTileset.js"
}],
"renderorder":"right-down",
"tiledversion":"1.7.0",
"tileheight":32,
"tilesets":[
{
"columns":8,
"firstgid":1,
"image":"tileset_dungeon.png",
"imageheight":256,
"imagewidth":256,
"margin":0,
"name":"Dungeon",
"spacing":0,
"tilecount":64,
"tileheight":32,
"tiles":[
{
"id":36,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":37,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":38,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":44,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":45,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":46,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":52,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":53,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":54,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
}],
"tilewidth":32
}],
"tilewidth":32,
"type":"map",
"version":"1.6",
"width":10
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,106 @@
{ "columns":11,
"image":"Yellow.jpg",
"imageheight":128,
"imagewidth":352,
"margin":0,
"name":"Yellow",
"spacing":0,
"tilecount":44,
"tiledversion":"1.7.0",
"tileheight":32,
"tiles":[
{
"id":0,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":1,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
},
{
"name":"name",
"type":"string",
"value":"Mur"
}]
},
{
"id":2,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":11,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":12,
"properties":[
{
"name":"name",
"type":"string",
"value":"sol"
},
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/fr.wikipedia.org\/wiki\/Wikip%C3%A9dia:Accueil_principal"
}]
},
{
"id":13,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":22,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":23,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":24,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
}],
"tilewidth":32,
"type":"tileset",
"version":"1.6"
}

View File

@ -0,0 +1,6 @@
WA.room.loadTileset("http://maps.workadventure.localhost/tests/LoadTileset/Yellow.json").then((firstgid) => {
WA.room.setTiles([
{x: 5, y: 5, tile: firstgid + 1, layer: 'bottom'},
{x: 5, y: 3, tile: 'sol', layer: 'bottom'}
]);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB