Merge pull request #1080 from thecodingmachine/metadataScriptingApi
Customize metadata with scripting api
This commit is contained in:
commit
f4209515a1
@ -7,6 +7,14 @@
|
||||
- Enabled outlines on player names (when the mouse hovers on a player you can interact with) #1219
|
||||
- Migrated the admin console to Svelte, and redesigned the console #1211
|
||||
- Layer properties (like `exitUrl`, `silent`, etc...) can now also used in tile properties #1210 (@jonnytest1)
|
||||
- New scripting API features :
|
||||
- Use `WA.room.showLayer(): void` to show a layer
|
||||
- Use `WA.room.hideLayer(): void` to hide a layer
|
||||
- Use `WA.room.setProperty() : void` to add or change existing property of a layer
|
||||
- Use `WA.player.onPlayerMove(): void` to track the movement of the current player
|
||||
- Use `WA.room.getCurrentUser(): Promise<User>` to get the ID, name and tags of the current player
|
||||
- Use `WA.room.getCurrentRoom(): Promise<Room>` to get the ID, JSON map file, url of the map of the current room and the layer where the current player started
|
||||
- Use `WA.ui.registerMenuCommand(): void` to add a custom menu
|
||||
|
||||
## Version 1.4.1
|
||||
|
||||
@ -50,6 +58,7 @@
|
||||
- New scripting API features:
|
||||
- Use `WA.loadSound(): Sound` to load / play / stop a sound
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Pinch gesture does no longer move the character
|
||||
|
21
docs/maps/api-player.md
Normal file
21
docs/maps/api-player.md
Normal file
@ -0,0 +1,21 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# API Player functions Reference
|
||||
|
||||
### Listen to player movement
|
||||
```
|
||||
WA.player.onPlayerMove(callback: HasPlayerMovedEventCallback): void;
|
||||
```
|
||||
Listens to the movement of the current user and calls the callback. Sends an event when the user stops moving, changes direction and every 200ms when moving in the same direction.
|
||||
|
||||
The event has the following attributes :
|
||||
* **moving (boolean):** **true** when the current player is moving, **false** otherwise.
|
||||
* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving.
|
||||
* **x (number):** coordinate X of the current player.
|
||||
* **y (number):** coordinate Y of the current player.
|
||||
|
||||
**callback:** the function that will be called when the current player is moving. It contains the event.
|
||||
|
||||
Example :
|
||||
```javascript
|
||||
WA.player.onPlayerMove(console.log);
|
||||
```
|
@ -4,6 +4,7 @@
|
||||
- [Navigation functions](api-nav.md)
|
||||
- [Chat functions](api-chat.md)
|
||||
- [Room functions](api-room.md)
|
||||
- [Player functions](api-player.md)
|
||||
- [UI functions](api-ui.md)
|
||||
- [Sound functions](api-sound.md)
|
||||
- [Controls functions](api-controls.md)
|
||||
|
@ -1,6 +1,22 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# API Room functions Reference
|
||||
|
||||
### Working with group layers
|
||||
If you use group layers in your map, to reference a layer in a group you will need to use a `/` to join layer names together.
|
||||
|
||||
Example :
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="https://workadventu.re/img/docs/groupLayer.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
The name of the layers of this map are :
|
||||
* `entries/start`
|
||||
* `bottom/ground/under`
|
||||
* `bottom/build/carpet`
|
||||
* `wall`
|
||||
|
||||
### Detecting when the user enters/leaves a zone
|
||||
|
||||
```
|
||||
@ -31,3 +47,68 @@ WA.room.onLeaveZone('myZone', () => {
|
||||
WA.chat.sendChatMessage("Goodbye!", 'Mr Robot');
|
||||
})
|
||||
```
|
||||
|
||||
### Show / Hide a layer
|
||||
```
|
||||
WA.room.showLayer(layerName : string): void
|
||||
WA.room.hideLayer(layerName : string) : void
|
||||
```
|
||||
These 2 methods can be used to show and hide a layer.
|
||||
|
||||
Example :
|
||||
```javascript
|
||||
WA.room.showLayer('bottom');
|
||||
//...
|
||||
WA.room.hideLayer('bottom');
|
||||
```
|
||||
|
||||
### Set/Create properties in a layer
|
||||
|
||||
```
|
||||
WA.room.setProperty(layerName : string, propertyName : string, propertyValue : string | number | boolean | undefined) : void;
|
||||
```
|
||||
|
||||
Set the value of the `propertyName` property of the layer `layerName` at `propertyValue`. If the property doesn't exist, create the property `propertyName` and set the value of the property at `propertyValue`.
|
||||
|
||||
Example :
|
||||
```javascript
|
||||
WA.room.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/');
|
||||
```
|
||||
|
||||
### Getting information on the current room
|
||||
```
|
||||
WA.room.getCurrentRoom(): Promise<Room>
|
||||
```
|
||||
Return a promise that resolves to a `Room` object with the following attributes :
|
||||
* **id (string) :** ID of the current room
|
||||
* **map (ITiledMap) :** contains the JSON map file with the properties that were setted by the script if `setProperty` was called.
|
||||
* **mapUrl (string) :** Url of the JSON map file
|
||||
* **startLayer (string | null) :** Name of the layer where the current user started, only if different from `start` layer
|
||||
|
||||
Example :
|
||||
```javascript
|
||||
WA.room.getCurrentRoom((room) => {
|
||||
if (room.id === '42') {
|
||||
console.log(room.map);
|
||||
window.open(room.mapUrl, '_blank');
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Getting information on the current user
|
||||
```
|
||||
WA.player.getCurrentUser(): Promise<User>
|
||||
```
|
||||
Return a promise that resolves to a `User` object with the following attributes :
|
||||
* **id (string) :** ID of the current user
|
||||
* **nickName (string) :** name displayed above the current user
|
||||
* **tags (string[]) :** list of all the tags of the current user
|
||||
|
||||
Example :
|
||||
```javascript
|
||||
WA.room.getCurrentUser().then((user) => {
|
||||
if (user.nickName === 'ABC') {
|
||||
console.log(user.tags);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -65,3 +65,25 @@ WA.room.onLeaveZone('myZone', () => {
|
||||
helloWorldPopup.close();
|
||||
});
|
||||
```
|
||||
|
||||
### Add custom menu
|
||||
|
||||
```typescript
|
||||
WA.ui.registerMenuCommand(menuCommand: string, callback: (menuCommand: string) => void): void
|
||||
```
|
||||
Add a custom menu item containing the text `commandDescriptor` in the main menu. A click on the menu will trigger the `callback`.
|
||||
Custom menu exist only until the map is unloaded, or you leave the iframe zone of the script.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
|
||||
WA.ui.registerMenuCommand("test", () => {
|
||||
WA.chat.sendChatMessage("test clicked", "menu cmd")
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
<div class="col">
|
||||
<img src="https://workadventu.re/img/docs/menu-command.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
@ -101,7 +101,7 @@ You can now start by testing this with a simple message sent to the chat.
|
||||
```html
|
||||
...
|
||||
<script>
|
||||
WA.sendChatMessage('Hello world', 'Mr Robot');
|
||||
WA.chat.sendChatMessage('Hello world', 'Mr Robot');
|
||||
</script>
|
||||
...
|
||||
```
|
||||
|
8393
front/package-lock.json
generated
Normal file
8393
front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
front/src/Api/Events/DataLayerEvent.ts
Normal file
13
front/src/Api/Events/DataLayerEvent.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
|
||||
|
||||
export const isDataLayerEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
data: tg.isObject
|
||||
}).get();
|
||||
|
||||
/**
|
||||
* A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers
|
||||
*/
|
||||
export type DataLayerEvent = tg.GuardedType<typeof isDataLayerEvent>;
|
15
front/src/Api/Events/GameStateEvent.ts
Normal file
15
front/src/Api/Events/GameStateEvent.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isGameStateEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
roomId: tg.isString,
|
||||
mapUrl: tg.isString,
|
||||
nickname: tg.isUnion(tg.isString, tg.isNull),
|
||||
uuid: tg.isUnion(tg.isString, tg.isUndefined),
|
||||
startLayerName: tg.isUnion(tg.isString, tg.isNull),
|
||||
tags : tg.isArray(tg.isString),
|
||||
}).get();
|
||||
/**
|
||||
* A message sent from the game to the iFrame when the gameState is received by the script
|
||||
*/
|
||||
export type GameStateEvent = tg.GuardedType<typeof isGameStateEvent>;
|
19
front/src/Api/Events/HasPlayerMovedEvent.ts
Normal file
19
front/src/Api/Events/HasPlayerMovedEvent.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
|
||||
|
||||
export const isHasPlayerMovedEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
direction: tg.isElementOf('right', 'left', 'up', 'down'),
|
||||
moving: tg.isBoolean,
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber
|
||||
}).get();
|
||||
|
||||
/**
|
||||
* A message sent from the game to the iFrame to notify a movement from the current player.
|
||||
*/
|
||||
export type HasPlayerMovedEvent = tg.GuardedType<typeof isHasPlayerMovedEvent>;
|
||||
|
||||
|
||||
export type HasPlayerMovedEventCallback = (event: HasPlayerMovedEvent) => void
|
@ -1,5 +1,5 @@
|
||||
|
||||
|
||||
import type { GameStateEvent } from './GameStateEvent';
|
||||
import type { ButtonClickedEvent } from './ButtonClickedEvent';
|
||||
import type { ChatEvent } from './ChatEvent';
|
||||
import type { ClosePopupEvent } from './ClosePopupEvent';
|
||||
@ -10,8 +10,14 @@ import type { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent';
|
||||
import type { OpenPopupEvent } from './OpenPopupEvent';
|
||||
import type { OpenTabEvent } from './OpenTabEvent';
|
||||
import type { UserInputChatEvent } from './UserInputChatEvent';
|
||||
import type { DataLayerEvent } from "./DataLayerEvent";
|
||||
import type { LayerEvent } from './LayerEvent';
|
||||
import type { SetPropertyEvent } from "./setPropertyEvent";
|
||||
import type { LoadSoundEvent } from "./LoadSoundEvent";
|
||||
import type { PlaySoundEvent } from "./PlaySoundEvent";
|
||||
import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent";
|
||||
import type { MenuItemRegisterEvent } from './ui/MenuItemRegisterEvent';
|
||||
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
||||
|
||||
|
||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||
@ -33,9 +39,16 @@ export type IframeEventMap = {
|
||||
restorePlayerControls: null
|
||||
displayBubble: null
|
||||
removeBubble: null
|
||||
onPlayerMove: undefined
|
||||
showLayer: LayerEvent
|
||||
hideLayer: LayerEvent
|
||||
setProperty: SetPropertyEvent
|
||||
getDataLayer: undefined
|
||||
loadSound: LoadSoundEvent
|
||||
playSound: PlaySoundEvent
|
||||
stopSound: null,
|
||||
getState: undefined,
|
||||
registerMenuCommand: MenuItemRegisterEvent
|
||||
}
|
||||
export interface IframeEvent<T extends keyof IframeEventMap> {
|
||||
type: T;
|
||||
@ -51,7 +64,10 @@ export interface IframeResponseEventMap {
|
||||
enterEvent: EnterLeaveEvent
|
||||
leaveEvent: EnterLeaveEvent
|
||||
buttonClickedEvent: ButtonClickedEvent
|
||||
// gameState: GameStateEvent
|
||||
gameState: GameStateEvent
|
||||
hasPlayerMoved: HasPlayerMovedEvent
|
||||
dataLayer: DataLayerEvent
|
||||
menuItemClicked: MenuItemClickedEvent
|
||||
}
|
||||
export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
|
||||
type: T;
|
||||
|
10
front/src/Api/Events/LayerEvent.ts
Normal file
10
front/src/Api/Events/LayerEvent.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isLayerEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
name: tg.isString,
|
||||
}).get();
|
||||
/**
|
||||
* A message sent from the iFrame to the game to show/hide a layer.
|
||||
*/
|
||||
export type LayerEvent = tg.GuardedType<typeof isLayerEvent>;
|
12
front/src/Api/Events/setPropertyEvent.ts
Normal file
12
front/src/Api/Events/setPropertyEvent.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isSetPropertyEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
layerName: tg.isString,
|
||||
propertyName: tg.isString,
|
||||
propertyValue: tg.isUnion(tg.isString, tg.isUnion(tg.isNumber, tg.isUnion(tg.isBoolean, tg.isUndefined)))
|
||||
}).get();
|
||||
/**
|
||||
* A message sent from the iFrame to the game to change the value of the property of the layer
|
||||
*/
|
||||
export type SetPropertyEvent = tg.GuardedType<typeof isSetPropertyEvent>;
|
12
front/src/Api/Events/ui/MenuItemClickedEvent.ts
Normal file
12
front/src/Api/Events/ui/MenuItemClickedEvent.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isMenuItemClickedEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
menuItem: tg.isString
|
||||
}).get();
|
||||
/**
|
||||
* A message sent from the game to the iFrame when a menu item is clicked.
|
||||
*/
|
||||
export type MenuItemClickedEvent = tg.GuardedType<typeof isMenuItemClickedEvent>;
|
||||
|
||||
|
25
front/src/Api/Events/ui/MenuItemRegisterEvent.ts
Normal file
25
front/src/Api/Events/ui/MenuItemRegisterEvent.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export const isMenuItemRegisterEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
menutItem: tg.isString
|
||||
}).get();
|
||||
/**
|
||||
* A message sent from the iFrame to the game to add a new menu item.
|
||||
*/
|
||||
export type MenuItemRegisterEvent = tg.GuardedType<typeof isMenuItemRegisterEvent>;
|
||||
|
||||
export const isMenuItemRegisterIframeEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
type: tg.isSingletonString("registerMenuCommand"),
|
||||
data: isMenuItemRegisterEvent
|
||||
}).get();
|
||||
|
||||
|
||||
const _registerMenuCommandStream: Subject<string> = new Subject();
|
||||
export const registerMenuCommandStream = _registerMenuCommandStream.asObservable();
|
||||
|
||||
export function handleMenuItemRegistrationEvent(event: MenuItemRegisterEvent) {
|
||||
_registerMenuCommandStream.next(event.menutItem)
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
import {Subject} from "rxjs";
|
||||
import {ChatEvent, isChatEvent} from "./Events/ChatEvent";
|
||||
import {HtmlUtils} from "../WebRtc/HtmlUtils";
|
||||
@ -10,17 +9,34 @@ import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent";
|
||||
import {scriptUtils} from "./ScriptUtils";
|
||||
import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent";
|
||||
import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent";
|
||||
import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMap, isIframeEventWrapper, TypedMessageEvent } from "./Events/IframeEvent";
|
||||
import {
|
||||
IframeEvent,
|
||||
IframeEventMap,
|
||||
IframeResponseEvent,
|
||||
IframeResponseEventMap,
|
||||
isIframeEventWrapper,
|
||||
TypedMessageEvent
|
||||
} from "./Events/IframeEvent";
|
||||
import type {UserInputChatEvent} from "./Events/UserInputChatEvent";
|
||||
import { isLoadPageEvent } from './Events/LoadPageEvent';
|
||||
//import { isLoadPageEvent } from './Events/LoadPageEvent';
|
||||
import {isPlaySoundEvent, PlaySoundEvent} from "./Events/PlaySoundEvent";
|
||||
import {isStopSoundEvent, StopSoundEvent} from "./Events/StopSoundEvent";
|
||||
import {isLoadSoundEvent, LoadSoundEvent} from "./Events/LoadSoundEvent";
|
||||
import {isSetPropertyEvent, SetPropertyEvent} from "./Events/setPropertyEvent";
|
||||
import {isLayerEvent, LayerEvent} from "./Events/LayerEvent";
|
||||
import {isMenuItemRegisterEvent,} from "./Events/ui/MenuItemRegisterEvent";
|
||||
import type {DataLayerEvent} from "./Events/DataLayerEvent";
|
||||
import type {GameStateEvent} from "./Events/GameStateEvent";
|
||||
import type {HasPlayerMovedEvent} from "./Events/HasPlayerMovedEvent";
|
||||
import {isLoadPageEvent} from "./Events/LoadPageEvent";
|
||||
import {handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent} from "./Events/ui/MenuItemRegisterEvent";
|
||||
|
||||
/**
|
||||
* Listens to messages from iframes and turn those messages into easy to use observables.
|
||||
* Also allows to send messages to those iframes.
|
||||
*/
|
||||
class IframeListener {
|
||||
|
||||
private readonly _chatStream: Subject<ChatEvent> = new Subject();
|
||||
public readonly chatStream = this._chatStream.asObservable();
|
||||
|
||||
@ -33,7 +49,6 @@ class IframeListener {
|
||||
private readonly _goToPageStream: Subject<GoToPageEvent> = new Subject();
|
||||
public readonly goToPageStream = this._goToPageStream.asObservable();
|
||||
|
||||
|
||||
private readonly _loadPageStream: Subject<string> = new Subject();
|
||||
public readonly loadPageStream = this._loadPageStream.asObservable();
|
||||
|
||||
@ -58,6 +73,27 @@ class IframeListener {
|
||||
private readonly _removeBubbleStream: Subject<void> = new Subject();
|
||||
public readonly removeBubbleStream = this._removeBubbleStream.asObservable();
|
||||
|
||||
private readonly _showLayerStream: Subject<LayerEvent> = new Subject();
|
||||
public readonly showLayerStream = this._showLayerStream.asObservable();
|
||||
|
||||
private readonly _hideLayerStream: Subject<LayerEvent> = new Subject();
|
||||
public readonly hideLayerStream = this._hideLayerStream.asObservable();
|
||||
|
||||
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
||||
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
||||
|
||||
private readonly _gameStateStream: Subject<void> = new Subject();
|
||||
public readonly gameStateStream = this._gameStateStream.asObservable();
|
||||
|
||||
private readonly _dataLayerChangeStream: Subject<void> = new Subject();
|
||||
public readonly dataLayerChangeStream = this._dataLayerChangeStream.asObservable();
|
||||
|
||||
private readonly _registerMenuCommandStream: Subject<string> = new Subject();
|
||||
public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable();
|
||||
|
||||
private readonly _unregisterMenuCommandStream: Subject<string> = new Subject();
|
||||
public readonly unregisterMenuCommandStream = this._unregisterMenuCommandStream.asObservable();
|
||||
|
||||
private readonly _playSoundStream: Subject<PlaySoundEvent> = new Subject();
|
||||
public readonly playSoundStream = this._playSoundStream.asObservable();
|
||||
|
||||
@ -68,7 +104,9 @@ class IframeListener {
|
||||
public readonly loadSoundStream = this._loadSoundStream.asObservable();
|
||||
|
||||
private readonly iframes = new Set<HTMLIFrameElement>();
|
||||
private readonly iframeCloseCallbacks = new Map<HTMLIFrameElement, (() => void)[]>();
|
||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||
private sendPlayerMove: boolean = false;
|
||||
|
||||
init() {
|
||||
window.addEventListener("message", (message: TypedMessageEvent<IframeEvent<keyof IframeEventMap>>) => {
|
||||
@ -77,12 +115,8 @@ class IframeListener {
|
||||
// Note: maybe we could restrict on the domain too for additional security (in case the iframe goes to another domain).
|
||||
let foundSrc: string | undefined;
|
||||
|
||||
foundSrc = [...this.scripts.keys()].find(key => {
|
||||
return this.scripts.get(key)?.contentWindow == message.source
|
||||
});
|
||||
|
||||
if (foundSrc === undefined) {
|
||||
for (const iframe of this.iframes) {
|
||||
let iframe: HTMLIFrameElement;
|
||||
for (iframe of this.iframes) {
|
||||
if (iframe.contentWindow === message.source) {
|
||||
foundSrc = iframe.src;
|
||||
break;
|
||||
@ -92,11 +126,16 @@ class IframeListener {
|
||||
if (foundSrc === undefined) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const payload = message.data;
|
||||
if (isIframeEventWrapper(payload)) {
|
||||
if (payload.type === 'chat' && isChatEvent(payload.data)) {
|
||||
if (payload.type === 'showLayer' && isLayerEvent(payload.data)) {
|
||||
this._showLayerStream.next(payload.data);
|
||||
} else if (payload.type === 'hideLayer' && isLayerEvent(payload.data)) {
|
||||
this._hideLayerStream.next(payload.data);
|
||||
} else if (payload.type === 'setProperty' && isSetPropertyEvent(payload.data)) {
|
||||
this._setPropertyStream.next(payload.data);
|
||||
} else if (payload.type === 'chat' && isChatEvent(payload.data)) {
|
||||
this._chatStream.next(payload.data);
|
||||
} else if (payload.type === 'openPopup' && isOpenPopupEvent(payload.data)) {
|
||||
this._openPopupStream.next(payload.data);
|
||||
@ -109,6 +148,9 @@ class IframeListener {
|
||||
else if (payload.type === 'goToPage' && isGoToPageEvent(payload.data)) {
|
||||
scriptUtils.goToPage(payload.data.url);
|
||||
}
|
||||
else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)) {
|
||||
this._loadPageStream.next(payload.data.url);
|
||||
}
|
||||
else if (payload.type === 'playSound' && isPlaySoundEvent(payload.data)) {
|
||||
this._playSoundStream.next(payload.data);
|
||||
}
|
||||
@ -131,30 +173,56 @@ class IframeListener {
|
||||
}
|
||||
else if (payload.type === 'restorePlayerControls') {
|
||||
this._enablePlayerControlStream.next();
|
||||
}
|
||||
else if (payload.type === 'displayBubble') {
|
||||
} else if (payload.type === 'displayBubble') {
|
||||
this._displayBubbleStream.next();
|
||||
}
|
||||
else if (payload.type === 'removeBubble') {
|
||||
} else if (payload.type === 'removeBubble') {
|
||||
this._removeBubbleStream.next();
|
||||
}else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)){
|
||||
this._loadPageStream.next(payload.data.url);
|
||||
} else if (payload.type == "getState") {
|
||||
this._gameStateStream.next();
|
||||
} else if (payload.type == "onPlayerMove") {
|
||||
this.sendPlayerMove = true
|
||||
} else if (payload.type == "getDataLayer") {
|
||||
this._dataLayerChangeStream.next();
|
||||
} else if (isMenuItemRegisterIframeEvent(payload)) {
|
||||
const data = payload.data.menutItem;
|
||||
// @ts-ignore
|
||||
this.iframeCloseCallbacks.get(iframe).push(() => {
|
||||
this._unregisterMenuCommandStream.next(data);
|
||||
})
|
||||
handleMenuItemRegistrationEvent(payload.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, false);
|
||||
|
||||
}
|
||||
|
||||
sendDataLayerEvent(dataLayerEvent: DataLayerEvent) {
|
||||
this.postMessage({
|
||||
'type' : 'dataLayer',
|
||||
'data' : dataLayerEvent
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
sendGameStateEvent(gameStateEvent: GameStateEvent) {
|
||||
this.postMessage({
|
||||
'type': 'gameState',
|
||||
'data': gameStateEvent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the passed iFrame to send/receive messages via the API.
|
||||
*/
|
||||
registerIframe(iframe: HTMLIFrameElement): void {
|
||||
this.iframes.add(iframe);
|
||||
this.iframeCloseCallbacks.set(iframe, []);
|
||||
}
|
||||
|
||||
unregisterIframe(iframe: HTMLIFrameElement): void {
|
||||
this.iframeCloseCallbacks.get(iframe)?.forEach(callback => {
|
||||
callback();
|
||||
});
|
||||
this.iframes.delete(iframe);
|
||||
}
|
||||
|
||||
@ -164,7 +232,7 @@ class IframeListener {
|
||||
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
|
||||
// Using external iframe mode (
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.id = this.getIFrameId(scriptUrl);
|
||||
iframe.id = IframeListener.getIFrameId(scriptUrl);
|
||||
iframe.style.display = 'none';
|
||||
iframe.src = '/iframe.html?script=' + encodeURIComponent(scriptUrl);
|
||||
|
||||
@ -179,25 +247,24 @@ class IframeListener {
|
||||
} else {
|
||||
// production code
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.id = this.getIFrameId(scriptUrl);
|
||||
iframe.id = IframeListener.getIFrameId(scriptUrl);
|
||||
iframe.style.display = 'none';
|
||||
|
||||
// We are putting a sandbox on this script because it will run in the same domain as the main website.
|
||||
iframe.sandbox.add('allow-scripts');
|
||||
iframe.sandbox.add('allow-top-navigation-by-user-activation');
|
||||
|
||||
const html = '<!doctype html>\n' +
|
||||
//iframe.src = "data:text/html;charset=utf-8," + escape(html);
|
||||
iframe.srcdoc = '<!doctype html>\n' +
|
||||
'\n' +
|
||||
'<html lang="en">\n' +
|
||||
'<head>\n' +
|
||||
'<script src="' + window.location.protocol + '//' + window.location.host + '/iframe_api.js" ></script>\n' +
|
||||
'<script src="' + scriptUrl + '" ></script>\n' +
|
||||
'<title></title>\n' +
|
||||
'</head>\n' +
|
||||
'</html>\n';
|
||||
|
||||
//iframe.src = "data:text/html;charset=utf-8," + escape(html);
|
||||
iframe.srcdoc = html;
|
||||
|
||||
document.body.prepend(iframe);
|
||||
|
||||
this.scripts.set(scriptUrl, iframe);
|
||||
@ -207,12 +274,12 @@ class IframeListener {
|
||||
|
||||
}
|
||||
|
||||
private getIFrameId(scriptUrl: string): string {
|
||||
private static getIFrameId(scriptUrl: string): string {
|
||||
return 'script' + btoa(scriptUrl);
|
||||
}
|
||||
|
||||
unregisterScript(scriptUrl: string): void {
|
||||
const iFrameId = this.getIFrameId(scriptUrl);
|
||||
const iFrameId = IframeListener.getIFrameId(scriptUrl);
|
||||
const iframe = HtmlUtils.getElementByIdOrFail<HTMLIFrameElement>(iFrameId);
|
||||
if (!iframe) {
|
||||
throw new Error('Unknown iframe for script "' + scriptUrl + '"');
|
||||
@ -250,6 +317,15 @@ class IframeListener {
|
||||
});
|
||||
}
|
||||
|
||||
hasPlayerMoved(event: HasPlayerMovedEvent) {
|
||||
if (this.sendPlayerMove) {
|
||||
this.postMessage({
|
||||
'type': 'hasPlayerMoved',
|
||||
'data': event
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sendButtonClickedEvent(popupId: number, buttonId: number): void {
|
||||
this.postMessage({
|
||||
'type': 'buttonClickedEvent',
|
||||
@ -263,7 +339,7 @@ class IframeListener {
|
||||
/**
|
||||
* Sends the message... to all allowed iframes.
|
||||
*/
|
||||
private postMessage(message: IframeResponseEvent<keyof IframeResponseEventMap>) {
|
||||
public postMessage(message: IframeResponseEvent<keyof IframeResponseEventMap>) {
|
||||
for (const iframe of this.iframes) {
|
||||
iframe.contentWindow?.postMessage(message, '*');
|
||||
}
|
||||
|
11
front/src/Api/iframe/Ui/MenuItem.ts
Normal file
11
front/src/Api/iframe/Ui/MenuItem.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { MenuItemClickedEvent } from '../../Events/ui/MenuItemClickedEvent';
|
||||
import { iframeListener } from '../../IframeListener';
|
||||
|
||||
export function sendMenuClickedEvent(menuItem: string) {
|
||||
iframeListener.postMessage({
|
||||
'type': 'menuItemClicked',
|
||||
'data': {
|
||||
menuItem: menuItem,
|
||||
} as MenuItemClickedEvent
|
||||
});
|
||||
}
|
@ -23,7 +23,7 @@ class WorkadventureChatCommands extends IframeApiContribution<WorkadventureChatC
|
||||
data: {
|
||||
'message': message,
|
||||
'author': author
|
||||
} as ChatEvent
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ import type { GoToPageEvent } from '../Events/GoToPageEvent';
|
||||
import type { OpenTabEvent } from '../Events/OpenTabEvent';
|
||||
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||
import type {OpenCoWebSiteEvent} from "../Events/OpenCoWebSiteEvent";
|
||||
import type {LoadPageEvent} from "../Events/LoadPageEvent";
|
||||
|
||||
|
||||
class WorkadventureNavigationCommands extends IframeApiContribution<WorkadventureNavigationCommands> {
|
||||
@ -13,7 +14,7 @@ class WorkadventureNavigationCommands extends IframeApiContribution<Workadventur
|
||||
"type": 'openTab',
|
||||
"data": {
|
||||
url
|
||||
} as OpenTabEvent
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -22,7 +23,7 @@ class WorkadventureNavigationCommands extends IframeApiContribution<Workadventur
|
||||
"type": 'goToPage',
|
||||
"data": {
|
||||
url
|
||||
} as GoToPageEvent
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -40,7 +41,7 @@ class WorkadventureNavigationCommands extends IframeApiContribution<Workadventur
|
||||
"type": 'openCoWebSite',
|
||||
"data": {
|
||||
url
|
||||
} as OpenCoWebSiteEvent
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
29
front/src/Api/iframe/player.ts
Normal file
29
front/src/Api/iframe/player.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import {IframeApiContribution, sendToWorkadventure} from "./IframeApiContribution";
|
||||
import type {HasPlayerMovedEvent, HasPlayerMovedEventCallback} from "../Events/HasPlayerMovedEvent";
|
||||
import {Subject} from "rxjs";
|
||||
import {apiCallback} from "./registeredCallbacks";
|
||||
import {isHasPlayerMovedEvent} from "../Events/HasPlayerMovedEvent";
|
||||
|
||||
const moveStream = new Subject<HasPlayerMovedEvent>();
|
||||
|
||||
class WorkadventurePlayerCommands extends IframeApiContribution<WorkadventurePlayerCommands> {
|
||||
callbacks = [
|
||||
apiCallback({
|
||||
type: 'hasPlayerMoved',
|
||||
typeChecker: isHasPlayerMovedEvent,
|
||||
callback: (payloadData) => {
|
||||
moveStream.next(payloadData);
|
||||
}
|
||||
}),
|
||||
]
|
||||
|
||||
onPlayerMove(callback: HasPlayerMovedEventCallback): void {
|
||||
moveStream.subscribe(callback);
|
||||
sendToWorkadventure({
|
||||
type: 'onPlayerMove',
|
||||
data: null
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default new WorkadventurePlayerCommands();
|
@ -1,10 +1,54 @@
|
||||
import { Subject } from "rxjs";
|
||||
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent';
|
||||
import { IframeApiContribution } from './IframeApiContribution';
|
||||
import {IframeApiContribution, sendToWorkadventure} from './IframeApiContribution';
|
||||
import { apiCallback } from "./registeredCallbacks";
|
||||
import type {LayerEvent} from "../Events/LayerEvent";
|
||||
import type {SetPropertyEvent} from "../Events/setPropertyEvent";
|
||||
import type {GameStateEvent} from "../Events/GameStateEvent";
|
||||
import type {ITiledMap} from "../../Phaser/Map/ITiledMap";
|
||||
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 leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||
const dataLayerResolver = new Subject<DataLayerEvent>();
|
||||
const stateResolvers = new Subject<GameStateEvent>();
|
||||
|
||||
let immutableData: GameStateEvent;
|
||||
|
||||
interface Room {
|
||||
id: string,
|
||||
mapUrl: string,
|
||||
map: ITiledMap,
|
||||
startLayer: string | null
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string | undefined,
|
||||
nickName: string | null,
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
|
||||
function getGameState(): Promise<GameStateEvent> {
|
||||
if (immutableData) {
|
||||
return Promise.resolve(immutableData);
|
||||
}
|
||||
else {
|
||||
return new Promise<GameStateEvent>((resolver, thrower) => {
|
||||
stateResolvers.subscribe(resolver);
|
||||
sendToWorkadventure({type: "getState", data: null});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getDataLayer(): Promise<DataLayerEvent> {
|
||||
return new Promise<DataLayerEvent>((resolver, thrower) => {
|
||||
dataLayerResolver.subscribe(resolver);
|
||||
sendToWorkadventure({type: "getDataLayer", data: null})
|
||||
})
|
||||
}
|
||||
|
||||
class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomCommands> {
|
||||
callbacks = [
|
||||
@ -21,8 +65,21 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
|
||||
callback: (payloadData) => {
|
||||
leaveStreams.get(payloadData.name)?.next();
|
||||
}
|
||||
})
|
||||
|
||||
}),
|
||||
apiCallback({
|
||||
type: "gameState",
|
||||
typeChecker: isGameStateEvent,
|
||||
callback: (payloadData) => {
|
||||
stateResolvers.next(payloadData);
|
||||
}
|
||||
}),
|
||||
apiCallback({
|
||||
type: "dataLayer",
|
||||
typeChecker: isDataLayerEvent,
|
||||
callback: (payloadData) => {
|
||||
dataLayerResolver.next(payloadData);
|
||||
}
|
||||
}),
|
||||
]
|
||||
|
||||
|
||||
@ -43,6 +100,34 @@ class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomC
|
||||
}
|
||||
subject.subscribe(callback);
|
||||
}
|
||||
showLayer(layerName: string): void {
|
||||
sendToWorkadventure({type: 'showLayer', data: {'name': layerName}});
|
||||
}
|
||||
hideLayer(layerName: string): void {
|
||||
sendToWorkadventure({type: 'hideLayer', data: {'name': layerName}});
|
||||
}
|
||||
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
|
||||
sendToWorkadventure({
|
||||
type: 'setProperty',
|
||||
data: {
|
||||
'layerName': layerName,
|
||||
'propertyName': propertyName,
|
||||
'propertyValue': propertyValue,
|
||||
}
|
||||
})
|
||||
}
|
||||
getCurrentRoom(): Promise<Room> {
|
||||
return getGameState().then((gameState) => {
|
||||
return getDataLayer().then((mapJson) => {
|
||||
return {id: gameState.roomId, map: mapJson.data as ITiledMap, mapUrl: gameState.mapUrl, startLayer: gameState.startLayerName};
|
||||
})
|
||||
})
|
||||
}
|
||||
getCurrentUser(): Promise<User> {
|
||||
return getGameState().then((gameState) => {
|
||||
return {id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags};
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
import { isButtonClickedEvent } from '../Events/ButtonClickedEvent';
|
||||
import type { ClosePopupEvent } from '../Events/ClosePopupEvent';
|
||||
import { isMenuItemClickedEvent } from '../Events/ui/MenuItemClickedEvent';
|
||||
import type { MenuItemRegisterEvent } from '../Events/ui/MenuItemRegisterEvent';
|
||||
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||
import { apiCallback } from "./registeredCallbacks";
|
||||
import {Popup} from "./Ui/Popup";
|
||||
import type { ButtonClickedCallback, ButtonDescriptor } from "./Ui/ButtonDescriptor";
|
||||
import { Popup } from "./Ui/Popup";
|
||||
|
||||
let popupId = 0;
|
||||
const popups: Map<number, Popup> = new Map<number, Popup>();
|
||||
const popupCallbacks: Map<number, Map<number, ButtonClickedCallback>> = new Map<number, Map<number, ButtonClickedCallback>>();
|
||||
|
||||
const menuCallbacks: Map<string, (command: string) => void> = new Map()
|
||||
|
||||
interface ZonedPopupOptions {
|
||||
zone: string
|
||||
objectLayerName?: string,
|
||||
@ -33,6 +36,16 @@ class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiComma
|
||||
callback(popup);
|
||||
}
|
||||
}
|
||||
}),
|
||||
apiCallback({
|
||||
type: "menuItemClicked",
|
||||
typeChecker: isMenuItemClickedEvent,
|
||||
callback: event => {
|
||||
const callback = menuCallbacks.get(event.menuItem);
|
||||
if (callback) {
|
||||
callback(event.menuItem)
|
||||
}
|
||||
}
|
||||
})];
|
||||
|
||||
|
||||
@ -71,6 +84,16 @@ class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiComma
|
||||
return popup;
|
||||
}
|
||||
|
||||
registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) {
|
||||
menuCallbacks.set(commandDescriptor, callback);
|
||||
sendToWorkadventure({
|
||||
'type': 'registerMenuCommand',
|
||||
'data': {
|
||||
menutItem: commandDescriptor
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
displayBubble(): void {
|
||||
sendToWorkadventure({ 'type': 'displayBubble', data: null });
|
||||
}
|
||||
|
@ -89,7 +89,6 @@ export class RoomConnection implements RoomConnection {
|
||||
url += '&bottom=' + Math.floor(viewport.bottom);
|
||||
url += '&left=' + Math.floor(viewport.left);
|
||||
url += '&right=' + Math.floor(viewport.right);
|
||||
|
||||
if (typeof companion === 'string') {
|
||||
url += '&companion=' + encodeURIComponent(companion);
|
||||
}
|
||||
@ -618,4 +617,8 @@ export class RoomConnection implements RoomConnection {
|
||||
|
||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||
}
|
||||
|
||||
public getAllTags() : string[] {
|
||||
return this.tags;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ export abstract class DirtyScene extends ResizableScene {
|
||||
|
||||
this.events.on(Events.RENDER, () => {
|
||||
this.objectListChanged = false;
|
||||
this.dirty = false;
|
||||
});
|
||||
|
||||
this.physics.disableUpdate();
|
||||
|
@ -10,12 +10,7 @@ import {get} from "svelte/store";
|
||||
import {requestedCameraState, requestedMicrophoneState} from "../../Stores/MediaStore";
|
||||
import {helpCameraSettingsVisibleStore} from "../../Stores/HelpCameraSettingsStore";
|
||||
|
||||
export interface HasMovedEvent {
|
||||
direction: string;
|
||||
moving: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class should be responsible for any scene starting/stopping
|
||||
|
@ -1,5 +1,7 @@
|
||||
import type { ITiledMap, ITiledMapLayerProperty } from "../Map/ITiledMap";
|
||||
import { LayersIterator } from "../Map/LayersIterator";
|
||||
import type {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty} from "../Map/ITiledMap";
|
||||
import { flattenGroupLayersMap } from "../Map/LayersFlattener";
|
||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
||||
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
||||
|
||||
export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) => void;
|
||||
|
||||
@ -13,13 +15,22 @@ export class GameMap {
|
||||
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
|
||||
|
||||
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapLayerProperty> } = {}
|
||||
public readonly layersIterator: LayersIterator;
|
||||
public readonly flatLayers: ITiledMapLayer[];
|
||||
public readonly phaserLayers: TilemapLayer[] = [];
|
||||
|
||||
public exitUrls: Array<string> = []
|
||||
|
||||
public constructor(private map: ITiledMap) {
|
||||
this.layersIterator = new LayersIterator(map);
|
||||
|
||||
public constructor(private map: ITiledMap, phaserMap: Phaser.Tilemaps.Tilemap, terrains: Array<Phaser.Tilemaps.Tileset>) {
|
||||
this.flatLayers = flattenGroupLayersMap(map);
|
||||
let depth = -2;
|
||||
for (const layer of this.flatLayers) {
|
||||
if(layer.type === 'tilelayer'){
|
||||
this.phaserLayers.push(phaserMap.createLayer(layer.name, terrains, 0, 0).setDepth(depth));
|
||||
}
|
||||
if (layer.type === 'objectgroup' && layer.name === 'floorLayer') {
|
||||
depth = DEPTH_OVERLAY_INDEX;
|
||||
}
|
||||
}
|
||||
for (const tileset of map.tilesets) {
|
||||
tileset?.tiles?.forEach(tile => {
|
||||
if (tile.properties) {
|
||||
@ -77,7 +88,7 @@ export class GameMap {
|
||||
private getProperties(key: number): Map<string, string | boolean | number> {
|
||||
const properties = new Map<string, string | boolean | number>();
|
||||
|
||||
for (const layer of this.layersIterator) {
|
||||
for (const layer of this.flatLayers) {
|
||||
if (layer.type !== 'tilelayer') {
|
||||
continue;
|
||||
}
|
||||
@ -115,6 +126,10 @@ export class GameMap {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public getMap(): ITiledMap{
|
||||
return this.map;
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -135,4 +150,19 @@ export class GameMap {
|
||||
}
|
||||
callbacksArray.push(callback);
|
||||
}
|
||||
|
||||
public findLayer(layerName: string): ITiledMapLayer | undefined {
|
||||
return this.flatLayers.find((layer) => layer.name === layerName);
|
||||
}
|
||||
|
||||
public findPhaserLayer(layerName: string): TilemapLayer | undefined {
|
||||
return this.phaserLayers.find((layer) => layer.layer.name === layerName);
|
||||
}
|
||||
|
||||
public addTerrain(terrain : Phaser.Tilemaps.Tileset): void {
|
||||
for (const phaserLayer of this.phaserLayers) {
|
||||
phaserLayer.tileset.push(terrain);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
import {gameManager, HasMovedEvent} from "./GameManager";
|
||||
import { Queue } from 'queue-typescript';
|
||||
import type { Subscription } from "rxjs";
|
||||
import { GlobalMessageManager } from "../../Administration/GlobalMessageManager";
|
||||
import { userMessageManager } from "../../Administration/UserMessageManager";
|
||||
import { iframeListener } from "../../Api/IframeListener";
|
||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||
import type {
|
||||
GroupCreatedUpdatedMessageInterface,
|
||||
MessageUserJoined,
|
||||
@ -9,70 +14,73 @@ import type {
|
||||
PositionInterface,
|
||||
RoomJoinedMessageInterface
|
||||
} from "../../Connexion/ConnexionModels";
|
||||
import {hasMovedEventName, Player, requestEmoteEventName} from "../Player/Player";
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { Room } from "../../Connexion/Room";
|
||||
import type { RoomConnection } from "../../Connexion/RoomConnection";
|
||||
import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream";
|
||||
import {
|
||||
DEBUG_MODE,
|
||||
JITSI_PRIVATE_MODE,
|
||||
MAX_PER_GROUP,
|
||||
POSITION_DELAY,
|
||||
POSITION_DELAY
|
||||
} from "../../Enum/EnvironmentVariable";
|
||||
import type {
|
||||
ITiledMap,
|
||||
ITiledMapLayer,
|
||||
ITiledMapLayerProperty,
|
||||
ITiledMapObject,
|
||||
ITiledMapTileLayer,
|
||||
ITiledTileSet
|
||||
} from "../Map/ITiledMap";
|
||||
import type {AddPlayerInterface} from "./AddPlayerInterface";
|
||||
import {PlayerAnimationDirections} from "../Player/Animation";
|
||||
import {PlayerMovement} from "./PlayerMovement";
|
||||
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
|
||||
import {RemotePlayer} from "../Entity/RemotePlayer";
|
||||
import {Queue} from 'queue-typescript';
|
||||
import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer";
|
||||
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
||||
import {lazyLoadPlayerCharacterTextures, loadCustomTexture} from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { TextureError } from "../../Exception/TextureError";
|
||||
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
|
||||
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
||||
import { peerStore } from "../../Stores/PeerStore";
|
||||
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||
import { urlManager } from "../../Url/UrlManager";
|
||||
import { audioManager } from "../../WebRtc/AudioManager";
|
||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||
import {
|
||||
CenterListener,
|
||||
AUDIO_LOOP_PROPERTY, AUDIO_VOLUME_PROPERTY, CenterListener,
|
||||
JITSI_MESSAGE_PROPERTIES,
|
||||
layoutManager,
|
||||
LayoutMode,
|
||||
ON_ACTION_TRIGGER_BUTTON,
|
||||
TRIGGER_JITSI_PROPERTIES,
|
||||
TRIGGER_WEBSITE_PROPERTIES,
|
||||
WEBSITE_MESSAGE_PROPERTIES,
|
||||
AUDIO_VOLUME_PROPERTY,
|
||||
AUDIO_LOOP_PROPERTY
|
||||
WEBSITE_MESSAGE_PROPERTIES
|
||||
} from "../../WebRtc/LayoutManager";
|
||||
import {GameMap} from "./GameMap";
|
||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||
import { mediaManager } from "../../WebRtc/MediaManager";
|
||||
import type {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
||||
import type {ActionableItem} from "../Items/ActionableItem";
|
||||
import {UserInputManager} from "../UserInput/UserInputManager";
|
||||
import {soundManager} from "./SoundManager";
|
||||
import type {UserMovedMessage} from "../../Messages/generated/messages_pb";
|
||||
import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
|
||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||
import type {RoomConnection} from "../../Connexion/RoomConnection";
|
||||
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
|
||||
import {userMessageManager} from "../../Administration/UserMessageManager";
|
||||
import {ResizableScene} from "../Login/ResizableScene";
|
||||
import {Room} from "../../Connexion/Room";
|
||||
import {jitsiFactory} from "../../WebRtc/JitsiFactory";
|
||||
import {urlManager} from "../../Url/UrlManager";
|
||||
import {audioManager} from "../../WebRtc/AudioManager";
|
||||
import {PresentationModeIcon} from "../Components/PresentationModeIcon";
|
||||
import { SimplePeer, UserSimplePeerInterface } from "../../WebRtc/SimplePeer";
|
||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||
import { ChatModeIcon } from "../Components/ChatModeIcon";
|
||||
import {OpenChatIcon, openChatIconName} from "../Components/OpenChatIcon";
|
||||
import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCharacterScene";
|
||||
import {TextureError} from "../../Exception/TextureError";
|
||||
import { addLoader } from "../Components/Loader";
|
||||
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
|
||||
import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon";
|
||||
import { PresentationModeIcon } from "../Components/PresentationModeIcon";
|
||||
import { TextUtils } from "../Components/TextUtils";
|
||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
||||
import type { ActionableItem } from "../Items/ActionableItem";
|
||||
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
|
||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||
import type {
|
||||
ITiledMap,
|
||||
ITiledMapLayer,
|
||||
ITiledMapLayerProperty,
|
||||
ITiledMapObject,
|
||||
ITiledMapTileLayer,
|
||||
ITiledTileSet } from "../Map/ITiledMap";
|
||||
import { MenuScene, MenuSceneName } from '../Menu/MenuScene';
|
||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
||||
import { ErrorSceneName } from "../Reconnecting/ErrorScene";
|
||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {iframeListener} from "../../Api/IframeListener";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { PinchManager } from "../UserInput/PinchManager";
|
||||
import { UserInputManager } from "../UserInput/UserInputManager";
|
||||
import type { AddPlayerInterface } from "./AddPlayerInterface";
|
||||
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
||||
import { DirtyScene } from "./DirtyScene";
|
||||
import { EmoteManager } from "./EmoteManager";
|
||||
import { gameManager } from "./GameManager";
|
||||
import { GameMap } from "./GameMap";
|
||||
import { PlayerMovement } from "./PlayerMovement";
|
||||
import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||
@ -80,22 +88,12 @@ import GameObject = Phaser.GameObjects.GameObject;
|
||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||
import EVENT_TYPE = Phaser.Scenes.Events
|
||||
import type {Subscription} from "rxjs";
|
||||
import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream";
|
||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||
import RenderTexture = Phaser.GameObjects.RenderTexture;
|
||||
import Tilemap = Phaser.Tilemaps.Tilemap;
|
||||
import {DirtyScene} from "./DirtyScene";
|
||||
import {TextUtils} from "../Components/TextUtils";
|
||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||
import {PinchManager} from "../UserInput/PinchManager";
|
||||
import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick";
|
||||
import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import {peerStore} from "../../Stores/PeerStore";
|
||||
import {EmoteManager} from "./EmoteManager";
|
||||
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||
|
||||
import AnimatedTiles from "phaser-animated-tiles";
|
||||
import {soundManager} from "./SoundManager";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface | null,
|
||||
@ -140,7 +138,6 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
MapPlayers!: Phaser.Physics.Arcade.Group;
|
||||
MapPlayersByKey: Map<number, RemotePlayer> = new Map<number, RemotePlayer>();
|
||||
Map!: Phaser.Tilemaps.Tilemap;
|
||||
Layers!: Array<Phaser.Tilemaps.TilemapLayer>;
|
||||
Objects!: Array<Phaser.Physics.Arcade.Sprite>;
|
||||
mapFile!: ITiledMap;
|
||||
animatedTiles!: AnimatedTiles;
|
||||
@ -168,7 +165,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
|
||||
currentTick!: number;
|
||||
lastSentTick!: number; // The last tick at which a position was sent.
|
||||
lastMoveEventSent: HasMovedEvent = {
|
||||
lastMoveEventSent: HasPlayerMovedEvent = {
|
||||
direction: '',
|
||||
moving: false,
|
||||
x: -1000,
|
||||
@ -413,7 +410,6 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
|
||||
//initalise map
|
||||
this.Map = this.add.tilemap(this.MapUrlFile);
|
||||
this.gameMap = new GameMap(this.mapFile);
|
||||
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||
this.mapFile.tilesets.forEach((tileset: ITiledTileSet) => {
|
||||
this.Terrains.push(this.Map.addTilesetImage(tileset.name, `${mapDirUrl}/${tileset.image}`, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing/*, tileset.firstgid*/));
|
||||
@ -423,11 +419,9 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
this.physics.world.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels);
|
||||
|
||||
//add layer on map
|
||||
this.Layers = new Array<Phaser.Tilemaps.TilemapLayer>();
|
||||
let depth = -2;
|
||||
for (const layer of this.gameMap.layersIterator) {
|
||||
this.gameMap = new GameMap(this.mapFile, this.Map, this.Terrains);
|
||||
for (const layer of this.gameMap.flatLayers) {
|
||||
if (layer.type === 'tilelayer') {
|
||||
this.addLayer(this.Map.createLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
|
||||
|
||||
const exitSceneUrl = this.getExitSceneUrl(layer);
|
||||
if (exitSceneUrl !== undefined) {
|
||||
@ -438,9 +432,6 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
this.loadNextGame(exitUrl);
|
||||
}
|
||||
}
|
||||
if (layer.type === 'objectgroup' && layer.name === 'floorLayer') {
|
||||
depth = DEPTH_OVERLAY_INDEX;
|
||||
}
|
||||
if (layer.type === 'objectgroup') {
|
||||
for (const object of layer.objects) {
|
||||
if (object.text) {
|
||||
@ -454,10 +445,6 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
this.loadNextGame(exitUrl)
|
||||
})
|
||||
|
||||
if (depth === -2) {
|
||||
throw new Error('Your map MUST contain a layer of type "objectgroup" whose name is "floorLayer" that represents the layer characters are drawn at. This layer cannot be contained in a group.');
|
||||
}
|
||||
|
||||
this.initStartXAndStartY();
|
||||
|
||||
//add entities
|
||||
@ -680,7 +667,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
||||
//listen event to share position of user
|
||||
this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this))
|
||||
this.CurrentPlayer.on(hasMovedEventName, this.outlineItem.bind(this))
|
||||
this.CurrentPlayer.on(hasMovedEventName, (event: HasMovedEvent) => {
|
||||
this.CurrentPlayer.on(hasMovedEventName, (event: HasPlayerMovedEvent) => {
|
||||
this.gameMap.setPosition(event.x, event.y);
|
||||
})
|
||||
|
||||
@ -909,20 +896,17 @@ ${escapedMessage}
|
||||
this.userInputManager.disableControls();
|
||||
}));
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.playSoundStream.subscribe((playSoundEvent)=>
|
||||
{
|
||||
this.iframeSubscriptionList.push(iframeListener.playSoundStream.subscribe((playSoundEvent) => {
|
||||
const url = new URL(playSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.playSound(this.load, this.sound, url.toString(), playSoundEvent.config);
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.stopSoundStream.subscribe((stopSoundEvent)=>
|
||||
{
|
||||
this.iframeSubscriptionList.push(iframeListener.stopSoundStream.subscribe((stopSoundEvent) => {
|
||||
const url = new URL(stopSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.stopSound(this.sound, url.toString());
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.loadSoundStream.subscribe((loadSoundEvent)=>
|
||||
{
|
||||
this.iframeSubscriptionList.push(iframeListener.loadSoundStream.subscribe((loadSoundEvent) => {
|
||||
const url = new URL(loadSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.loadSound(this.load, this.sound, url.toString());
|
||||
}))
|
||||
@ -948,8 +932,61 @@ ${escapedMessage}
|
||||
scriptedBubbleSprite.destroy();
|
||||
}));
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.showLayerStream.subscribe((layerEvent)=>{
|
||||
this.setLayerVisibility(layerEvent.name, true);
|
||||
}));
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.hideLayerStream.subscribe((layerEvent)=>{
|
||||
this.setLayerVisibility(layerEvent.name, false);
|
||||
}));
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.setPropertyStream.subscribe((setProperty) => {
|
||||
this.setPropertyLayer(setProperty.layerName, setProperty.propertyName, setProperty.propertyValue);
|
||||
}));
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.dataLayerChangeStream.subscribe(() => {
|
||||
iframeListener.sendDataLayerEvent({data: this.gameMap.getMap()});
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => {
|
||||
iframeListener.sendGameStateEvent({
|
||||
mapUrl: this.MapUrlFile,
|
||||
startLayerName: this.startLayerName,
|
||||
uuid: localUserStore.getLocalUser()?.uuid,
|
||||
nickname: localUserStore.getName(),
|
||||
roomId: this.RoomId,
|
||||
tags: this.connection ? this.connection.getAllTags() : []
|
||||
})
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
|
||||
const layer = this.gameMap.findLayer(layerName);
|
||||
if (layer === undefined) {
|
||||
console.warn('Could not find layer "' + layerName + '" when calling setProperty');
|
||||
return;
|
||||
}
|
||||
const property = (layer.properties as ITiledMapLayerProperty[])?.find((property) => property.name === propertyName);
|
||||
if (property === undefined) {
|
||||
layer.properties = [];
|
||||
layer.properties.push({name : propertyName, type : typeof propertyValue, value : propertyValue});
|
||||
return;
|
||||
}
|
||||
property.value = propertyValue;
|
||||
}
|
||||
|
||||
private setLayerVisibility(layerName: string, visible: boolean): void {
|
||||
const phaserLayer = this.gameMap.findPhaserLayer(layerName);
|
||||
if (phaserLayer === undefined) {
|
||||
console.warn('Could not find layer "' + layerName + '" when calling WA.hideLayer / WA.showLayer');
|
||||
return;
|
||||
}
|
||||
phaserLayer.setVisible(visible);
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
|
||||
private getMapDirUrl(): string {
|
||||
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||
}
|
||||
@ -960,6 +997,8 @@ ${escapedMessage}
|
||||
const { roomId, hash } = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
|
||||
if (!roomId) throw new Error('Could not find the room from its exit key: ' + exitKey);
|
||||
urlManager.pushStartLayerNameToUrl(hash);
|
||||
const menuScene: MenuScene = this.scene.get(MenuSceneName) as MenuScene
|
||||
menuScene.reset()
|
||||
if (roomId !== this.scene.key) {
|
||||
if (this.scene.get(roomId) === null) {
|
||||
console.error("next room not loaded", exitKey);
|
||||
@ -1061,7 +1100,7 @@ ${escapedMessage}
|
||||
}
|
||||
|
||||
private initPositionFromLayerName(layerName: string) {
|
||||
for (const layer of this.gameMap.layersIterator) {
|
||||
for (const layer of this.gameMap.flatLayers) {
|
||||
if ((layerName === layer.name || layer.name.endsWith('/' + layerName)) && layer.type === 'tilelayer' && (layerName === defaultStartLayerName || this.isStartLayer(layer))) {
|
||||
const startPosition = this.startUser(layer);
|
||||
this.startX = startPosition.x + this.mapFile.tilewidth / 2;
|
||||
@ -1151,26 +1190,25 @@ ${escapedMessage}
|
||||
this.updateCameraOffset();
|
||||
}
|
||||
|
||||
addLayer(Layer : Phaser.Tilemaps.TilemapLayer){
|
||||
this.Layers.push(Layer);
|
||||
}
|
||||
|
||||
createCollisionWithPlayer() {
|
||||
//add collision layer
|
||||
this.Layers.forEach((Layer: Phaser.Tilemaps.TilemapLayer) => {
|
||||
this.physics.add.collider(this.CurrentPlayer, Layer, (object1: GameObject, object2: GameObject) => {
|
||||
for (const phaserLayer of this.gameMap.phaserLayers) {
|
||||
if (phaserLayer.type == "tilelayer") {
|
||||
this.physics.add.collider(this.CurrentPlayer, phaserLayer, (object1: GameObject, object2: GameObject) => {
|
||||
//this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name)
|
||||
});
|
||||
Layer.setCollisionByProperty({collides: true});
|
||||
phaserLayer.setCollisionByProperty({collides: true});
|
||||
if (DEBUG_MODE) {
|
||||
//debug code to see the collision hitbox of the object in the top layer
|
||||
Layer.renderDebug(this.add.graphics(), {
|
||||
phaserLayer.renderDebug(this.add.graphics(), {
|
||||
tileColor: null, //non-colliding tiles
|
||||
collidingTileColor: new Phaser.Display.Color(243, 134, 48, 200), // Colliding tiles,
|
||||
faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Colliding face edges
|
||||
});
|
||||
}
|
||||
});
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createCurrentPlayer() {
|
||||
@ -1209,7 +1247,7 @@ ${escapedMessage}
|
||||
this.createCollisionWithPlayer();
|
||||
}
|
||||
|
||||
pushPlayerPosition(event: HasMovedEvent) {
|
||||
pushPlayerPosition(event: HasPlayerMovedEvent) {
|
||||
if (this.lastMoveEventSent === event) {
|
||||
return;
|
||||
}
|
||||
@ -1239,7 +1277,7 @@ ${escapedMessage}
|
||||
* Finds the correct item to outline and outline it (if there is an item to be outlined)
|
||||
* @param event
|
||||
*/
|
||||
private outlineItem(event: HasMovedEvent): void {
|
||||
private outlineItem(event: HasPlayerMovedEvent): void {
|
||||
let x = event.x;
|
||||
let y = event.y;
|
||||
switch (event.direction) {
|
||||
@ -1278,7 +1316,7 @@ ${escapedMessage}
|
||||
this.outlinedItem?.selectable();
|
||||
}
|
||||
|
||||
private doPushPlayerPosition(event: HasMovedEvent): void {
|
||||
private doPushPlayerPosition(event: HasPlayerMovedEvent): void {
|
||||
this.lastMoveEventSent = event;
|
||||
this.lastSentTick = this.currentTick;
|
||||
const camera = this.cameras.main;
|
||||
@ -1288,6 +1326,7 @@ ${escapedMessage}
|
||||
right: camera.scrollX + camera.width,
|
||||
bottom: camera.scrollY + camera.height,
|
||||
});
|
||||
iframeListener.hasPlayerMoved(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1295,7 +1334,6 @@ ${escapedMessage}
|
||||
* @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate.
|
||||
*/
|
||||
update(time: number, delta: number): void {
|
||||
this.dirty = false;
|
||||
mediaManager.updateScene();
|
||||
this.currentTick = time;
|
||||
this.CurrentPlayer.moveUser(delta);
|
||||
@ -1327,7 +1365,7 @@ ${escapedMessage}
|
||||
}
|
||||
// Let's move all users
|
||||
const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
|
||||
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => {
|
||||
updatedPlayersPositions.forEach((moveEvent: HasPlayerMovedEvent, userId: number) => {
|
||||
this.dirty = true;
|
||||
const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
|
||||
if (player === undefined) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type {HasMovedEvent} from "./GameManager";
|
||||
import { MAX_EXTRAPOLATION_TIME } from "../../Enum/EnvironmentVariable";
|
||||
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
||||
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||
|
||||
export class PlayerMovement {
|
||||
public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasMovedEvent, private endTick: number) {
|
||||
public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasPlayerMovedEvent, private endTick: number) {
|
||||
}
|
||||
|
||||
public isOutdated(tick: number): boolean {
|
||||
@ -17,7 +17,7 @@ export class PlayerMovement {
|
||||
return tick > this.endTick + MAX_EXTRAPOLATION_TIME;
|
||||
}
|
||||
|
||||
public getPosition(tick: number): HasMovedEvent {
|
||||
public getPosition(tick: number): HasPlayerMovedEvent {
|
||||
// Special case: end position reached and end position is not moving
|
||||
if (tick >= this.endTick && this.endPosition.moving === false) {
|
||||
//console.log('Movement finished ', this.endPosition)
|
||||
|
@ -2,8 +2,8 @@
|
||||
* This class is in charge of computing the position of all players.
|
||||
* Player movement is delayed by 200ms so position depends on ticks.
|
||||
*/
|
||||
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||
import type { PlayerMovement } from "./PlayerMovement";
|
||||
import type {HasMovedEvent} from "./GameManager";
|
||||
|
||||
export class PlayersPositionInterpolator {
|
||||
playerMovements: Map<number, PlayerMovement> = new Map<number, PlayerMovement>();
|
||||
@ -16,8 +16,8 @@ export class PlayersPositionInterpolator {
|
||||
this.playerMovements.delete(userId);
|
||||
}
|
||||
|
||||
getUpdatedPositions(tick: number) : Map<number, HasMovedEvent> {
|
||||
const positions = new Map<number, HasMovedEvent>();
|
||||
getUpdatedPositions(tick: number): Map<number, HasPlayerMovedEvent> {
|
||||
const positions = new Map<number, HasPlayerMovedEvent>();
|
||||
this.playerMovements.forEach((playerMovement: PlayerMovement, userId: number) => {
|
||||
if (playerMovement.isOutdated(tick)) {
|
||||
//console.log("outdated")
|
||||
|
@ -4,6 +4,8 @@
|
||||
* Represents the interface for the Tiled exported data structure (JSON). Used
|
||||
* when loading resources via Resource loader.
|
||||
*/
|
||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
||||
|
||||
export interface ITiledMap {
|
||||
width: number;
|
||||
height: number;
|
||||
@ -81,6 +83,7 @@ export interface ITiledMapTileLayer {
|
||||
* Draw order (topdown (default), index)
|
||||
*/
|
||||
draworder?: string;
|
||||
phaserLayer?: TilemapLayer;
|
||||
}
|
||||
|
||||
export interface ITiledMapObjectLayer {
|
||||
|
21
front/src/Phaser/Map/LayersFlattener.ts
Normal file
21
front/src/Phaser/Map/LayersFlattener.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import type {ITiledMap, ITiledMapLayer} from "./ITiledMap";
|
||||
|
||||
/**
|
||||
* Flatten the grouped layers
|
||||
*/
|
||||
export function flattenGroupLayersMap(map: ITiledMap) {
|
||||
const flatLayers: ITiledMapLayer[] = [];
|
||||
flattenGroupLayers(map.layers, '', flatLayers);
|
||||
return flatLayers;
|
||||
}
|
||||
|
||||
function flattenGroupLayers(layers : ITiledMapLayer[], prefix : string, flatLayers: ITiledMapLayer[]) {
|
||||
for (const layer of layers) {
|
||||
if (layer.type === 'group') {
|
||||
flattenGroupLayers(layer.layers, prefix + layer.name + '/', flatLayers);
|
||||
} else {
|
||||
layer.name = prefix+layer.name
|
||||
flatLayers.push(layer);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import type {ITiledMap, ITiledMapLayer} from "./ITiledMap";
|
||||
|
||||
/**
|
||||
* Iterates over the layers of a map, flattening the grouped layers
|
||||
*/
|
||||
export class LayersIterator implements IterableIterator<ITiledMapLayer> {
|
||||
|
||||
private layers: ITiledMapLayer[] = [];
|
||||
private pointer: number = 0;
|
||||
|
||||
constructor(private map: ITiledMap) {
|
||||
this.initLayersList(map.layers, '');
|
||||
}
|
||||
|
||||
private initLayersList(layers : ITiledMapLayer[], prefix : string) {
|
||||
for (const layer of layers) {
|
||||
if (layer.type === 'group') {
|
||||
this.initLayersList(layer.layers, prefix + layer.name + '/');
|
||||
} else {
|
||||
const layerWithNewName = { ...layer };
|
||||
layerWithNewName.name = prefix+layerWithNewName.name;
|
||||
this.layers.push(layerWithNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public next(): IteratorResult<ITiledMapLayer> {
|
||||
if (this.pointer < this.layers.length) {
|
||||
return {
|
||||
done: false,
|
||||
value: this.layers[this.pointer++]
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
done: true,
|
||||
value: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<ITiledMapLayer> {
|
||||
return new LayersIterator(this.map);
|
||||
}
|
||||
}
|
@ -10,7 +10,12 @@ import {GameConnexionTypes} from "../../Url/UrlManager";
|
||||
import {WarningContainer, warningContainerHtml, warningContainerKey} from "../Components/WarningContainer";
|
||||
import {worldFullWarningStream} from "../../Connexion/WorldFullWarningStream";
|
||||
import {menuIconVisible} from "../../Stores/MenuStore";
|
||||
import { HtmlUtils } from '../../WebRtc/HtmlUtils';
|
||||
import { iframeListener } from '../../Api/IframeListener';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { videoConstraintStore } from "../../Stores/MediaStore";
|
||||
import {registerMenuCommandStream} from "../../Api/Events/ui/MenuItemRegisterEvent";
|
||||
import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem";
|
||||
import {consoleGlobalMessageManagerVisibleStore} from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||
import {get} from "svelte/store";
|
||||
|
||||
@ -39,12 +44,38 @@ export class MenuScene extends Phaser.Scene {
|
||||
private menuButton!: Phaser.GameObjects.DOMElement;
|
||||
private warningContainer: WarningContainer | null = null;
|
||||
private warningContainerTimeout: NodeJS.Timeout | null = null;
|
||||
|
||||
private subscriptions = new Subscription()
|
||||
constructor() {
|
||||
super({ key: MenuSceneName });
|
||||
|
||||
this.gameQualityValue = localUserStore.getGameQualityValue();
|
||||
this.videoQualityValue = localUserStore.getVideoQualityValue();
|
||||
|
||||
this.subscriptions.add(registerMenuCommandStream.subscribe(menuCommand => {
|
||||
this.addMenuOption(menuCommand);
|
||||
}))
|
||||
|
||||
this.subscriptions.add(iframeListener.unregisterMenuCommandStream.subscribe(menuCommand => {
|
||||
this.destroyMenu(menuCommand);
|
||||
}))
|
||||
}
|
||||
|
||||
reset() {
|
||||
const addedMenuItems = [...this.menuElement.node.querySelectorAll(".fromApi")];
|
||||
for (let index = addedMenuItems.length - 1; index >= 0; index--) {
|
||||
addedMenuItems[index].remove()
|
||||
}
|
||||
}
|
||||
|
||||
public addMenuOption(menuText: string) {
|
||||
const wrappingSection = document.createElement("section")
|
||||
const escapedHtml = HtmlUtils.escapeHtml(menuText);
|
||||
wrappingSection.innerHTML = `<button class="fromApi" id="${escapedHtml}">${escapedHtml}</button>`
|
||||
const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main");
|
||||
if (menuItemContainer) {
|
||||
menuItemContainer.querySelector(`#${escapedHtml}.fromApi`)?.remove()
|
||||
menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks"))
|
||||
}
|
||||
}
|
||||
|
||||
preload() {
|
||||
@ -272,11 +303,17 @@ export class MenuScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private onMenuClick(event: MouseEvent) {
|
||||
if((event?.target as HTMLInputElement).classList.contains('not-button')){
|
||||
const htmlMenuItem = (event?.target as HTMLInputElement);
|
||||
if (htmlMenuItem.classList.contains('not-button')) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
if (htmlMenuItem.classList.contains("fromApi")) {
|
||||
sendMenuClickedEvent(htmlMenuItem.id)
|
||||
return
|
||||
}
|
||||
|
||||
switch ((event?.target as HTMLInputElement).id) {
|
||||
case 'changeNameButton':
|
||||
this.closeSideMenu();
|
||||
@ -360,6 +397,10 @@ export class MenuScene extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
|
||||
public destroyMenu(menu: string) {
|
||||
this.menuElement.getChildByID(menu).remove();
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
@ -27,10 +27,13 @@ export class MediaManager {
|
||||
private remoteVideo: Map<string, HTMLVideoElement> = new Map<string, HTMLVideoElement>();
|
||||
//FIX ME SOUNDMETER: check stalability of sound meter calculation
|
||||
//mySoundMeterElement: HTMLDivElement;
|
||||
|
||||
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||
stopScreenSharingCallBacks: Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
||||
showReportModalCallBacks: Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
|
||||
|
||||
|
||||
|
||||
private focused: boolean = true;
|
||||
|
||||
private triggerCloseJistiFrame: Map<String, Function> = new Map<String, Function>();
|
||||
@ -134,7 +137,10 @@ export class MediaManager {
|
||||
gameOverlayVisibilityStore.hideGameOverlay();
|
||||
}
|
||||
|
||||
|
||||
|
||||
addActiveVideo(user: UserSimplePeerInterface, userName: string = "") {
|
||||
|
||||
const userId = '' + user.userId
|
||||
|
||||
userName = userName.toUpperCase();
|
||||
@ -426,15 +432,15 @@ export class MediaManager {
|
||||
}
|
||||
element.classList.add('active');
|
||||
element.childNodes.forEach((value: ChildNode, index) => {
|
||||
const elementChildre = element.children.item(index);
|
||||
if(!elementChildre){
|
||||
const elementChildren = element.children.item(index);
|
||||
if (!elementChildren) {
|
||||
return;
|
||||
}
|
||||
elementChildre.classList.remove('active');
|
||||
elementChildren.classList.remove('active');
|
||||
if ((index + 1) > volume) {
|
||||
return;
|
||||
}
|
||||
elementChildre.classList.add('active');
|
||||
elementChildren.classList.add('active');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import controls from "./Api/iframe/controls";
|
||||
import ui from "./Api/iframe/ui";
|
||||
import sound from "./Api/iframe/sound";
|
||||
import room from "./Api/iframe/room";
|
||||
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";
|
||||
@ -23,6 +24,7 @@ const wa = {
|
||||
chat,
|
||||
sound,
|
||||
room,
|
||||
player,
|
||||
|
||||
// All methods below are deprecated and should not be used anymore.
|
||||
// They are kept here for backward compatibility.
|
||||
|
@ -1,10 +1,12 @@
|
||||
import "jasmine";
|
||||
import {Room} from "../../../src/Connexion/Room";
|
||||
import {LayersIterator} from "../../../src/Phaser/Map/LayersIterator";
|
||||
import {flattenGroupLayersMap} from "../../../src/Phaser/Map/LayersFlattener";
|
||||
import type {ITiledMapLayer} from "../../../src/Phaser/Map/ITiledMap";
|
||||
|
||||
describe("Layers iterator", () => {
|
||||
describe("Layers flattener", () => {
|
||||
it("should iterate maps with no group", () => {
|
||||
const layersIterator = new LayersIterator({
|
||||
let flatLayers:ITiledMapLayer[] = [];
|
||||
flatLayers = flattenGroupLayersMap({
|
||||
"compressionlevel": -1,
|
||||
"height": 2,
|
||||
"infinite": false,
|
||||
@ -47,14 +49,15 @@ describe("Layers iterator", () => {
|
||||
})
|
||||
|
||||
const layers = [];
|
||||
for (const layer of layersIterator) {
|
||||
for (const layer of flatLayers) {
|
||||
layers.push(layer.name);
|
||||
}
|
||||
expect(layers).toEqual(['Tile Layer 1', 'Tile Layer 2']);
|
||||
});
|
||||
|
||||
it("should iterate maps with recursive groups", () => {
|
||||
const layersIterator = new LayersIterator({
|
||||
let flatLayers:ITiledMapLayer[] = [];
|
||||
flatLayers = flattenGroupLayersMap({
|
||||
"compressionlevel": -1,
|
||||
"height": 2,
|
||||
"infinite": false,
|
||||
@ -139,7 +142,7 @@ describe("Layers iterator", () => {
|
||||
})
|
||||
|
||||
const layers = [];
|
||||
for (const layer of layersIterator) {
|
||||
for (const layer of flatLayers) {
|
||||
layers.push(layer.name);
|
||||
}
|
||||
expect(layers).toEqual(['Group 1/Group 3/Tile3', 'Group 1/Group 3/Tile2', 'Group 1/Group 2/Tile1']);
|
||||
|
13
maps/tests/Metadata/customMenu.html
Normal file
13
maps/tests/Metadata/customMenu.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
WA.ui.registerMenuCommand("test", () => {
|
||||
WA.chat.sendChatMessage("test clicked", "menu cmd")
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
279
maps/tests/Metadata/customMenu.json
Normal file
279
maps/tests/Metadata/customMenu.json
Normal file
@ -0,0 +1,279 @@
|
||||
{ "compressionlevel":-1,
|
||||
"editorsettings":
|
||||
{
|
||||
"export":
|
||||
{
|
||||
"target":"."
|
||||
}
|
||||
},
|
||||
"height":10,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[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, 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, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51],
|
||||
"height":10,
|
||||
"id":2,
|
||||
"name":"bottom",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[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, 101, 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":6,
|
||||
"name":"exit",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"exitUrl",
|
||||
"type":"string",
|
||||
"value":"showHideLayer.json"
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 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":4,
|
||||
"name":"metadata",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"openWebsite",
|
||||
"type":"string",
|
||||
"value":"customMenu.html"
|
||||
},
|
||||
{
|
||||
"name":"openWebsiteAllowApi",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":5,
|
||||
"name":"floorLayer",
|
||||
"objects":[
|
||||
{
|
||||
"height":217.142414860681,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":9,
|
||||
"text":"Test : \nWalk on the grass, an iframe open.\nResult : \nOpen the menu, a new sub-menu is displayed.\n\nTest : \nExit the grass\nResult : \nOpen the menu, the submenu has disappeared.\n\nTest : \nClick on the 'HELP' menu.\nResult : \nChat open and a 'HELP' message is displayed.\n\nTest : \nWalk on the red tile then open the menu.\nResult : \nYou have exit the room to another room, the submenu has disappeared.\n",
|
||||
"wrap":true
|
||||
},
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":305.097705765524,
|
||||
"x":15.1244925229277,
|
||||
"y":103.029937496349
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":7,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":1,
|
||||
"image":"tileset_dungeon.png",
|
||||
"imageheight":256,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"TDungeon",
|
||||
"spacing":0,
|
||||
"tilecount":64,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"id":0,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":9,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":17,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":19,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":32
|
||||
},
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":65,
|
||||
"image":"floortileset.png",
|
||||
"imageheight":288,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"Floor",
|
||||
"spacing":0,
|
||||
"tilecount":72,
|
||||
"tileheight":32,
|
||||
"tilewidth":32
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
BIN
maps/tests/Metadata/floortileset.png
Normal file
BIN
maps/tests/Metadata/floortileset.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
16
maps/tests/Metadata/getCurrentRoom.html
Normal file
16
maps/tests/Metadata/getCurrentRoom.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
WA.room.getCurrentRoom().then((room) => {
|
||||
console.log('id : ', room.id);
|
||||
console.log('map : ', room.map);
|
||||
console.log('mapUrl : ', room.mapUrl);
|
||||
console.log('startLayer : ', room.startLayer);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
279
maps/tests/Metadata/getCurrentRoom.json
Normal file
279
maps/tests/Metadata/getCurrentRoom.json
Normal file
@ -0,0 +1,279 @@
|
||||
{ "compressionlevel":-1,
|
||||
"editorsettings":
|
||||
{
|
||||
"export":
|
||||
{
|
||||
"target":"."
|
||||
}
|
||||
},
|
||||
"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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 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":10,
|
||||
"name":"HereYouAppered",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"startLayer",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[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, 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, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51],
|
||||
"height":10,
|
||||
"id":2,
|
||||
"name":"bottom",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 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":4,
|
||||
"name":"metadata",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"openWebsite",
|
||||
"type":"string",
|
||||
"value":"getCurrentRoom.html"
|
||||
},
|
||||
{
|
||||
"name":"openWebsiteAllowApi",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":5,
|
||||
"name":"floorLayer",
|
||||
"objects":[
|
||||
{
|
||||
"height":191.607568521364,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":9,
|
||||
"text":"Test : \nWalk on the grass and open the console.\n\nResult : \nYou should see a console.log() of the following attributes : \n\t- id : ID of the current room\n\t- map : data of the JSON file of the map\n\t- mapUrl : url of the JSON file of the map\n\t- startLayer : Name of the layer where the current user started (HereYouAppered)\n\n\n",
|
||||
"wrap":true
|
||||
},
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":305.097705765524,
|
||||
"x":14.750638909983,
|
||||
"y":128.564783835666
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":11,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":1,
|
||||
"image":"tileset_dungeon.png",
|
||||
"imageheight":256,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"TDungeon",
|
||||
"spacing":0,
|
||||
"tilecount":64,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"id":0,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":9,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":17,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":19,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":32
|
||||
},
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":65,
|
||||
"image":"floortileset.png",
|
||||
"imageheight":288,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"Floor",
|
||||
"spacing":0,
|
||||
"tilecount":72,
|
||||
"tileheight":32,
|
||||
"tilewidth":32
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
15
maps/tests/Metadata/getCurrentUser.html
Normal file
15
maps/tests/Metadata/getCurrentUser.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
WA.room.getCurrentUser().then((user) => {
|
||||
console.log('id : ', user.id);
|
||||
console.log('nickName : ', user.nickName);
|
||||
console.log('tags : ', user.tags);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
296
maps/tests/Metadata/getCurrentUser.json
Normal file
296
maps/tests/Metadata/getCurrentUser.json
Normal file
@ -0,0 +1,296 @@
|
||||
{ "compressionlevel":-1,
|
||||
"editorsettings":
|
||||
{
|
||||
"export":
|
||||
{
|
||||
"target":"."
|
||||
}
|
||||
},
|
||||
"height":10,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[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, 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, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51],
|
||||
"height":10,
|
||||
"id":2,
|
||||
"name":"bottom",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[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, 101, 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":9,
|
||||
"name":"exit",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"exitUrl",
|
||||
"type":"string",
|
||||
"value":"getCurrentRoom.json#HereYouAppered"
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 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":4,
|
||||
"name":"metadata",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"openWebsite",
|
||||
"type":"string",
|
||||
"value":"getCurrentUser.html"
|
||||
},
|
||||
{
|
||||
"name":"openWebsiteAllowApi",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":5,
|
||||
"name":"floorLayer",
|
||||
"objects":[
|
||||
{
|
||||
"height":151.839293303871,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":9,
|
||||
"text":"Test : \nWalk on the grass, open the console.\n\nResut : \nYou should see a console.log() of the following attributes :\n\t- id : ID of the current user\n\t- nickName : Name of the current user\n\t- tags : List of tags of the current user\n\nFinally : \nWalk on the red tile and continue the test in an another room.",
|
||||
"wrap":true
|
||||
},
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":305.097705765524,
|
||||
"x":14.750638909983,
|
||||
"y":159.621625296353
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":10,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":1,
|
||||
"image":"tileset_dungeon.png",
|
||||
"imageheight":256,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"TDungeon",
|
||||
"spacing":0,
|
||||
"tilecount":64,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"id":0,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":9,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":17,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":19,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":32
|
||||
},
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":65,
|
||||
"image":"floortileset.png",
|
||||
"imageheight":288,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"Floor",
|
||||
"spacing":0,
|
||||
"tilecount":72,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"animation":[
|
||||
{
|
||||
"duration":100,
|
||||
"tileid":9
|
||||
},
|
||||
{
|
||||
"duration":100,
|
||||
"tileid":64
|
||||
},
|
||||
{
|
||||
"duration":100,
|
||||
"tileid":55
|
||||
}],
|
||||
"id":0
|
||||
}],
|
||||
"tilewidth":32
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
12
maps/tests/Metadata/playerMove.html
Normal file
12
maps/tests/Metadata/playerMove.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="playerMovement"></div>
|
||||
<script>
|
||||
WA.player.onPlayerMove(console.log);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
254
maps/tests/Metadata/playerMove.json
Normal file
254
maps/tests/Metadata/playerMove.json
Normal file
@ -0,0 +1,254 @@
|
||||
{ "compressionlevel":-1,
|
||||
"height":10,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[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, 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, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51],
|
||||
"height":10,
|
||||
"id":2,
|
||||
"name":"bottom",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 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":4,
|
||||
"name":"metadata",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"openWebsite",
|
||||
"type":"string",
|
||||
"value":"playerMove.html"
|
||||
},
|
||||
{
|
||||
"name":"openWebsiteAllowApi",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":5,
|
||||
"name":"floorLayer",
|
||||
"objects":[
|
||||
{
|
||||
"height":159.195104854255,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":9,
|
||||
"text":"Test : \nWalk on the grass, an iframe open.\nResult : \nIf you move on the grass, your movement will be displayed in the console.log(). \nYour movement appears according to the following rules : \n - When you stop (the moving attribute will be false)\n - When you change direction (the direction attribute will change value)\n - Every 200ms if you keep moving in the same direction.\n\nMovement are represented by the following attributes : \n - moving : if you are moving or not.\n - direction : the direction where you are moving into\n - X and Y coordinates : Place of your character in the room.\n\n\n",
|
||||
"wrap":true
|
||||
},
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":305.097705765524,
|
||||
"x":14.750638909983,
|
||||
"y":160.977247502775
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":10,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":1,
|
||||
"image":"tileset_dungeon.png",
|
||||
"imageheight":256,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"TDungeon",
|
||||
"spacing":0,
|
||||
"tilecount":64,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"id":0,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":9,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":17,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":19,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":32
|
||||
},
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":65,
|
||||
"image":"floortileset.png",
|
||||
"imageheight":288,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"Floor",
|
||||
"spacing":0,
|
||||
"tilecount":72,
|
||||
"tileheight":32,
|
||||
"tilewidth":32
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
12
maps/tests/Metadata/setProperty.html
Normal file
12
maps/tests/Metadata/setProperty.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
WA.room.setProperty('iframeTest', 'openWebsite', 'https://www.wikipedia.org/');
|
||||
WA.room.setProperty('metadata', 'openWebsite', 'https://www.wikipedia.org/');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
266
maps/tests/Metadata/setProperty.json
Normal file
266
maps/tests/Metadata/setProperty.json
Normal file
@ -0,0 +1,266 @@
|
||||
{ "compressionlevel":-1,
|
||||
"height":10,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[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, 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, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51],
|
||||
"height":10,
|
||||
"id":2,
|
||||
"name":"bottom",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 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":4,
|
||||
"name":"metadata",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"openWebsite",
|
||||
"type":"string",
|
||||
"value":"setProperty.html"
|
||||
},
|
||||
{
|
||||
"name":"openWebsiteAllowApi",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[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, 101, 101, 101, 101, 101, 0, 0, 0, 0, 0, 101, 101, 101, 101, 101, 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":7,
|
||||
"name":"iframeTest",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":5,
|
||||
"name":"floorLayer",
|
||||
"objects":[
|
||||
{
|
||||
"height":157.325836789532,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":9,
|
||||
"text":"Test : \nWalk on the red tiles.\nResult :\nNothing happens.\n\nTest : \nWalk on the grass, an iframe open. Then walk on the red tiles.\nResult : \nAn iframe of Wikipedia open.\n\nTest : \nWalk on the grass again.\nResult : \nAn iframe of Wikipedia open.\n",
|
||||
"wrap":true
|
||||
},
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":305.097705765524,
|
||||
"x":15.1244925229277,
|
||||
"y":162.846515567498
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":8,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":1,
|
||||
"image":"tileset_dungeon.png",
|
||||
"imageheight":256,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"TDungeon",
|
||||
"spacing":0,
|
||||
"tilecount":64,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"id":0,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":9,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":17,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":19,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":32
|
||||
},
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":65,
|
||||
"image":"floortileset.png",
|
||||
"imageheight":288,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"Floor",
|
||||
"spacing":0,
|
||||
"tilecount":72,
|
||||
"tileheight":32,
|
||||
"tilewidth":32
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
21
maps/tests/Metadata/showHideLayer.html
Normal file
21
maps/tests/Metadata/showHideLayer.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<label for="show/hideLayer">Crysal Layer : </label><input type="checkbox" id="show/hideLayer" name="visible" value="show" checked>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('show/hideLayer').onclick = () => {
|
||||
if (document.getElementById('show/hideLayer').checked) {
|
||||
WA.room.showLayer('crystal');
|
||||
}
|
||||
else {
|
||||
WA.room.hideLayer('crystal');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
266
maps/tests/Metadata/showHideLayer.json
Normal file
266
maps/tests/Metadata/showHideLayer.json
Normal file
@ -0,0 +1,266 @@
|
||||
{ "compressionlevel":-1,
|
||||
"height":10,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[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, 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, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51],
|
||||
"height":10,
|
||||
"id":2,
|
||||
"name":"bottom",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[22, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 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, 22, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 22, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"height":10,
|
||||
"id":6,
|
||||
"name":"crystal",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 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":4,
|
||||
"name":"metadata",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"openWebsite",
|
||||
"type":"string",
|
||||
"value":"showHideLayer.html"
|
||||
},
|
||||
{
|
||||
"name":"openWebsiteAllowApi",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":5,
|
||||
"name":"floorLayer",
|
||||
"objects":[
|
||||
{
|
||||
"height":191.346515567498,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":9,
|
||||
"text":"Test : \nWalk on the grass, an iframe open, uncheck the checkbox.\nResult : \nCrystals disappeared.\n\nTest : \nCheck the checkbox\nResult : \nCrystals appear.",
|
||||
"wrap":true
|
||||
},
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":306.219266604358,
|
||||
"x":14.0029316840937,
|
||||
"y":128.078129563643
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":7,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":1,
|
||||
"image":"tileset_dungeon.png",
|
||||
"imageheight":256,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"TDungeon",
|
||||
"spacing":0,
|
||||
"tilecount":64,
|
||||
"tileheight":32,
|
||||
"tiles":[
|
||||
{
|
||||
"id":0,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":8,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":9,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":10,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":11,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":12,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":16,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":17,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":18,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":19,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id":20,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":32
|
||||
},
|
||||
{
|
||||
"columns":8,
|
||||
"firstgid":65,
|
||||
"image":"floortileset.png",
|
||||
"imageheight":288,
|
||||
"imagewidth":256,
|
||||
"margin":0,
|
||||
"name":"Floor",
|
||||
"spacing":0,
|
||||
"tilecount":72,
|
||||
"tileheight":32,
|
||||
"tilewidth":32
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
BIN
maps/tests/Metadata/tileset_dungeon.png
Normal file
BIN
maps/tests/Metadata/tileset_dungeon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
@ -2,15 +2,12 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="http://play.workadventure.localhost/iframe_api.js"></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<button id="sendchat">Send chat message</button>
|
||||
<script>
|
||||
document.getElementById('sendchat').onclick = () => {
|
||||
WA.sendChatMessage('Hello world!', 'Mr Robot');
|
||||
WA.sendChatMessage('Hello world!', 'Mr ROBOT');
|
||||
}
|
||||
</script>
|
||||
<div id="chatSent"></div>
|
||||
|
@ -1,4 +1,11 @@
|
||||
{ "compressionlevel":-1,
|
||||
"editorsettings":
|
||||
{
|
||||
"export":
|
||||
{
|
||||
"target":"."
|
||||
}
|
||||
},
|
||||
"height":10,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
@ -49,6 +56,18 @@
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 93, 0, 104, 0, 0, 0, 0, 0, 0, 0, 104, 0, 115, 0, 0, 0, 93, 0, 0, 0, 115, 0, 0, 0, 93, 0, 104, 0, 0, 0, 0, 0, 0, 0, 104, 0, 115, 93, 0, 0, 0, 0, 0, 0, 115, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 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":6,
|
||||
"name":"Metadata",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"draworder":"topdown",
|
||||
"id":3,
|
||||
@ -78,11 +97,11 @@
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":6,
|
||||
"nextlayerid":7,
|
||||
"nextobjectid":3,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"2021.03.23",
|
||||
"tiledversion":"1.4.3",
|
||||
"tileheight":32,
|
||||
"tilesets":[
|
||||
{
|
||||
@ -100,6 +119,6 @@
|
||||
}],
|
||||
"tilewidth":32,
|
||||
"type":"map",
|
||||
"version":1.5,
|
||||
"version":1.4,
|
||||
"width":10
|
||||
}
|
@ -106,6 +106,54 @@
|
||||
<a href="#" class="testLink" data-testmap="help_camera_setting.json" target="_blank">Test the HelpCameraSettingScene</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-custom-menu"> Success <input type="radio" name="test-custom-menu"> Failure <input type="radio" name="test-custom-menu" checked> Pending
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="testLink" data-testmap="Metadata/customMenu.json" target="_blank">Testing add a custom menu by scripting API</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-getCurrentRoom"> Success <input type="radio" name="test-getCurrentRoom"> Failure <input type="radio" name="test-getCurrentRoom" checked> Pending
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="testLink" data-testmap="Metadata/getCurrentRoom.json" target="_blank">Testing return current room attributes by Scripting API (Need to test from current user)</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-getCurrentUser"> Success <input type="radio" name="test-getCurrentUser"> Failure <input type="radio" name="test-getCurrentUser" checked> Pending
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="testLink" data-testmap="Metadata/getCurrentUser.json" target="_blank">Testing return current user attributes by Scripting API</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-player-move"> Success <input type="radio" name="test-player-move"> Failure <input type="radio" name="test-player-move" checked> Pending
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="testLink" data-testmap="Metadata/playerMove.json" target="_blank">Test listening player movement by Scripting API</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-setProperty"> Success <input type="radio" name="test-setProperty"> Failure <input type="radio" name="test-setProperty" checked> Pending
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="testLink" data-testmap="Metadata/setProperty.json" target="_blank">Testing set a property on a layer by Scripting API</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-show-hide"> Success <input type="radio" name="test-show-hide"> Failure <input type="radio" name="test-show-hide" checked> Pending
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="testLink" data-testmap="Metadata/showHideLayer.json" target="_blank">Testing show or hide a layer by Scripting API</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" name="test-animated-tiles"> Success <input type="radio" name="test-animated-tiles"> Failure <input type="radio" name="test-animated-tiles" checked> Pending
|
||||
|
Loading…
Reference in New Issue
Block a user