commit
9bdda210f5
@ -22,6 +22,10 @@ MAX_USERNAME_LENGTH=8
|
|||||||
OPID_CLIENT_ID=
|
OPID_CLIENT_ID=
|
||||||
OPID_CLIENT_SECRET=
|
OPID_CLIENT_SECRET=
|
||||||
OPID_CLIENT_ISSUER=
|
OPID_CLIENT_ISSUER=
|
||||||
|
OPID_CLIENT_REDIRECT_URL=
|
||||||
|
OPID_LOGIN_SCREEN_PROVIDER=http://pusher.workadventure.localhost/login-screen
|
||||||
|
OPID_PROFILE_SCREEN_PROVIDER=
|
||||||
|
DISABLE_ANONYMOUS=
|
||||||
|
|
||||||
# If you want to have a contact page in your menu, you MUST set CONTACT_URL to the URL of the page that you want
|
# If you want to have a contact page in your menu, you MUST set CONTACT_URL to the URL of the page that you want
|
||||||
CONTACT_URL=
|
CONTACT_URL=
|
@ -1,9 +1,13 @@
|
|||||||
## Version develop
|
## Version develop
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
- Added multi Co-Website management
|
||||||
|
|
||||||
### Bugfix
|
### Bugfix
|
||||||
- Moving a discussion over a user will now add this user to the discussion
|
- Moving a discussion over a user will now add this user to the discussion
|
||||||
- Being in a silent zone new forces mediaConstraints to false (#1508)
|
- Being in a silent zone new forces mediaConstraints to false (#1508)
|
||||||
- Fixes for the emote menu (#1501)
|
- Fixes for the emote menu (#1501)
|
||||||
|
- Fixing chat message attributed to wrong user (#1507 #1528)
|
||||||
|
|
||||||
## Version 1.5.0
|
## Version 1.5.0
|
||||||
### Updates
|
### Updates
|
||||||
|
@ -38,7 +38,7 @@ Note: on some OSes, you will need to add this line to your `/etc/hosts` file:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note: If on the first run you get a page with "network error". Try to ``docker-compose stop`` , then ``docker-compose start``.
|
Note: If on the first run you get a page with "network error". Try to ``docker-compose stop`` , then ``docker-compose start``.
|
||||||
Note 2: If you are still getting "network error". Make sure you are authorizing the self-signed certificate by entering https://pusher.workadventure.testing and accepting them.
|
Note 2: If you are still getting "network error". Make sure you are authorizing the self-signed certificate by entering https://pusher.workadventure.localhost and accepting them.
|
||||||
|
|
||||||
### MacOS developers, your environment with Vagrant
|
### MacOS developers, your environment with Vagrant
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/thecodingmachine/workadventure#readme",
|
"homepage": "https://github.com/thecodingmachine/workadventure#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@workadventure/tiled-map-type-guard": "^1.0.2",
|
"@workadventure/tiled-map-type-guard": "^1.0.3",
|
||||||
"axios": "^0.21.2",
|
"axios": "^0.21.2",
|
||||||
"busboy": "^0.3.1",
|
"busboy": "^0.3.1",
|
||||||
"circular-json": "^0.5.9",
|
"circular-json": "^0.5.9",
|
||||||
|
@ -194,10 +194,10 @@
|
|||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
tsutils "^3.17.1"
|
tsutils "^3.17.1"
|
||||||
|
|
||||||
"@workadventure/tiled-map-type-guard@^1.0.2":
|
"@workadventure/tiled-map-type-guard@^1.0.3":
|
||||||
version "1.0.2"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@workadventure/tiled-map-type-guard/-/tiled-map-type-guard-1.0.2.tgz#4171550f6cd71be19791faef48360d65d698bcb0"
|
resolved "https://registry.yarnpkg.com/@workadventure/tiled-map-type-guard/-/tiled-map-type-guard-1.0.3.tgz#62c2061cacbe1360b84162af0b7e4639ed8bfa7e"
|
||||||
integrity sha512-RCtygGV5y9cb7QoyGMINBE9arM5pyXjkxvXgA5uXEv4GDbXKorhFim/rHgwbVR+eFnVF3rDgWbRnk3DIaHt+lQ==
|
integrity sha512-pUMxBBZHYAFkpnGWZAVAE8+M+Wn9UtzqZhXvBBBbB1gEakHIka7ahdTGfh0DgRaWrVszVXOP3tf49Dhdmn9pDg==
|
||||||
dependencies:
|
dependencies:
|
||||||
generic-type-guard "^3.4.1"
|
generic-type-guard "^3.4.1"
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ services:
|
|||||||
TURN_USER: ""
|
TURN_USER: ""
|
||||||
TURN_PASSWORD: ""
|
TURN_PASSWORD: ""
|
||||||
START_ROOM_URL: "$START_ROOM_URL"
|
START_ROOM_URL: "$START_ROOM_URL"
|
||||||
|
DISABLE_ANONYMOUS: "$DISABLE_ANONYMOUS"
|
||||||
command: yarn run start
|
command: yarn run start
|
||||||
volumes:
|
volumes:
|
||||||
- ./front:/usr/src/app
|
- ./front:/usr/src/app
|
||||||
@ -70,6 +71,9 @@ services:
|
|||||||
OPID_CLIENT_ID: $OPID_CLIENT_ID
|
OPID_CLIENT_ID: $OPID_CLIENT_ID
|
||||||
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
|
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
|
||||||
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
|
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
|
||||||
|
OPID_CLIENT_REDIRECT_URL: $OPID_CLIENT_REDIRECT_URL
|
||||||
|
OPID_PROFILE_SCREEN_PROVIDER: $OPID_PROFILE_SCREEN_PROVIDER
|
||||||
|
DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS
|
||||||
volumes:
|
volumes:
|
||||||
- ./pusher:/usr/src/app
|
- ./pusher:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
|
@ -29,6 +29,7 @@ services:
|
|||||||
PUSHER_URL: //pusher.workadventure.localhost
|
PUSHER_URL: //pusher.workadventure.localhost
|
||||||
UPLOADER_URL: //uploader.workadventure.localhost
|
UPLOADER_URL: //uploader.workadventure.localhost
|
||||||
ADMIN_URL: //workadventure.localhost
|
ADMIN_URL: //workadventure.localhost
|
||||||
|
ICON_URL: //icon.workadventure.localhost
|
||||||
STARTUP_COMMAND_1: ./templater.sh
|
STARTUP_COMMAND_1: ./templater.sh
|
||||||
STARTUP_COMMAND_2: yarn install
|
STARTUP_COMMAND_2: yarn install
|
||||||
STUN_SERVER: "stun:stun.l.google.com:19302"
|
STUN_SERVER: "stun:stun.l.google.com:19302"
|
||||||
@ -42,6 +43,8 @@ services:
|
|||||||
START_ROOM_URL: "$START_ROOM_URL"
|
START_ROOM_URL: "$START_ROOM_URL"
|
||||||
MAX_PER_GROUP: "$MAX_PER_GROUP"
|
MAX_PER_GROUP: "$MAX_PER_GROUP"
|
||||||
MAX_USERNAME_LENGTH: "$MAX_USERNAME_LENGTH"
|
MAX_USERNAME_LENGTH: "$MAX_USERNAME_LENGTH"
|
||||||
|
DISABLE_ANONYMOUS: "$DISABLE_ANONYMOUS"
|
||||||
|
OPID_LOGIN_SCREEN_PROVIDER: "$OPID_LOGIN_SCREEN_PROVIDER"
|
||||||
command: yarn run start
|
command: yarn run start
|
||||||
volumes:
|
volumes:
|
||||||
- ./front:/usr/src/app
|
- ./front:/usr/src/app
|
||||||
@ -70,6 +73,9 @@ services:
|
|||||||
OPID_CLIENT_ID: $OPID_CLIENT_ID
|
OPID_CLIENT_ID: $OPID_CLIENT_ID
|
||||||
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
|
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
|
||||||
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
|
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
|
||||||
|
OPID_CLIENT_REDIRECT_URL: $OPID_CLIENT_REDIRECT_URL
|
||||||
|
OPID_PROFILE_SCREEN_PROVIDER: $OPID_PROFILE_SCREEN_PROVIDER
|
||||||
|
DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS
|
||||||
volumes:
|
volumes:
|
||||||
- ./pusher:/usr/src/app
|
- ./pusher:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
@ -177,6 +183,17 @@ services:
|
|||||||
- "traefik.http.routers.redisinsight-ssl.tls=true"
|
- "traefik.http.routers.redisinsight-ssl.tls=true"
|
||||||
- "traefik.http.routers.redisinsight-ssl.service=redisinsight"
|
- "traefik.http.routers.redisinsight-ssl.service=redisinsight"
|
||||||
|
|
||||||
|
icon:
|
||||||
|
image: matthiasluedtke/iconserver:v3.13.0
|
||||||
|
labels:
|
||||||
|
- "traefik.http.routers.icon.rule=Host(`icon.workadventure.localhost`)"
|
||||||
|
- "traefik.http.routers.icon.entryPoints=web"
|
||||||
|
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||||
|
- "traefik.http.routers.icon-ssl.rule=Host(`icon.workadventure.localhost`)"
|
||||||
|
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||||
|
- "traefik.http.routers.icon-ssl.tls=true"
|
||||||
|
- "traefik.http.routers.icon-ssl.service=icon"
|
||||||
|
|
||||||
# coturn:
|
# coturn:
|
||||||
# image: coturn/coturn:4.5.2
|
# image: coturn/coturn:4.5.2
|
||||||
# command:
|
# command:
|
||||||
|
@ -3,19 +3,21 @@
|
|||||||
|
|
||||||
The list of functions below is **deprecated**. You should not use those but. use the replacement functions.
|
The list of functions below is **deprecated**. You should not use those but. use the replacement functions.
|
||||||
|
|
||||||
- Method `WA.sendChatMessage` is deprecated. It has been renamed to `WA.chat.sendChatMessage`.
|
- Method `WA.sendChatMessage` is deprecated. It has been renamed to [`WA.chat.sendChatMessage`](api-chat.md#sending-a-message-in-the-chat).
|
||||||
- Method `WA.disablePlayerControls` is deprecated. It has been renamed to `WA.controls.disablePlayerControls`.
|
- Method `WA.disablePlayerControls` is deprecated. It has been renamed to [`WA.controls.disablePlayerControls`](api-controls.md#disabling--restoring-controls).
|
||||||
- Method `WA.restorePlayerControls` is deprecated. It has been renamed to `WA.controls.restorePlayerControls`.
|
- Method `WA.restorePlayerControls` is deprecated. It has been renamed to [`WA.controls.restorePlayerControls`](api-controls.md#disabling--restoring-controls).
|
||||||
- Method `WA.displayBubble` is deprecated. It has been renamed to `WA.ui.displayBubble`.
|
- Method `WA.displayBubble` is deprecated. It has been renamed to `WA.ui.displayBubble`.
|
||||||
- Method `WA.removeBubble` is deprecated. It has been renamed to `WA.ui.removeBubble`.
|
- Method `WA.removeBubble` is deprecated. It has been renamed to `WA.ui.removeBubble`.
|
||||||
- Method `WA.openTab` is deprecated. It has been renamed to `WA.nav.openTab`.
|
- Method `WA.openTab` is deprecated. It has been renamed to [`WA.nav.openTab`](api-nav.md#opening-a-web-page-in-a-new-tab).
|
||||||
- Method `WA.loadSound` is deprecated. It has been renamed to `WA.sound.loadSound`.
|
- Method `WA.loadSound` is deprecated. It has been renamed to [`WA.sound.loadSound`](api-sound.md#load-a-sound-from-an-url).
|
||||||
- Method `WA.goToPage` is deprecated. It has been renamed to `WA.nav.goToPage`.
|
- Method `WA.goToPage` is deprecated. It has been renamed to [`WA.nav.goToPage`](api-nav.md#opening-a-web-page-in-the-current-tab).
|
||||||
- Method `WA.goToRoom` is deprecated. It has been renamed to `WA.nav.goToRoom`.
|
- Method `WA.goToRoom` is deprecated. It has been renamed to [`WA.nav.goToRoom`](api-nav.md#going-to-a-different-map-from-the-script).
|
||||||
- Method `WA.openCoWebSite` is deprecated. It has been renamed to `WA.nav.openCoWebSite`.
|
- Method `WA.openCoWebSite` is deprecated. It has been renamed to [`WA.nav.openCoWebSite`](api-nav.md#openingclosing-web-page-in-co-websites).
|
||||||
- Method `WA.closeCoWebSite` is deprecated. It has been renamed to `WA.nav.closeCoWebSite`.
|
- Method `WA.closeCoWebSite` is deprecated. It has been remove and [replace by a function close](api-nav.md#openingclosing-web-page-in-co-websites).
|
||||||
- Method `WA.openPopup` is deprecated. It has been renamed to `WA.ui.openPopup`.
|
- Method `WA.openPopup` is deprecated. It has been renamed to [`WA.ui.openPopup`](api-ui.md#opening-a-popup).
|
||||||
- Method `WA.onChatMessage` is deprecated. It has been renamed to `WA.chat.onChatMessage`.
|
- Method `WA.onChatMessage` is deprecated. It has been renamed to [`WA.chat.onChatMessage`](api-chat.md#listening-to-messages-from-the-chat).
|
||||||
- Method `WA.onEnterZone` is deprecated. It has been renamed to `WA.room.onEnterZone`.
|
- Method `WA.onEnterZone` is deprecated. It has been renamed to [`WA.room.onEnterZone`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||||
- Method `WA.onLeaveZone` is deprecated. It has been renamed to `WA.room.onLeaveZone`.
|
- Method `WA.onLeaveZone` is deprecated. It has been renamed to [`WA.room.onLeaveZone`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||||
- Method `WA.ui.registerMenuCommand` parameter `callback` is deprecated. Use `WA.ui.registerMenuCommand(commandDescriptor: string, options: MenuOptions)`.
|
- Method `WA.ui.registerMenuCommand` parameter `callback` is deprecated. Use [`WA.ui.registerMenuCommand(commandDescriptor: string, options: MenuOptions)`](api-ui.md#add-custom-menu).
|
||||||
|
- Method `WA.room.onEnterZone` is deprecated. Use instead [`WA.room.onEnterLayer`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||||
|
- Method `WA.room.onLeaveZone` is deprecated. Use instead [`WA.room.onLeaveLayer`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
@ -49,19 +49,34 @@ WA.nav.goToRoom('../otherMap/map.json');
|
|||||||
WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
|
WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Opening/closing a web page in an iFrame
|
### Opening/closing web page in Co-Websites
|
||||||
|
|
||||||
```
|
```
|
||||||
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = ""): void
|
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number = 0): Promise<CoWebsite>
|
||||||
WA.nav.closeCoWebSite(): void
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow).
|
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow), position in whitch slot the web page will be open.
|
||||||
|
You can have only 5 co-wbesites open simultaneously.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
WA.nav.openCoWebSite('https://www.wikipedia.org/');
|
const coWebsite = await WA.nav.openCoWebSite('https://www.wikipedia.org/');
|
||||||
|
const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 1);
|
||||||
// ...
|
// ...
|
||||||
WA.nav.closeCoWebSite();
|
coWebsite.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get all Co-Websites
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.nav.getCoWebSites(): Promise<CoWebsite[]>
|
||||||
|
```
|
||||||
|
|
||||||
|
Get all opened co-websites with their ids and positions.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const coWebsites = await WA.nav.getCowebSites();
|
||||||
```
|
```
|
||||||
|
@ -69,6 +69,8 @@ The event has the following attributes :
|
|||||||
* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving.
|
* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving.
|
||||||
* **x (number):** coordinate X of the current player.
|
* **x (number):** coordinate X of the current player.
|
||||||
* **y (number):** coordinate Y of the current player.
|
* **y (number):** coordinate Y of the current player.
|
||||||
|
* **oldX (number):** old coordinate X of the current player.
|
||||||
|
* **oldY (number):** old coordinate Y of the current player.
|
||||||
|
|
||||||
**callback:** the function that will be called when the current player is moving. It contains the event.
|
**callback:** the function that will be called when the current player is moving. It contains the event.
|
||||||
|
|
||||||
|
@ -17,35 +17,27 @@ The name of the layers of this map are :
|
|||||||
* `bottom/build/carpet`
|
* `bottom/build/carpet`
|
||||||
* `wall`
|
* `wall`
|
||||||
|
|
||||||
### Detecting when the user enters/leaves a zone
|
### Detecting when the user enters/leaves a layer
|
||||||
|
|
||||||
```
|
```
|
||||||
WA.room.onEnterZone(name: string, callback: () => void): void
|
WA.room.onEnterLayer(name: string): Subscription
|
||||||
WA.room.onLeaveZone(name: string, callback: () => void): void
|
WA.room.onLeaveLayer(name: string): Subscription
|
||||||
```
|
```
|
||||||
|
|
||||||
Listens to the position of the current user. The event is triggered when the user enters or leaves a given zone. The name of the zone is stored in the map, on a dedicated layer with the `zone` property.
|
Listens to the position of the current user. The event is triggered when the user enters or leaves a given layer.
|
||||||
|
|
||||||
<div>
|
* **name**: the name of the layer who as defined in Tiled.
|
||||||
<figure class="figure">
|
|
||||||
<img src="images/trigger_event.png" class="figure-img img-fluid rounded" alt="" />
|
|
||||||
<figcaption class="figure-caption">The `zone` property, applied on a layer</figcaption>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
* **name**: the name of the zone, as defined in the `zone` property.
|
|
||||||
* **callback**: the function that will be called when a user enters or leaves the zone.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
WA.room.onEnterZone('myZone', () => {
|
WA.room.onEnterLayer('myLayer').subscribe(() => {
|
||||||
WA.chat.sendChatMessage("Hello!", 'Mr Robot');
|
WA.chat.sendChatMessage("Hello!", 'Mr Robot');
|
||||||
})
|
});
|
||||||
|
|
||||||
WA.room.onLeaveZone('myZone', () => {
|
WA.room.onLeaveLayer('myLayer').subscribe(() => {
|
||||||
WA.chat.sendChatMessage("Goodbye!", 'Mr Robot');
|
WA.chat.sendChatMessage("Goodbye!", 'Mr Robot');
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Show / Hide a layer
|
### Show / Hide a layer
|
||||||
|
@ -64,3 +64,13 @@ For instance, if you want an iFrame to be able to go in fullscreen, you will use
|
|||||||
<img src="images/open_website_policy.jpg" class="figure-img img-fluid rounded" alt="" />
|
<img src="images/open_website_policy.jpg" class="figure-img img-fluid rounded" alt="" />
|
||||||
<figcaption class="figure-caption">The generated iFrame will have the allow attribute set to: <code><iframe allow="fullscreen"></code></figcaption>
|
<figcaption class="figure-caption">The generated iFrame will have the allow attribute set to: <code><iframe allow="fullscreen"></code></figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
### Open a Jitsi with a co-website
|
||||||
|
|
||||||
|
Cowebsites allow you to have several sites open at the same time.
|
||||||
|
|
||||||
|
If you want to open a Jitsi and another page it's easy!
|
||||||
|
|
||||||
|
You have just to [add a Jitsi to the map](meeting-rooms.md) and [add a co-website](opening-a-website.md#the-openwebsite-property) on the same layer.
|
||||||
|
|
||||||
|
It's done!
|
||||||
|
73
front/dist/index.tmpl.html
vendored
73
front/dist/index.tmpl.html
vendored
@ -37,6 +37,54 @@
|
|||||||
<div class="main-container" id="main-container">
|
<div class="main-container" id="main-container">
|
||||||
<!-- Create the editor container -->
|
<!-- Create the editor container -->
|
||||||
<div id="game" class="game">
|
<div id="game" class="game">
|
||||||
|
<div id="cowebsite-container">
|
||||||
|
<div id="cowebsite-container-main">
|
||||||
|
<div id="cowebsite-slot-1">
|
||||||
|
<div class="actions">
|
||||||
|
<button type="button" class="nes-btn is-primary expand">></button>
|
||||||
|
<button type="button" class="nes-btn is-error close">×</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cowebsite-container-sub">
|
||||||
|
<div id="cowebsite-slot-2">
|
||||||
|
<div class="overlay">
|
||||||
|
<div class="actions">
|
||||||
|
<button type="button" title="Close" class="nes-btn is-error close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="actions-move">
|
||||||
|
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
|
||||||
|
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">Ξ</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cowebsite-slot-3">
|
||||||
|
<div class="overlay">
|
||||||
|
<div class="actions">
|
||||||
|
<button type="button" title="Close" class="nes-btn is-error close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="actions-move">
|
||||||
|
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
|
||||||
|
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">Ξ</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cowebsite-slot-4">
|
||||||
|
<div class="overlay">
|
||||||
|
<div class="actions">
|
||||||
|
<button type="button" title="Close" class="nes-btn is-error close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="actions-move">
|
||||||
|
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
|
||||||
|
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">Ξ</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="svelte-overlay"></div>
|
<div id="svelte-overlay"></div>
|
||||||
<div id="game-overlay" class="game-overlay">
|
<div id="game-overlay" class="game-overlay">
|
||||||
<div id="main-section" class="main-section">
|
<div id="main-section" class="main-section">
|
||||||
@ -48,19 +96,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="cowebsite" class="cowebsite hidden">
|
<div id="cowebsite" class="cowebsite hidden">
|
||||||
<aside id="cowebsite-aside">
|
<aside id="cowebsite-aside" class="noselect">
|
||||||
<img src="/static/images/menu.svg" alt="hold to resize"/>
|
<div id="cowebsite-aside-buttons">
|
||||||
</aside>
|
<button class="top-right-btn nes-btn is-error" id="cowebsite-close" alt="close all co-websites">
|
||||||
<main id="cowebsite-main">
|
×
|
||||||
</main>
|
|
||||||
<button class="top-right-btn" id="cowebsite-fullscreen" alt="fullscreen mode">
|
|
||||||
<img id="cowebsite-fullscreen-open" src="resources/logos/fullscreen.svg"/>
|
|
||||||
<img id="cowebsite-fullscreen-close" style="display: none;" src="resources/logos/fullscreen-exit.svg"/>
|
|
||||||
</button>
|
</button>
|
||||||
<button class="top-right-btn" id="cowebsite-close" alt="close the iframe">
|
<button class="top-right-btn nes-btn is-primary" id="cowebsite-fullscreen" alt="fullscreen mode">
|
||||||
<img src="resources/logos/close.svg"/>
|
<img id="cowebsite-fullscreen-close" style="display: none;" src="resources/logos/fullscreen-exit.svg"/>
|
||||||
|
<img id="cowebsite-fullscreen-open" src="resources/logos/fullscreen.svg"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="cowebsite-aside-holder">
|
||||||
|
<img src="/static/images/menu.svg" alt="hold to resize"/>
|
||||||
|
</div>
|
||||||
|
<div id="cowebsite-sub-icons"></div>
|
||||||
|
</aside>
|
||||||
|
<main id="cowebsite-slot-0"></main>
|
||||||
|
</div>
|
||||||
|
<div id="cowebsite-buffer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="activeScreenSharing" class="active-screen-sharing active">
|
<div id="activeScreenSharing" class="active-screen-sharing active">
|
||||||
|
11
front/src/Api/Events/ChangeLayerEvent.ts
Normal file
11
front/src/Api/Events/ChangeLayerEvent.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isChangeLayerEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
name: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
/**
|
||||||
|
* A message sent from the game to the iFrame when a user enters or leaves a layer.
|
||||||
|
*/
|
||||||
|
export type ChangeLayerEvent = tg.GuardedType<typeof isChangeLayerEvent>;
|
12
front/src/Api/Events/CloseCoWebsiteEvent.ts
Normal file
12
front/src/Api/Events/CloseCoWebsiteEvent.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isCloseCoWebsite = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isOptional(tg.isString)
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
|
*/
|
||||||
|
export type CloseCoWebsiteEvent = tg.GuardedType<typeof isCloseCoWebsite>;
|
@ -6,6 +6,8 @@ export const isHasPlayerMovedEvent = new tg.IsInterface()
|
|||||||
moving: tg.isBoolean,
|
moving: tg.isBoolean,
|
||||||
x: tg.isNumber,
|
x: tg.isNumber,
|
||||||
y: tg.isNumber,
|
y: tg.isNumber,
|
||||||
|
oldX: tg.isOptional(tg.isNumber),
|
||||||
|
oldY: tg.isOptional(tg.isNumber),
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
@ -5,11 +5,10 @@ import type { ClosePopupEvent } from "./ClosePopupEvent";
|
|||||||
import type { EnterLeaveEvent } from "./EnterLeaveEvent";
|
import type { EnterLeaveEvent } from "./EnterLeaveEvent";
|
||||||
import type { GoToPageEvent } from "./GoToPageEvent";
|
import type { GoToPageEvent } from "./GoToPageEvent";
|
||||||
import type { LoadPageEvent } from "./LoadPageEvent";
|
import type { LoadPageEvent } from "./LoadPageEvent";
|
||||||
import type { OpenCoWebSiteEvent } from "./OpenCoWebSiteEvent";
|
import { isCoWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent";
|
||||||
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
||||||
import type { OpenTabEvent } from "./OpenTabEvent";
|
import type { OpenTabEvent } from "./OpenTabEvent";
|
||||||
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
||||||
import type { MapDataEvent } from "./MapDataEvent";
|
|
||||||
import type { LayerEvent } from "./LayerEvent";
|
import type { LayerEvent } from "./LayerEvent";
|
||||||
import type { SetPropertyEvent } from "./setPropertyEvent";
|
import type { SetPropertyEvent } from "./setPropertyEvent";
|
||||||
import type { LoadSoundEvent } from "./LoadSoundEvent";
|
import type { LoadSoundEvent } from "./LoadSoundEvent";
|
||||||
@ -27,12 +26,10 @@ import type { LoadTilesetEvent } from "./LoadTilesetEvent";
|
|||||||
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
|
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
|
||||||
import type {
|
import type {
|
||||||
MessageReferenceEvent,
|
MessageReferenceEvent,
|
||||||
removeActionMessage,
|
|
||||||
triggerActionMessage,
|
|
||||||
TriggerActionMessageEvent,
|
|
||||||
} from "./ui/TriggerActionMessageEvent";
|
} from "./ui/TriggerActionMessageEvent";
|
||||||
import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/TriggerActionMessageEvent";
|
import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/TriggerActionMessageEvent";
|
||||||
import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent";
|
import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent";
|
||||||
|
import type { ChangeLayerEvent } from "./ChangeLayerEvent";
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
data: T;
|
data: T;
|
||||||
@ -48,8 +45,6 @@ export type IframeEventMap = {
|
|||||||
closePopup: ClosePopupEvent;
|
closePopup: ClosePopupEvent;
|
||||||
openTab: OpenTabEvent;
|
openTab: OpenTabEvent;
|
||||||
goToPage: GoToPageEvent;
|
goToPage: GoToPageEvent;
|
||||||
openCoWebSite: OpenCoWebSiteEvent;
|
|
||||||
closeCoWebSite: null;
|
|
||||||
disablePlayerControls: null;
|
disablePlayerControls: null;
|
||||||
restorePlayerControls: null;
|
restorePlayerControls: null;
|
||||||
displayBubble: null;
|
displayBubble: null;
|
||||||
@ -81,6 +76,8 @@ export interface IframeResponseEventMap {
|
|||||||
userInputChat: UserInputChatEvent;
|
userInputChat: UserInputChatEvent;
|
||||||
enterEvent: EnterLeaveEvent;
|
enterEvent: EnterLeaveEvent;
|
||||||
leaveEvent: EnterLeaveEvent;
|
leaveEvent: EnterLeaveEvent;
|
||||||
|
enterLayerEvent: ChangeLayerEvent;
|
||||||
|
leaveLayerEvent: ChangeLayerEvent;
|
||||||
buttonClickedEvent: ButtonClickedEvent;
|
buttonClickedEvent: ButtonClickedEvent;
|
||||||
hasPlayerMoved: HasPlayerMovedEvent;
|
hasPlayerMoved: HasPlayerMovedEvent;
|
||||||
menuItemClicked: MenuItemClickedEvent;
|
menuItemClicked: MenuItemClickedEvent;
|
||||||
@ -118,6 +115,22 @@ export const iframeQueryMapTypeGuards = {
|
|||||||
query: isLoadTilesetEvent,
|
query: isLoadTilesetEvent,
|
||||||
answer: tg.isNumber,
|
answer: tg.isNumber,
|
||||||
},
|
},
|
||||||
|
openCoWebsite: {
|
||||||
|
query: isOpenCoWebsiteEvent,
|
||||||
|
answer: isCoWebsite
|
||||||
|
},
|
||||||
|
getCoWebsites: {
|
||||||
|
query: tg.isUndefined,
|
||||||
|
answer: tg.isArray(isCoWebsite)
|
||||||
|
},
|
||||||
|
closeCoWebsite: {
|
||||||
|
query: tg.isString,
|
||||||
|
answer: tg.isUndefined
|
||||||
|
},
|
||||||
|
closeCoWebsites: {
|
||||||
|
query: tg.isUndefined,
|
||||||
|
answer: tg.isUndefined
|
||||||
|
},
|
||||||
triggerActionMessage: {
|
triggerActionMessage: {
|
||||||
query: isTriggerActionMessageEvent,
|
query: isTriggerActionMessageEvent,
|
||||||
answer: tg.isUndefined,
|
answer: tg.isUndefined,
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import * as tg from "generic-type-guard";
|
|
||||||
|
|
||||||
export const isOpenCoWebsite = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
url: tg.isString,
|
|
||||||
allowApi: tg.isBoolean,
|
|
||||||
allowPolicy: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
|
||||||
*/
|
|
||||||
export type OpenCoWebSiteEvent = tg.GuardedType<typeof isOpenCoWebsite>;
|
|
22
front/src/Api/Events/OpenCoWebsiteEvent.ts
Normal file
22
front/src/Api/Events/OpenCoWebsiteEvent.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isOpenCoWebsiteEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
url: tg.isString,
|
||||||
|
allowApi: tg.isOptional(tg.isBoolean),
|
||||||
|
allowPolicy: tg.isOptional(tg.isString),
|
||||||
|
position: tg.isOptional(tg.isNumber)
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
export const isCoWebsite = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isString,
|
||||||
|
position: tg.isNumber,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
|
*/
|
||||||
|
export type OpenCoWebsiteEvent = tg.GuardedType<typeof isOpenCoWebsiteEvent>;
|
@ -1,6 +1,5 @@
|
|||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import type * as tg from "generic-type-guard";
|
import { isChatEvent } from "./Events/ChatEvent";
|
||||||
import { ChatEvent, isChatEvent } from "./Events/ChatEvent";
|
|
||||||
import { HtmlUtils } from "../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../WebRtc/HtmlUtils";
|
||||||
import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent";
|
import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent";
|
||||||
import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent";
|
import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent";
|
||||||
@ -8,18 +7,15 @@ import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent";
|
|||||||
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
|
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
|
||||||
import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent";
|
import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent";
|
||||||
import { scriptUtils } from "./ScriptUtils";
|
import { scriptUtils } from "./ScriptUtils";
|
||||||
import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent";
|
import { isGoToPageEvent } from "./Events/GoToPageEvent";
|
||||||
import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent";
|
import { isCloseCoWebsite, CloseCoWebsiteEvent } from "./Events/CloseCoWebsiteEvent";
|
||||||
import {
|
import {
|
||||||
IframeErrorAnswerEvent,
|
IframeErrorAnswerEvent,
|
||||||
IframeEvent,
|
|
||||||
IframeEventMap,
|
|
||||||
IframeQueryMap,
|
IframeQueryMap,
|
||||||
IframeResponseEvent,
|
IframeResponseEvent,
|
||||||
IframeResponseEventMap,
|
IframeResponseEventMap,
|
||||||
isIframeEventWrapper,
|
isIframeEventWrapper,
|
||||||
isIframeQueryWrapper,
|
isIframeQueryWrapper,
|
||||||
TypedMessageEvent,
|
|
||||||
} from "./Events/IframeEvent";
|
} from "./Events/IframeEvent";
|
||||||
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
||||||
import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent";
|
import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent";
|
||||||
@ -33,8 +29,8 @@ import { isMenuRegisterEvent, isUnregisterMenuEvent } from "./Events/ui/MenuRegi
|
|||||||
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
||||||
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
||||||
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
||||||
import { EmbeddedWebsite } from "./iframe/Room/EmbeddedWebsite";
|
|
||||||
import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore";
|
import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore";
|
||||||
|
import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent";
|
||||||
|
|
||||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||||
query: IframeQueryMap[T]["query"],
|
query: IframeQueryMap[T]["query"],
|
||||||
@ -53,10 +49,7 @@ class IframeListener {
|
|||||||
public readonly openTabStream = this._openTabStream.asObservable();
|
public readonly openTabStream = this._openTabStream.asObservable();
|
||||||
|
|
||||||
private readonly _loadPageStream: Subject<string> = new Subject();
|
private readonly _loadPageStream: Subject<string> = new Subject();
|
||||||
public readonly loadPageStream = this._loadPageStream.asObservable();
|
public readonly loadPageStream = this._loadPageStream.asObservable()
|
||||||
|
|
||||||
private readonly _openCoWebSiteStream: Subject<OpenCoWebSiteEvent> = new Subject();
|
|
||||||
public readonly openCoWebSiteStream = this._openCoWebSiteStream.asObservable();
|
|
||||||
|
|
||||||
private readonly _disablePlayerControlStream: Subject<void> = new Subject();
|
private readonly _disablePlayerControlStream: Subject<void> = new Subject();
|
||||||
public readonly disablePlayerControlStream = this._disablePlayerControlStream.asObservable();
|
public readonly disablePlayerControlStream = this._disablePlayerControlStream.asObservable();
|
||||||
@ -138,8 +131,6 @@ class IframeListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foundSrc = this.getBaseUrl(foundSrc, message.source);
|
|
||||||
|
|
||||||
if (isIframeQueryWrapper(payload)) {
|
if (isIframeQueryWrapper(payload)) {
|
||||||
const queryId = payload.id;
|
const queryId = payload.id;
|
||||||
const query = payload.query;
|
const query = payload.query;
|
||||||
@ -224,15 +215,6 @@ class IframeListener {
|
|||||||
this._stopSoundStream.next(payload.data);
|
this._stopSoundStream.next(payload.data);
|
||||||
} else if (payload.type === "loadSound" && isLoadSoundEvent(payload.data)) {
|
} else if (payload.type === "loadSound" && isLoadSoundEvent(payload.data)) {
|
||||||
this._loadSoundStream.next(payload.data);
|
this._loadSoundStream.next(payload.data);
|
||||||
} else if (payload.type === "openCoWebSite" && isOpenCoWebsite(payload.data)) {
|
|
||||||
scriptUtils.openCoWebsite(
|
|
||||||
payload.data.url,
|
|
||||||
foundSrc,
|
|
||||||
payload.data.allowApi,
|
|
||||||
payload.data.allowPolicy
|
|
||||||
);
|
|
||||||
} else if (payload.type === "closeCoWebSite") {
|
|
||||||
scriptUtils.closeCoWebSite();
|
|
||||||
} else if (payload.type === "disablePlayerControls") {
|
} else if (payload.type === "disablePlayerControls") {
|
||||||
this._disablePlayerControlStream.next();
|
this._disablePlayerControlStream.next();
|
||||||
} else if (payload.type === "restorePlayerControls") {
|
} else if (payload.type === "restorePlayerControls") {
|
||||||
@ -252,6 +234,9 @@ class IframeListener {
|
|||||||
this.iframeCloseCallbacks.get(iframe)?.push(() => {
|
this.iframeCloseCallbacks.get(iframe)?.push(() => {
|
||||||
handleMenuUnregisterEvent(dataName);
|
handleMenuUnregisterEvent(dataName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
foundSrc = this.getBaseUrl(foundSrc, message.source);
|
||||||
|
|
||||||
handleMenuRegistrationEvent(
|
handleMenuRegistrationEvent(
|
||||||
payload.data.name,
|
payload.data.name,
|
||||||
payload.data.iframe,
|
payload.data.iframe,
|
||||||
@ -354,6 +339,20 @@ class IframeListener {
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getBaseUrlFromSource(source: MessageEventSource): string {
|
||||||
|
let foundSrc: string | undefined;
|
||||||
|
let iframe: HTMLIFrameElement | undefined;
|
||||||
|
|
||||||
|
for (iframe of this.iframes) {
|
||||||
|
if (iframe.contentWindow === source) {
|
||||||
|
foundSrc = iframe.src;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getBaseUrl(foundSrc ?? "", source);
|
||||||
|
}
|
||||||
|
|
||||||
private static getIFrameId(scriptUrl: string): string {
|
private static getIFrameId(scriptUrl: string): string {
|
||||||
return "script" + btoa(scriptUrl);
|
return "script" + btoa(scriptUrl);
|
||||||
}
|
}
|
||||||
@ -397,6 +396,24 @@ class IframeListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendEnterLayerEvent(layerName: string) {
|
||||||
|
this.postMessage({
|
||||||
|
type: "enterLayerEvent",
|
||||||
|
data: {
|
||||||
|
name: layerName,
|
||||||
|
} as ChangeLayerEvent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendLeaveLayerEvent(layerName: string) {
|
||||||
|
this.postMessage({
|
||||||
|
type: "leaveLayerEvent",
|
||||||
|
data: {
|
||||||
|
name: layerName,
|
||||||
|
} as ChangeLayerEvent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
hasPlayerMoved(event: HasPlayerMovedEvent) {
|
hasPlayerMoved(event: HasPlayerMovedEvent) {
|
||||||
if (this.sendPlayerMove) {
|
if (this.sendPlayerMove) {
|
||||||
this.postMessage({
|
this.postMessage({
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { coWebsiteManager } from "../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager, CoWebsite } from "../WebRtc/CoWebsiteManager";
|
||||||
import { playersStore } from "../Stores/PlayersStore";
|
import { playersStore } from "../Stores/PlayersStore";
|
||||||
import { chatMessagesStore } from "../Stores/ChatStore";
|
import { chatMessagesStore } from "../Stores/ChatStore";
|
||||||
import type { ChatEvent } from "./Events/ChatEvent";
|
import type { ChatEvent } from "./Events/ChatEvent";
|
||||||
@ -12,14 +12,6 @@ class ScriptUtils {
|
|||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public openCoWebsite(url: string, base: string, api: boolean, policy: string) {
|
|
||||||
coWebsiteManager.loadCoWebsite(url, base, api, policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeCoWebSite() {
|
|
||||||
coWebsiteManager.closeCoWebsite();
|
|
||||||
}
|
|
||||||
|
|
||||||
public sendAnonymousChat(chatEvent: ChatEvent) {
|
public sendAnonymousChat(chatEvent: ChatEvent) {
|
||||||
const userId = playersStore.addFacticePlayer(chatEvent.author);
|
const userId = playersStore.addFacticePlayer(chatEvent.author);
|
||||||
chatMessagesStore.addExternalMessage(userId, chatEvent.message);
|
chatMessagesStore.addExternalMessage(userId, chatEvent.message);
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
import type { GoToPageEvent } from "../Events/GoToPageEvent";
|
import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution";
|
||||||
import type { OpenTabEvent } from "../Events/OpenTabEvent";
|
|
||||||
import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution";
|
export class CoWebsite {
|
||||||
import type { OpenCoWebSiteEvent } from "../Events/OpenCoWebSiteEvent";
|
constructor(private readonly id: string, public readonly position: number) {}
|
||||||
import type { LoadPageEvent } from "../Events/LoadPageEvent";
|
|
||||||
|
close() {
|
||||||
|
return queryWorkadventure({
|
||||||
|
type: "closeCoWebsite",
|
||||||
|
data: this.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class WorkadventureNavigationCommands extends IframeApiContribution<WorkadventureNavigationCommands> {
|
export class WorkadventureNavigationCommands extends IframeApiContribution<WorkadventureNavigationCommands> {
|
||||||
callbacks = [];
|
callbacks = [];
|
||||||
@ -34,21 +41,34 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = ""): void {
|
async openCoWebSite(url: string, allowApi?: boolean, allowPolicy?: string, position?: number): Promise<CoWebsite> {
|
||||||
sendToWorkadventure({
|
const result = await queryWorkadventure({
|
||||||
type: "openCoWebSite",
|
type: "openCoWebsite",
|
||||||
data: {
|
data: {
|
||||||
url,
|
url,
|
||||||
allowApi,
|
allowApi,
|
||||||
allowPolicy,
|
allowPolicy,
|
||||||
|
position,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
return new CoWebsite(result.id, result.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeCoWebSite(): void {
|
async getCoWebSites(): Promise<CoWebsite[]> {
|
||||||
sendToWorkadventure({
|
const result = await queryWorkadventure({
|
||||||
type: "closeCoWebSite",
|
type: "getCoWebsites",
|
||||||
data: null,
|
data: undefined
|
||||||
|
});
|
||||||
|
return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id, cowebsiteEvent.position));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use closeCoWebsites instead to close all co-websites
|
||||||
|
*/
|
||||||
|
closeCoWebSite() {
|
||||||
|
return queryWorkadventure({
|
||||||
|
type: "closeCoWebsites",
|
||||||
|
data: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
|
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
||||||
|
import { ChangeLayerEvent, isChangeLayerEvent } from "../Events/ChangeLayerEvent";
|
||||||
|
|
||||||
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
||||||
import { apiCallback } from "./registeredCallbacks";
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
@ -12,6 +13,9 @@ import website from "./website";
|
|||||||
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
|
|
||||||
|
const enterLayerStreams: Map<string, Subject<void>> = new Map<string, Subject<void>>();
|
||||||
|
const leaveLayerStreams: Map<string, Subject<void>> = new Map<string, Subject<void>>();
|
||||||
|
|
||||||
interface TileDescriptor {
|
interface TileDescriptor {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
@ -47,8 +51,25 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
|||||||
leaveStreams.get(payloadData.name)?.next();
|
leaveStreams.get(payloadData.name)?.next();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
apiCallback({
|
||||||
|
type: "enterLayerEvent",
|
||||||
|
typeChecker: isChangeLayerEvent,
|
||||||
|
callback: (payloadData: ChangeLayerEvent) => {
|
||||||
|
enterLayerStreams.get(payloadData.name)?.next();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
apiCallback({
|
||||||
|
type: "leaveLayerEvent",
|
||||||
|
typeChecker: isChangeLayerEvent,
|
||||||
|
callback: (payloadData) => {
|
||||||
|
leaveLayerStreams.get(payloadData.name)?.next();
|
||||||
|
},
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use onEnterLayer instead
|
||||||
|
*/
|
||||||
onEnterZone(name: string, callback: () => void): void {
|
onEnterZone(name: string, callback: () => void): void {
|
||||||
let subject = enterStreams.get(name);
|
let subject = enterStreams.get(name);
|
||||||
if (subject === undefined) {
|
if (subject === undefined) {
|
||||||
@ -57,6 +78,10 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
|||||||
}
|
}
|
||||||
subject.subscribe(callback);
|
subject.subscribe(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use onLeaveLayer instead
|
||||||
|
*/
|
||||||
onLeaveZone(name: string, callback: () => void): void {
|
onLeaveZone(name: string, callback: () => void): void {
|
||||||
let subject = leaveStreams.get(name);
|
let subject = leaveStreams.get(name);
|
||||||
if (subject === undefined) {
|
if (subject === undefined) {
|
||||||
@ -65,12 +90,35 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
|||||||
}
|
}
|
||||||
subject.subscribe(callback);
|
subject.subscribe(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEnterLayer(layerName: string): Subject<void> {
|
||||||
|
let subject = enterLayerStreams.get(layerName);
|
||||||
|
if (subject === undefined) {
|
||||||
|
subject = new Subject<void>();
|
||||||
|
enterLayerStreams.set(layerName, subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeaveLayer(layerName: string): Subject<void> {
|
||||||
|
let subject = leaveLayerStreams.get(layerName);
|
||||||
|
if (subject === undefined) {
|
||||||
|
subject = new Subject<void>();
|
||||||
|
leaveLayerStreams.set(layerName, subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
|
||||||
showLayer(layerName: string): void {
|
showLayer(layerName: string): void {
|
||||||
sendToWorkadventure({ type: "showLayer", data: { name: layerName } });
|
sendToWorkadventure({ type: "showLayer", data: { name: layerName } });
|
||||||
}
|
}
|
||||||
|
|
||||||
hideLayer(layerName: string): void {
|
hideLayer(layerName: string): void {
|
||||||
sendToWorkadventure({ type: "hideLayer", data: { name: layerName } });
|
sendToWorkadventure({ type: "hideLayer", data: { name: layerName } });
|
||||||
}
|
}
|
||||||
|
|
||||||
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
|
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
|
||||||
sendToWorkadventure({
|
sendToWorkadventure({
|
||||||
type: "setProperty",
|
type: "setProperty",
|
||||||
@ -81,10 +129,12 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTiledMap(): Promise<ITiledMap> {
|
async getTiledMap(): Promise<ITiledMap> {
|
||||||
const event = await queryWorkadventure({ type: "getMapData", data: undefined });
|
const event = await queryWorkadventure({ type: "getMapData", data: undefined });
|
||||||
return event.data as ITiledMap;
|
return event.data as ITiledMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTiles(tiles: TileDescriptor[]) {
|
setTiles(tiles: TileDescriptor[]) {
|
||||||
sendToWorkadventure({
|
sendToWorkadventure({
|
||||||
type: "setTiles",
|
type: "setTiles",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
||||||
import {chatSubMenuVisbilityStore} from "../../Stores/ChatStore";
|
import {chatSubMenuVisibilityStore} from "../../Stores/ChatStore";
|
||||||
import {onDestroy, onMount} from "svelte";
|
import {onDestroy, onMount} from "svelte";
|
||||||
import type {Unsubscriber} from "svelte/store";
|
import type {Unsubscriber} from "svelte/store";
|
||||||
import ChatSubMenu from "./ChatSubMenu.svelte";
|
import ChatSubMenu from "./ChatSubMenu.svelte";
|
||||||
@ -12,11 +12,11 @@
|
|||||||
let chatSubMenuVisivilytUnsubcribe: Unsubscriber;
|
let chatSubMenuVisivilytUnsubcribe: Unsubscriber;
|
||||||
|
|
||||||
function openSubMenu() {
|
function openSubMenu() {
|
||||||
chatSubMenuVisbilityStore.openSubMenu(player.name, line);
|
chatSubMenuVisibilityStore.openSubMenu(player.name, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
chatSubMenuVisivilytUnsubcribe = chatSubMenuVisbilityStore.subscribe((newValue) => {
|
chatSubMenuVisivilytUnsubcribe = chatSubMenuVisibilityStore.subscribe((newValue) => {
|
||||||
isSubMenuOpen = (newValue === player.name + line);
|
isSubMenuOpen = (newValue === player.name + line);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -18,13 +18,18 @@
|
|||||||
'--font': 'Press Start 2P'
|
'--font': 'Press Start 2P'
|
||||||
},
|
},
|
||||||
emojisPerRow: isMobile() ? 6 : 8,
|
emojisPerRow: isMobile() ? 6 : 8,
|
||||||
autoFocusSearch: false
|
autoFocusSearch: false,
|
||||||
|
style: 'twemoji',
|
||||||
});
|
});
|
||||||
//the timeout is here to prevent the menu from flashing
|
//the timeout is here to prevent the menu from flashing
|
||||||
setTimeout(() => picker.showPicker(emojiContainer), 100);
|
setTimeout(() => picker.showPicker(emojiContainer), 100);
|
||||||
|
|
||||||
picker.on("emoji", (selection) => {
|
picker.on("emoji", (selection) => {
|
||||||
emoteStore.set(selection.emoji);
|
emoteStore.set({
|
||||||
|
unicode: selection.emoji,
|
||||||
|
url: selection.url,
|
||||||
|
name: selection.name
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
picker.on("hidden", () => {
|
picker.on("hidden", () => {
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
await navigator.share(shareData);
|
await navigator.share(shareData);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error: ' + err);
|
console.error('Error: ' + err);
|
||||||
|
copyLink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -63,6 +64,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="is-mobile">
|
<section class="is-mobile">
|
||||||
<h3>Share the link of the room !</h3>
|
<h3>Share the link of the room !</h3>
|
||||||
|
<input type="hidden" readonly bind:this={HTMLShareLink} value={location.toString()}>
|
||||||
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
||||||
</section>
|
</section>
|
||||||
<h2>Information on the map</h2>
|
<h2>Information on the map</h2>
|
||||||
|
@ -1,10 +1,60 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
function goToGettingStarted() {
|
||||||
|
const sparkHost = "https://workadventu.re/getting-started";
|
||||||
|
window.open(sparkHost, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToBuildingMap() {
|
||||||
|
const sparkHost = "https://workadventu.re/map-building/";
|
||||||
|
window.open(sparkHost, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
import {contactPageStore} from "../../Stores/MenuStore";
|
import {contactPageStore} from "../../Stores/MenuStore";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<iframe title="contact" src="{$contactPageStore}" allow="clipboard-read; clipboard-write self {$contactPageStore}" allowfullscreen></iframe>
|
<div class="create-map-main">
|
||||||
|
<section class="container-overflow">
|
||||||
|
<section>
|
||||||
|
<h3>Getting started</h3>
|
||||||
|
<p>
|
||||||
|
WorkAdventure allows you to create an online space to communicate spontaneously with others.
|
||||||
|
And it all starts with creating your own space. Choose from a large selection of prefabricated maps by our team.
|
||||||
|
</p>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={goToGettingStarted}>Getting started</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h3>Create your map</h3>
|
||||||
|
<p>You can also create your own custom map by following the step of the documentation.</p>
|
||||||
|
<button type="button" class="nes-btn" on:click={goToBuildingMap}>Create your map</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<iframe title="contact"
|
||||||
|
src="{$contactPageStore}"
|
||||||
|
allow="clipboard-read; clipboard-write self {$contactPageStore}"
|
||||||
|
allowfullscreen></iframe>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
div.create-map-main {
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
border: none;
|
border: none;
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
|
|
||||||
function goToGettingStarted() {
|
|
||||||
const sparkHost = "https://workadventu.re/getting-started";
|
|
||||||
window.open(sparkHost, "_blank");
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToBuildingMap() {
|
|
||||||
const sparkHost = "https://workadventu.re/map-building/";
|
|
||||||
window.open(sparkHost, "_blank");
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="create-map-main">
|
|
||||||
<section class="container-overflow">
|
|
||||||
<section>
|
|
||||||
<h3>Getting started</h3>
|
|
||||||
<p>
|
|
||||||
WorkAdventure allows you to create an online space to communicate spontaneously with others.
|
|
||||||
And it all starts with creating your own space. Choose from a large selection of prefabricated maps by our team.
|
|
||||||
</p>
|
|
||||||
<button type="button" class="nes-btn is-primary" on:click={goToGettingStarted}>Getting started</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3>Create your map</h3>
|
|
||||||
<p>You can also create your own custom map by following the step of the documentation.</p>
|
|
||||||
<button type="button" class="nes-btn" on:click={goToBuildingMap}>Create your map</button>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
div.create-map-main {
|
|
||||||
height: calc(100% - 56px);
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin-bottom: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.container-overflow {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
75
front/src/Components/Menu/GuestSubMenu.svelte
Normal file
75
front/src/Components/Menu/GuestSubMenu.svelte
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let HTMLShareLink: HTMLInputElement;
|
||||||
|
|
||||||
|
function copyLink() {
|
||||||
|
HTMLShareLink.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shareLink() {
|
||||||
|
const shareData = {url: location.toString()};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.share(shareData);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error: ' + err);
|
||||||
|
copyLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="guest-main">
|
||||||
|
<section class="container-overflow">
|
||||||
|
<section class="share-url not-mobile">
|
||||||
|
<h3>Share the link of the room !</h3>
|
||||||
|
<input type="text" readonly bind:this={HTMLShareLink} value={location.toString()}>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
|
||||||
|
</section>
|
||||||
|
<section class="is-mobile">
|
||||||
|
<h3>Share the link of the room !</h3>
|
||||||
|
<input type="hidden" readonly bind:this={HTMLShareLink} value={location.toString()}>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.guest-main {
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.is-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 900px), only screen and (max-height: 600px) {
|
||||||
|
div.guest-main {
|
||||||
|
section.share-url.not-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.is-mobile {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: calc(100% - 120px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,11 +2,11 @@
|
|||||||
import {fly} from "svelte/transition";
|
import {fly} from "svelte/transition";
|
||||||
import SettingsSubMenu from "./SettingsSubMenu.svelte";
|
import SettingsSubMenu from "./SettingsSubMenu.svelte";
|
||||||
import ProfileSubMenu from "./ProfileSubMenu.svelte";
|
import ProfileSubMenu from "./ProfileSubMenu.svelte";
|
||||||
import CreateMapSubMenu from "./CreateMapSubMenu.svelte";
|
|
||||||
import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte";
|
import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte";
|
||||||
import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte";
|
import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte";
|
||||||
import ContactSubMenu from "./ContactSubMenu.svelte";
|
import ContactSubMenu from "./ContactSubMenu.svelte";
|
||||||
import CustomSubMenu from "./CustomSubMenu.svelte"
|
import CustomSubMenu from "./CustomSubMenu.svelte"
|
||||||
|
import GuestSubMenu from "./GuestSubMenu.svelte";
|
||||||
import {
|
import {
|
||||||
checkSubMenuToShow,
|
checkSubMenuToShow,
|
||||||
customMenuIframe,
|
customMenuIframe,
|
||||||
@ -19,21 +19,21 @@
|
|||||||
import type {Unsubscriber} from "svelte/store";
|
import type {Unsubscriber} from "svelte/store";
|
||||||
import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem";
|
import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem";
|
||||||
|
|
||||||
let activeSubMenu: string = SubMenusInterface.settings;
|
let activeSubMenu: string = SubMenusInterface.profile;
|
||||||
let activeComponent: typeof SettingsSubMenu | typeof CustomSubMenu = SettingsSubMenu;
|
let activeComponent: typeof ProfileSubMenu | typeof CustomSubMenu = ProfileSubMenu;
|
||||||
let props: { url: string, allowApi: boolean };
|
let props: { url: string, allowApi: boolean };
|
||||||
let unsubscriberSubMenuStore: Unsubscriber;
|
let unsubscriberSubMenuStore: Unsubscriber;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
unsubscriberSubMenuStore = subMenusStore.subscribe(() => {
|
unsubscriberSubMenuStore = subMenusStore.subscribe(() => {
|
||||||
if(!get(subMenusStore).includes(activeSubMenu)) {
|
if(!get(subMenusStore).includes(activeSubMenu)) {
|
||||||
switchMenu(SubMenusInterface.settings);
|
switchMenu(SubMenusInterface.profile);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
checkSubMenuToShow();
|
checkSubMenuToShow();
|
||||||
|
|
||||||
switchMenu(SubMenusInterface.settings);
|
switchMenu(SubMenusInterface.profile);
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@ -52,8 +52,8 @@
|
|||||||
case SubMenusInterface.profile:
|
case SubMenusInterface.profile:
|
||||||
activeComponent = ProfileSubMenu;
|
activeComponent = ProfileSubMenu;
|
||||||
break;
|
break;
|
||||||
case SubMenusInterface.createMap:
|
case SubMenusInterface.invite:
|
||||||
activeComponent = CreateMapSubMenu;
|
activeComponent = GuestSubMenu;
|
||||||
break;
|
break;
|
||||||
case SubMenusInterface.aboutRoom:
|
case SubMenusInterface.aboutRoom:
|
||||||
activeComponent = AboutRoomSubMenu;
|
activeComponent = AboutRoomSubMenu;
|
||||||
@ -124,6 +124,7 @@
|
|||||||
top: 10%;
|
top: 10%;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 80;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
|
@ -11,15 +11,9 @@
|
|||||||
function showChat(){
|
function showChat(){
|
||||||
chatVisibilityStore.set(true);
|
chatVisibilityStore.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeyDown(e: KeyboardEvent) {
|
|
||||||
if (e.key === "Tab") {
|
|
||||||
showMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown}/>
|
<svelte:window/>
|
||||||
|
|
||||||
<main class="menuIcon">
|
<main class="menuIcon">
|
||||||
<img src={logoWA} alt="open menu" class="nes-pointer" on:click|preventDefault={showMenu}>
|
<img src={logoWA} alt="open menu" class="nes-pointer" on:click|preventDefault={showMenu}>
|
||||||
@ -29,6 +23,8 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.menuIcon {
|
.menuIcon {
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
|
z-index: 90;
|
||||||
|
position: relative;
|
||||||
margin: 25px;
|
margin: 25px;
|
||||||
img {
|
img {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
import {EnableCameraScene, EnableCameraSceneName} from "../../Phaser/Login/EnableCameraScene";
|
import {EnableCameraScene, EnableCameraSceneName} from "../../Phaser/Login/EnableCameraScene";
|
||||||
import {enableCameraSceneVisibilityStore} from "../../Stores/MediaStore";
|
import {enableCameraSceneVisibilityStore} from "../../Stores/MediaStore";
|
||||||
|
import btnProfileSubMenuCamera from "../images/btn-menu-profile-camera.svg";
|
||||||
|
import btnProfileSubMenuIdentity from "../images/btn-menu-profile-identity.svg";
|
||||||
|
import btnProfileSubMenuCompanion from "../images/btn-menu-profile-companion.svg";
|
||||||
|
import btnProfileSubMenuWoka from "../images/btn-menu-profile-woka.svg";
|
||||||
|
|
||||||
|
|
||||||
function disableMenuStores(){
|
function disableMenuStores(){
|
||||||
@ -55,6 +59,28 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="customize-main">
|
<div class="customize-main">
|
||||||
|
<div class="submenu">
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>
|
||||||
|
<img src={btnProfileSubMenuIdentity} alt="Edit your name">
|
||||||
|
<span class="btn-hover">Edit your name</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditSkinScene}>
|
||||||
|
<img src={btnProfileSubMenuWoka} alt="Edit your WOKA">
|
||||||
|
<span class="btn-hover">Edit your WOKA</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>
|
||||||
|
<img src={btnProfileSubMenuCompanion} alt="Edit your companion">
|
||||||
|
<span class="btn-hover">Edit your companion</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEnableCameraScene}>
|
||||||
|
<img src={btnProfileSubMenuCamera} alt="Edit your camera">
|
||||||
|
<span class="btn-hover">Edit your camera</span>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
{#if $userIsConnected}
|
{#if $userIsConnected}
|
||||||
<section>
|
<section>
|
||||||
{#if PROFILE_URL != undefined}
|
{#if PROFILE_URL != undefined}
|
||||||
@ -69,18 +95,48 @@
|
|||||||
<a type="button" class="nes-btn" href="/login">Sign in</a>
|
<a type="button" class="nes-btn" href="/login">Sign in</a>
|
||||||
</section>
|
</section>
|
||||||
{/if}
|
{/if}
|
||||||
<section>
|
</div>
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>Edit Name</button>
|
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditSkinScene}>Edit Skin</button>
|
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>Edit Companion</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEnableCameraScene}>Setup camera</button>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.customize-main{
|
div.customize-main{
|
||||||
|
width: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
div.submenu{
|
||||||
|
height: 100%;
|
||||||
|
width: 50px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
transition: all .5s ease;
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
max-height: 44px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.btn-hover{
|
||||||
|
display: none;
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
span.btn-hover {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content {
|
||||||
|
width: 100%;
|
||||||
section {
|
section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -100,9 +156,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
div.customize-main section button {
|
div.customize-main.content section button {
|
||||||
width: 130px;
|
width: 130px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
front/src/Components/images/btn-menu-profile-camera.svg
Normal file
1
front/src/Components/images/btn-menu-profile-camera.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><g id="btn_setup_camera" data-name="btn setup camera"><circle cx="24.71" cy="13.11" r="1.46"/><path d="M8.65,23.34H40.78V2.89H31.16L28.24,0h-7L18.27,2.89H8.65ZM32,8.73h2.92v2.92H32Zm-7.31,0a4.39,4.39,0,1,1-4.38,4.38A4.39,4.39,0,0,1,24.71,8.73Z"/><path d="M2.81,44H5.73v5.84h8.76V44h5.84V46.9h2.92V44h5.84V46.9H32V44h5.84V46.9h2.92V44h5.84V41.06h-33l-3.52-3.53L6.58,41.06H2.81Z"/><path d="M2.81,32.3H8.65v2.92h2.92V32.3h5.84v2.92h2.92V32.3h5.84v2.92h2.92V32.3h5.85v5.84H43.7V32.3h2.92V29.37H42.84l-3.52-3.52-3.53,3.52h-33Z"/></g></svg>
|
After Width: | Height: | Size: 629 B |
@ -0,0 +1 @@
|
|||||||
|
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50"><g id="btn_setup_companion" data-name="btn setup companion"><g id="iNhyGC.tif"><image id="Layer_0" data-name="Layer 0" width="15" height="30" transform="translate(13.21 0.25) scale(1.65)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAfCAYAAADupU20AAAACXBIWXMAAAbEAAAGxAGo1xHEAAAB20lEQVQ4T51UO04DMRScRYmEhGWlApRsBcUap4VUXICSjpqaY3ACSgpOgERQKnpoNjXRhjrkANZGikRhiuDH8w8BI7l5n/H4fVxYaxFC66FnnM1eiyjoC53QoPXQjkYnkS1HUnAFWg+tUhXatsVi8Q4AUKqClBJ1PU0q8RTMZq+Fk++CU4o4oiekbjHGhCbCVtbzS/xIwGuSQ/GbNgL5VkYEWg9tWQ4ghCCb60qKJGqjS5ZSkt0YkyWhGjjZYTIASClJUfg8r4hKVWiaOYwx0WmaOZSqEKIDfEu/PDvGHYCmmUeBSlW4PDvGTdt6o00Krq8uAIDkl+UASlUoy4Fnd3EOHXc7AOzu7QN4o/l3ie79G/+G3Kkojo50svI5hB3pAOnK5xDG0TLV9ZSMqe3jft4NKuLt/Qu6qzXG40m0fcYYjMcTdFdr3N6/eL4tYDOqhwc9AMDT4wNScPbDg563XFTEfr8P+3C6MZ4/RwTct1wuqYiFtTa5A3U9RXe1xsfONtUktRNUxMXi3Rua0egExhgi5MkcRFCWA3I6IgD0Xu7jJEQghKDE8BaX6OI4vE9VCEE38r3nqx7CW2c+9yFy00oE/x1lInDTlyPi3eCgP5F/VanPM+dPfut/wScEgxZt/KHdLgAAAABJRU5ErkJggg=="/></g></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1 @@
|
|||||||
|
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><g id="btn_setup_identity" data-name="btn setup identity"><path d="M31.94,6l-4.35,6.39a3.63,3.63,0,1,1-3.07-1.7,3.71,3.71,0,0,1,.67.06l4-5.89a16,16,0,0,0-9.37,0L17,.76a1.45,1.45,0,0,0-2.4,1.64L17.09,6A16,16,0,0,0,8.56,20.15V33.69a16,16,0,0,0,31.91,0V20.15A16,16,0,0,0,31.94,6Zm-.65,32.49H17.75a1.45,1.45,0,1,1,0-2.9H31.29a1.45,1.45,0,0,1,0,2.9Zm0-5.8H17.75a1.45,1.45,0,1,1,0-2.9H31.29a1.45,1.45,0,1,1,0,2.9Zm0-5.8H17.75a1.45,1.45,0,1,1,0-2.9H31.29a1.45,1.45,0,1,1,0,2.9Z"/><path d="M34.42,2.4A1.45,1.45,0,1,0,32,.76L29.21,4.89A16.38,16.38,0,0,1,31.94,6Z"/></g></svg>
|
After Width: | Height: | Size: 661 B |
1
front/src/Components/images/btn-menu-profile-woka.svg
Normal file
1
front/src/Components/images/btn-menu-profile-woka.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50"><g id="btn_setup_woka" data-name="btn setup woka"><g id="NP8bMB.tif"><image id="Layer_0" data-name="Layer 0" width="23" height="29" transform="translate(4.61 0.1) scale(1.71)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAdCAYAAABBsffGAAAACXBIWXMAAAZ1AAAGdQGEn07tAAACCUlEQVRIS61WS4rDMAx9abLoxuqi4MIYSk+Q+59iBnqCUlBhDNnYmy4aMosgj+3YyRTmQReVpSdZP6eZpglrMOajqsD8aGpnANDUyIW0bTsAwPF4DGfDMAAAxvEFoO6kSG7Mx9S2XSBUSi10vPcAZkfj+Co6WJDHxCXSHN77qoOuZJATE9FCxzkH4PdW1n4vdHbxH4k6Rom4JG/bblH8hBxIo64RC+RcKZUUXLAgF2wRC9b0AvlaP7+DmGcnAq1PdYs3oPUpOKim5T+wA+YJk1aS6XsXYmftd+j3EPnWnvgrYp4kLcyPZhxf8N6HIdmCcw7e+79PaDxta60mxKXpBLLdEk/oOL6wtmPinRLbxNEHciHu+34zohhan6CUAhHher0mDpK0xMQSrTEGAJIaSKqYGUqpsH77vsfX12fQ62aCOeo8YmMMDodDUHbOgYgSGTMnN5QFxvxoQrdcLhcA633+fD6rZ2InPADQSdREBGYOT1fuxFqL/X4Pa22QMXPy5HnvYYwJ0e+AOVc5oXSJcw7OOWitQUTQWgdZvmrFXvhCWpxzSaWHYQiFk6GSnxSQiAKhDGBc+I750cgWK60AIsLtdlukSbooRs5V/bQ4n8+TpCbveeltGaT7/V7cS9WVK4WVFADpzUQueiWs7nOlFIwxi/GvyXOskm+9o1vn1ZwD6XsYp6Qmz/ED0qpw9h1b2uQAAAAASUVORK5CYII="/></g></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -41,7 +41,6 @@ class ConnectionManager {
|
|||||||
const nonce = localUserStore.generateNonce();
|
const nonce = localUserStore.generateNonce();
|
||||||
localUserStore.setAuthToken(null);
|
localUserStore.setAuthToken(null);
|
||||||
|
|
||||||
//TODO fix me to redirect this URL by pusher
|
|
||||||
if (!this._currentRoom || !this._currentRoom.iframeAuthentication) {
|
if (!this._currentRoom || !this._currentRoom.iframeAuthentication) {
|
||||||
loginSceneVisibleIframeStore.set(false);
|
loginSceneVisibleIframeStore.set(false);
|
||||||
return null;
|
return null;
|
||||||
@ -79,6 +78,16 @@ class ConnectionManager {
|
|||||||
const connexionType = urlManager.getGameConnexionType();
|
const connexionType = urlManager.getGameConnexionType();
|
||||||
this.connexionType = connexionType;
|
this.connexionType = connexionType;
|
||||||
this._currentRoom = null;
|
this._currentRoom = null;
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const token = urlParams.get("token");
|
||||||
|
if (token) {
|
||||||
|
this.authToken = token;
|
||||||
|
localUserStore.setAuthToken(token);
|
||||||
|
//token was saved, clear url
|
||||||
|
urlParams.delete("token");
|
||||||
|
}
|
||||||
|
|
||||||
if (connexionType === GameConnexionTypes.login) {
|
if (connexionType === GameConnexionTypes.login) {
|
||||||
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
||||||
if (this.loadOpenIDScreen() !== null) {
|
if (this.loadOpenIDScreen() !== null) {
|
||||||
@ -87,6 +96,8 @@ class ConnectionManager {
|
|||||||
urlManager.pushRoomIdToUrl(this._currentRoom);
|
urlManager.pushRoomIdToUrl(this._currentRoom);
|
||||||
} else if (connexionType === GameConnexionTypes.jwt) {
|
} else if (connexionType === GameConnexionTypes.jwt) {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
const code = urlParams.get("code");
|
const code = urlParams.get("code");
|
||||||
const state = urlParams.get("state");
|
const state = urlParams.get("state");
|
||||||
if (!state || !localUserStore.verifyState(state)) {
|
if (!state || !localUserStore.verifyState(state)) {
|
||||||
@ -96,9 +107,11 @@ class ConnectionManager {
|
|||||||
throw "No Auth code provided";
|
throw "No Auth code provided";
|
||||||
}
|
}
|
||||||
localUserStore.setCode(code);
|
localUserStore.setCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
||||||
try {
|
try {
|
||||||
await this.checkAuthUserConnexion(this._currentRoom.key);
|
await this.checkAuthUserConnexion();
|
||||||
analyticsClient.loggedWithSso();
|
analyticsClient.loggedWithSso();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -172,9 +185,12 @@ class ConnectionManager {
|
|||||||
await this.anonymousLogin();
|
await this.anonymousLogin();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
await this.checkAuthUserConnexion(this._currentRoom.key);
|
await this.checkAuthUserConnexion();
|
||||||
|
analyticsClient.loggedWithSso();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
this.loadOpenIDScreen();
|
||||||
|
return Promise.reject(new Error("You will be redirect on login page"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
||||||
@ -202,6 +218,8 @@ class ConnectionManager {
|
|||||||
analyticsClient.identifyUser(this.localUser.uuid, this.localUser.email);
|
analyticsClient.identifyUser(this.localUser.uuid, this.localUser.email);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//clean history with new URL
|
||||||
|
window.history.pushState({}, document.title, window.location.pathname);
|
||||||
this.serviceWorker = new _ServiceWorker();
|
this.serviceWorker = new _ServiceWorker();
|
||||||
return Promise.resolve(this._currentRoom);
|
return Promise.resolve(this._currentRoom);
|
||||||
}
|
}
|
||||||
@ -278,22 +296,25 @@ class ConnectionManager {
|
|||||||
return this.connexionType;
|
return this.connexionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkAuthUserConnexion(playUri: string) {
|
async checkAuthUserConnexion() {
|
||||||
//set connected store for menu at false
|
//set connected store for menu at false
|
||||||
userIsConnected.set(false);
|
userIsConnected.set(false);
|
||||||
|
|
||||||
|
const token = localUserStore.getAuthToken();
|
||||||
const state = localUserStore.getState();
|
const state = localUserStore.getState();
|
||||||
const code = localUserStore.getCode();
|
const code = localUserStore.getCode();
|
||||||
|
const nonce = localUserStore.getNonce();
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
if (!state || !localUserStore.verifyState(state)) {
|
if (!state || !localUserStore.verifyState(state)) {
|
||||||
throw "Could not validate state!";
|
throw "Could not validate state!";
|
||||||
}
|
}
|
||||||
if (!code) {
|
if (!code) {
|
||||||
throw "No Auth code provided";
|
throw "No Auth code provided";
|
||||||
}
|
}
|
||||||
const nonce = localUserStore.getNonce();
|
}
|
||||||
const token = localUserStore.getAuthToken();
|
|
||||||
const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, {
|
const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, {
|
||||||
params: { code, nonce, token, playUri },
|
params: { code, nonce, token },
|
||||||
}).then((res) => res.data);
|
}).then((res) => res.data);
|
||||||
localUserStore.setAuthToken(authToken);
|
localUserStore.setAuthToken(authToken);
|
||||||
this.localUser = new LocalUser(userUuid, textures, email);
|
this.localUser = new LocalUser(userUuid, textures, email);
|
||||||
|
@ -165,8 +165,15 @@ class LocalUserStore {
|
|||||||
|
|
||||||
verifyState(value: string): boolean {
|
verifyState(value: string): boolean {
|
||||||
const oldValue = localStorage.getItem(state);
|
const oldValue = localStorage.getItem(state);
|
||||||
|
if (!oldValue) {
|
||||||
|
localStorage.setItem(state, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return oldValue === value;
|
return oldValue === value;
|
||||||
}
|
}
|
||||||
|
setState(value: string) {
|
||||||
|
localStorage.setItem(state, value);
|
||||||
|
}
|
||||||
getState(): string | null {
|
getState(): string | null {
|
||||||
return localStorage.getItem(state);
|
return localStorage.getItem(state);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import { CONTACT_URL, PUSHER_URL } from "../Enum/EnvironmentVariable";
|
import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS, OPID_LOGIN_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
||||||
import type { CharacterTexture } from "./LocalUser";
|
import type { CharacterTexture } from "./LocalUser";
|
||||||
import { localUserStore } from "./LocalUserStore";
|
import { localUserStore } from "./LocalUserStore";
|
||||||
|
|
||||||
@ -14,8 +14,8 @@ export interface RoomRedirect {
|
|||||||
export class Room {
|
export class Room {
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
public readonly isPublic: boolean;
|
public readonly isPublic: boolean;
|
||||||
private _authenticationMandatory: boolean = false;
|
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS as boolean;
|
||||||
private _iframeAuthentication?: string;
|
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
|
||||||
private _mapUrl: string | undefined;
|
private _mapUrl: string | undefined;
|
||||||
private _textures: CharacterTexture[] | undefined;
|
private _textures: CharacterTexture[] | undefined;
|
||||||
private instance: string | undefined;
|
private instance: string | undefined;
|
||||||
@ -106,8 +106,8 @@ export class Room {
|
|||||||
this._mapUrl = data.mapUrl;
|
this._mapUrl = data.mapUrl;
|
||||||
this._textures = data.textures;
|
this._textures = data.textures;
|
||||||
this._group = data.group;
|
this._group = data.group;
|
||||||
this._authenticationMandatory = data.authenticationMandatory || false;
|
this._authenticationMandatory = data.authenticationMandatory || (DISABLE_ANONYMOUS as boolean);
|
||||||
this._iframeAuthentication = data.iframeAuthentication;
|
this._iframeAuthentication = data.iframeAuthentication || OPID_LOGIN_SCREEN_PROVIDER;
|
||||||
this._contactPage = data.contactPage || CONTACT_URL;
|
this._contactPage = data.contactPage || CONTACT_URL;
|
||||||
return new MapDetail(data.mapUrl, data.textures);
|
return new MapDetail(data.mapUrl, data.textures);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ const START_ROOM_URL: string =
|
|||||||
const PUSHER_URL = process.env.PUSHER_URL || "//pusher.workadventure.localhost";
|
const PUSHER_URL = process.env.PUSHER_URL || "//pusher.workadventure.localhost";
|
||||||
export const ADMIN_URL = process.env.ADMIN_URL || "//workadventu.re";
|
export const ADMIN_URL = process.env.ADMIN_URL || "//workadventu.re";
|
||||||
const UPLOADER_URL = process.env.UPLOADER_URL || "//uploader.workadventure.localhost";
|
const UPLOADER_URL = process.env.UPLOADER_URL || "//uploader.workadventure.localhost";
|
||||||
|
const ICON_URL = process.env.ICON_URL || "//icon.workadventure.localhost";
|
||||||
const STUN_SERVER: string = process.env.STUN_SERVER || "stun:stun.l.google.com:19302";
|
const STUN_SERVER: string = process.env.STUN_SERVER || "stun:stun.l.google.com:19302";
|
||||||
const TURN_SERVER: string = process.env.TURN_SERVER || "";
|
const TURN_SERVER: string = process.env.TURN_SERVER || "";
|
||||||
const SKIP_RENDER_OPTIMIZATIONS: boolean = process.env.SKIP_RENDER_OPTIMIZATIONS == "true";
|
const SKIP_RENDER_OPTIMIZATIONS: boolean = process.env.SKIP_RENDER_OPTIMIZATIONS == "true";
|
||||||
@ -22,6 +23,8 @@ export const CONTACT_URL = process.env.CONTACT_URL || undefined;
|
|||||||
export const PROFILE_URL = process.env.PROFILE_URL || undefined;
|
export const PROFILE_URL = process.env.PROFILE_URL || undefined;
|
||||||
export const POSTHOG_API_KEY: string = (process.env.POSTHOG_API_KEY as string) || "";
|
export const POSTHOG_API_KEY: string = (process.env.POSTHOG_API_KEY as string) || "";
|
||||||
export const POSTHOG_URL = process.env.POSTHOG_URL || undefined;
|
export const POSTHOG_URL = process.env.POSTHOG_URL || undefined;
|
||||||
|
export const DISABLE_ANONYMOUS = process.env.DISABLE_ANONYMOUS || false;
|
||||||
|
export const OPID_LOGIN_SCREEN_PROVIDER = process.env.OPID_LOGIN_SCREEN_PROVIDER;
|
||||||
|
|
||||||
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ export {
|
|||||||
DISABLE_NOTIFICATIONS,
|
DISABLE_NOTIFICATIONS,
|
||||||
PUSHER_URL,
|
PUSHER_URL,
|
||||||
UPLOADER_URL,
|
UPLOADER_URL,
|
||||||
|
ICON_URL,
|
||||||
POSITION_DELAY,
|
POSITION_DELAY,
|
||||||
MAX_EXTRAPOLATION_TIME,
|
MAX_EXTRAPOLATION_TIME,
|
||||||
STUN_SERVER,
|
STUN_SERVER,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { ITiledMapObject } from "../Map/ITiledMap";
|
import type { ITiledMapObject } from "../Map/ITiledMap";
|
||||||
import type { GameScene } from "../Game/GameScene";
|
import type { GameScene } from "../Game/GameScene";
|
||||||
import { type } from "os";
|
import { type } from "os";
|
||||||
|
import { GameMapProperties } from "../Game/GameMapProperties";
|
||||||
|
|
||||||
export class TextUtils {
|
export class TextUtils {
|
||||||
public static createTextFromITiledMapObject(scene: GameScene, object: ITiledMapObject): void {
|
public static createTextFromITiledMapObject(scene: GameScene, object: ITiledMapObject): void {
|
||||||
@ -32,7 +33,7 @@ export class TextUtils {
|
|||||||
}
|
}
|
||||||
if (object.properties !== undefined) {
|
if (object.properties !== undefined) {
|
||||||
for (const property of object.properties) {
|
for (const property of object.properties) {
|
||||||
if (property.name === "font-family" && typeof property.value === "string") {
|
if (property.name === GameMapProperties.FONT_FAMILY && typeof property.value === "string") {
|
||||||
options.fontFamily = property.value;
|
options.fontFamily = property.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { SpeechBubble } from "./SpeechBubble";
|
|||||||
import Text = Phaser.GameObjects.Text;
|
import Text = Phaser.GameObjects.Text;
|
||||||
import Container = Phaser.GameObjects.Container;
|
import Container = Phaser.GameObjects.Container;
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
|
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||||
import { TextureError } from "../../Exception/TextureError";
|
import { TextureError } from "../../Exception/TextureError";
|
||||||
import { Companion } from "../Companion/Companion";
|
import { Companion } from "../Companion/Companion";
|
||||||
import type { GameScene } from "../Game/GameScene";
|
import type { GameScene } from "../Game/GameScene";
|
||||||
@ -33,7 +34,7 @@ export abstract class Character extends Container {
|
|||||||
//private teleportation: Sprite;
|
//private teleportation: Sprite;
|
||||||
private invisible: boolean;
|
private invisible: boolean;
|
||||||
public companion?: Companion;
|
public companion?: Companion;
|
||||||
private emote: Phaser.GameObjects.Text | null = null;
|
private emote: Phaser.GameObjects.DOMElement | null = null;
|
||||||
private emoteTween: Phaser.Tweens.Tween | null = null;
|
private emoteTween: Phaser.Tweens.Tween | null = null;
|
||||||
scene: GameScene;
|
scene: GameScene;
|
||||||
|
|
||||||
@ -62,11 +63,13 @@ export abstract class Character extends Container {
|
|||||||
.then((textures) => {
|
.then((textures) => {
|
||||||
this.addTextures(textures, frame);
|
this.addTextures(textures, frame);
|
||||||
this.invisible = false;
|
this.invisible = false;
|
||||||
|
this.playAnimation(direction, moving);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
return lazyLoadPlayerCharacterTextures(scene.load, ["color_22", "eyes_23"]).then((textures) => {
|
return lazyLoadPlayerCharacterTextures(scene.load, ["color_22", "eyes_23"]).then((textures) => {
|
||||||
this.addTextures(textures, frame);
|
this.addTextures(textures, frame);
|
||||||
this.invisible = false;
|
this.invisible = false;
|
||||||
|
this.playAnimation(direction, moving);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -107,9 +110,7 @@ export abstract class Character extends Container {
|
|||||||
this.setSize(16, 16);
|
this.setSize(16, 16);
|
||||||
this.getBody().setSize(16, 16); //edit the hitbox to better match the character model
|
this.getBody().setSize(16, 16); //edit the hitbox to better match the character model
|
||||||
this.getBody().setOffset(0, 8);
|
this.getBody().setOffset(0, 8);
|
||||||
this.setDepth(-1);
|
this.setDepth(0);
|
||||||
|
|
||||||
this.playAnimation(direction, moving);
|
|
||||||
|
|
||||||
if (typeof companion === "string") {
|
if (typeof companion === "string") {
|
||||||
this.addCompanion(companion, companionTexturePromise);
|
this.addCompanion(companion, companionTexturePromise);
|
||||||
@ -300,8 +301,9 @@ export abstract class Character extends Container {
|
|||||||
playEmote(emote: string) {
|
playEmote(emote: string) {
|
||||||
this.cancelPreviousEmote();
|
this.cancelPreviousEmote();
|
||||||
const emoteY = -45;
|
const emoteY = -45;
|
||||||
this.playerName.setVisible(false);
|
const image = new Image(16, 16);
|
||||||
this.emote = new Text(this.scene, -10, 0, emote, { fontSize: "20px" });
|
image.src = emote;
|
||||||
|
this.emote = new DOMElement(this.scene, -1, 0, image, "z-index:10;");
|
||||||
this.emote.setAlpha(0);
|
this.emote.setAlpha(0);
|
||||||
this.add(this.emote);
|
this.add(this.emote);
|
||||||
this.createStartTransition(emoteY);
|
this.createStartTransition(emoteY);
|
||||||
|
@ -2,6 +2,7 @@ import type { ITiledMap, ITiledMapLayer, ITiledMapProperty } from "../Map/ITiled
|
|||||||
import { flattenGroupLayersMap } from "../Map/LayersFlattener";
|
import { flattenGroupLayersMap } from "../Map/LayersFlattener";
|
||||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
||||||
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
||||||
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
|
|
||||||
export type PropertyChangeCallback = (
|
export type PropertyChangeCallback = (
|
||||||
newValue: string | number | boolean | undefined,
|
newValue: string | number | boolean | undefined,
|
||||||
@ -9,14 +10,25 @@ export type PropertyChangeCallback = (
|
|||||||
allProps: Map<string, string | boolean | number>
|
allProps: Map<string, string | boolean | number>
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
|
export type layerChangeCallback = (
|
||||||
|
layersChangedByAction: Array<ITiledMapLayer>,
|
||||||
|
allLayersOnNewPosition: Array<ITiledMapLayer>,
|
||||||
|
|
||||||
|
) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a ITiledMap interface to provide additional capabilities.
|
* A wrapper around a ITiledMap interface to provide additional capabilities.
|
||||||
* It is used to handle layer properties.
|
* It is used to handle layer properties.
|
||||||
*/
|
*/
|
||||||
export class GameMap {
|
export class GameMap {
|
||||||
|
// oldKey is the index of the previous tile.
|
||||||
|
private oldKey: number | undefined;
|
||||||
|
// key is the index of the current tile.
|
||||||
private key: number | undefined;
|
private key: number | undefined;
|
||||||
private lastProperties = new Map<string, string | boolean | number>();
|
private lastProperties = new Map<string, string | boolean | number>();
|
||||||
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
|
private propertiesChangeCallbacks = new Map<string, Array<PropertyChangeCallback>>();
|
||||||
|
private enterLayerCallbacks = Array<layerChangeCallback>();
|
||||||
|
private leaveLayerCallbacks = Array<layerChangeCallback>();
|
||||||
private tileNameMap = new Map<string, number>();
|
private tileNameMap = new Map<string, number>();
|
||||||
|
|
||||||
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapProperty> } = {};
|
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapProperty> } = {};
|
||||||
@ -47,12 +59,12 @@ export class GameMap {
|
|||||||
if (tile.properties) {
|
if (tile.properties) {
|
||||||
this.tileSetPropertyMap[tileset.firstgid + tile.id] = tile.properties;
|
this.tileSetPropertyMap[tileset.firstgid + tile.id] = tile.properties;
|
||||||
tile.properties.forEach((prop) => {
|
tile.properties.forEach((prop) => {
|
||||||
if (prop.name == "name" && typeof prop.value == "string") {
|
if (prop.name == GameMapProperties.NAME && typeof prop.value == "string") {
|
||||||
this.tileNameMap.set(prop.value, tileset.firstgid + tile.id);
|
this.tileNameMap.set(prop.value, tileset.firstgid + tile.id);
|
||||||
}
|
}
|
||||||
if (prop.name == "exitUrl" && typeof prop.value == "string") {
|
if (prop.name == GameMapProperties.EXIT_URL && typeof prop.value == "string") {
|
||||||
this.exitUrls.push(prop.value);
|
this.exitUrls.push(prop.value);
|
||||||
} else if (prop.name == "start") {
|
} else if (prop.name == GameMapProperties.START) {
|
||||||
this.hasStartTile = true;
|
this.hasStartTile = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -68,22 +80,32 @@ export class GameMap {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getLayersByKey(key: number): Array<ITiledMapLayer> {
|
||||||
|
return this.flatLayers.filter(flatLayer => flatLayer.type === 'tilelayer' && flatLayer.data[key] !== 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the position of the current player (in pixels)
|
* Sets the position of the current player (in pixels)
|
||||||
* This will trigger events if properties are changing.
|
* This will trigger events if properties are changing.
|
||||||
*/
|
*/
|
||||||
public setPosition(x: number, y: number) {
|
public setPosition(x: number, y: number) {
|
||||||
|
this.oldKey = this.key;
|
||||||
|
|
||||||
const xMap = Math.floor(x / this.map.tilewidth);
|
const xMap = Math.floor(x / this.map.tilewidth);
|
||||||
const yMap = Math.floor(y / this.map.tileheight);
|
const yMap = Math.floor(y / this.map.tileheight);
|
||||||
const key = xMap + yMap * this.map.width;
|
const key = xMap + yMap * this.map.width;
|
||||||
|
|
||||||
if (key === this.key) {
|
if (key === this.key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.triggerAll();
|
|
||||||
|
this.triggerAllProperties();
|
||||||
|
this.triggerLayersChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private triggerAll(): void {
|
private triggerAllProperties(): void {
|
||||||
const newProps = this.getProperties(this.key ?? 0);
|
const newProps = this.getProperties(this.key ?? 0);
|
||||||
const oldProps = this.lastProperties;
|
const oldProps = this.lastProperties;
|
||||||
this.lastProperties = newProps;
|
this.lastProperties = newProps;
|
||||||
@ -105,6 +127,36 @@ export class GameMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private triggerLayersChange() {
|
||||||
|
const layersByOldKey = this.oldKey ? this.getLayersByKey(this.oldKey) : [];
|
||||||
|
const layersByNewKey = this.key ? this.getLayersByKey(this.key) : [];
|
||||||
|
|
||||||
|
const enterLayers = new Set(layersByNewKey);
|
||||||
|
const leaveLayers = new Set(layersByOldKey);
|
||||||
|
|
||||||
|
enterLayers.forEach(layer => {
|
||||||
|
if (leaveLayers.has(layer)) {
|
||||||
|
leaveLayers.delete(layer);
|
||||||
|
enterLayers.delete(layer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (enterLayers.size > 0) {
|
||||||
|
const layerArray = Array.from(enterLayers);
|
||||||
|
for (const callback of this.enterLayerCallbacks) {
|
||||||
|
callback(layerArray, layersByNewKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaveLayers.size > 0) {
|
||||||
|
const layerArray = Array.from(leaveLayers);
|
||||||
|
for (const callback of this.leaveLayerCallbacks) {
|
||||||
|
callback(layerArray, layersByNewKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getCurrentProperties(): Map<string, string | boolean | number> {
|
public getCurrentProperties(): Map<string, string | boolean | number> {
|
||||||
return this.lastProperties;
|
return this.lastProperties;
|
||||||
}
|
}
|
||||||
@ -167,7 +219,7 @@ export class GameMap {
|
|||||||
newValue: string | number | boolean | undefined,
|
newValue: string | number | boolean | undefined,
|
||||||
allProps: Map<string, string | boolean | number>
|
allProps: Map<string, string | boolean | number>
|
||||||
) {
|
) {
|
||||||
const callbacksArray = this.callbacks.get(propName);
|
const callbacksArray = this.propertiesChangeCallbacks.get(propName);
|
||||||
if (callbacksArray !== undefined) {
|
if (callbacksArray !== undefined) {
|
||||||
for (const callback of callbacksArray) {
|
for (const callback of callbacksArray) {
|
||||||
callback(newValue, oldValue, allProps);
|
callback(newValue, oldValue, allProps);
|
||||||
@ -179,14 +231,28 @@ export class GameMap {
|
|||||||
* Registers a callback called when the user moves to a tile where the property propName is different from the last tile the user was on.
|
* Registers a callback called when the user moves to a tile where the property propName is different from the last tile the user was on.
|
||||||
*/
|
*/
|
||||||
public onPropertyChange(propName: string, callback: PropertyChangeCallback) {
|
public onPropertyChange(propName: string, callback: PropertyChangeCallback) {
|
||||||
let callbacksArray = this.callbacks.get(propName);
|
let callbacksArray = this.propertiesChangeCallbacks.get(propName);
|
||||||
if (callbacksArray === undefined) {
|
if (callbacksArray === undefined) {
|
||||||
callbacksArray = new Array<PropertyChangeCallback>();
|
callbacksArray = new Array<PropertyChangeCallback>();
|
||||||
this.callbacks.set(propName, callbacksArray);
|
this.propertiesChangeCallbacks.set(propName, callbacksArray);
|
||||||
}
|
}
|
||||||
callbacksArray.push(callback);
|
callbacksArray.push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback called when the user moves inside another layer.
|
||||||
|
*/
|
||||||
|
public onEnterLayer(callback: layerChangeCallback) {
|
||||||
|
this.enterLayerCallbacks.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback called when the user moves outside another layer.
|
||||||
|
*/
|
||||||
|
public onLeaveLayer(callback: layerChangeCallback) {
|
||||||
|
this.leaveLayerCallbacks.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
public findLayer(layerName: string): ITiledMapLayer | undefined {
|
public findLayer(layerName: string): ITiledMapLayer | undefined {
|
||||||
return this.flatLayers.find((layer) => layer.name === layerName);
|
return this.flatLayers.find((layer) => layer.name === layerName);
|
||||||
}
|
}
|
||||||
@ -238,7 +304,7 @@ export class GameMap {
|
|||||||
this.putTileInFlatLayer(tileIndex, x, y, layer);
|
this.putTileInFlatLayer(tileIndex, x, y, layer);
|
||||||
const phaserTile = phaserLayer.putTileAt(tileIndex, x, y);
|
const phaserTile = phaserLayer.putTileAt(tileIndex, x, y);
|
||||||
for (const property of this.getTileProperty(tileIndex)) {
|
for (const property of this.getTileProperty(tileIndex)) {
|
||||||
if (property.name === "collides" && property.value) {
|
if (property.name === GameMapProperties.COLLIDES && property.value) {
|
||||||
phaserTile.setCollision(true);
|
phaserTile.setCollision(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +350,8 @@ export class GameMap {
|
|||||||
}
|
}
|
||||||
property.value = propertyValue;
|
property.value = propertyValue;
|
||||||
|
|
||||||
this.triggerAll();
|
this.triggerAllProperties();
|
||||||
|
this.triggerLayersChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
37
front/src/Phaser/Game/GameMapProperties.ts
Normal file
37
front/src/Phaser/Game/GameMapProperties.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
export enum GameMapProperties {
|
||||||
|
ALLOW_API = 'allowApi',
|
||||||
|
AUDIO_LOOP = 'audioLoop',
|
||||||
|
AUDIO_VOLUME = 'audioVolume',
|
||||||
|
COLLIDES = 'collides',
|
||||||
|
DEFAULT = 'default',
|
||||||
|
EXIT_URL = 'exitUrl',
|
||||||
|
EXIT_SCENE_URL = 'exitSceneUrl',
|
||||||
|
FONT_FAMILY = 'font-family',
|
||||||
|
JITSI_ADMIN_ROOM_TAG = 'jitsiRoomAdminTag',
|
||||||
|
JITSI_CONFIG = 'jitsiConfig',
|
||||||
|
JITSI_INTERFACE_CONFIG = 'jitsiInterfaceConfig',
|
||||||
|
JITSI_ROOM = 'jitsiRoom',
|
||||||
|
JITSI_TRIGGER = 'jitsiTrigger',
|
||||||
|
JITSI_TRIGGER_MESSAGE = 'jitsiTriggerMessage',
|
||||||
|
JITSI_URL = 'jitsiUrl',
|
||||||
|
JITSI_WIDTH = 'jitsiWidth',
|
||||||
|
NAME = 'name',
|
||||||
|
OPEN_TAB = 'openTab',
|
||||||
|
OPEN_WEBSITE = 'openWebsite',
|
||||||
|
OPEN_WEBSITE_ALLOW_API = 'openWebsiteAllowApi',
|
||||||
|
OPEN_WEBSITE_POLICY = 'openWebsitePolicy',
|
||||||
|
OPEN_WEBSITE_WIDTH = 'openWebsiteWidth',
|
||||||
|
OPEN_WEBSITE_POSITION = 'openWebsitePosition',
|
||||||
|
OPEN_WEBSITE_TRIGGER = 'openWebsiteTrigger',
|
||||||
|
OPEN_WEBSITE_TRIGGER_MESSAGE = 'openWebsiteTriggerMessage',
|
||||||
|
PLAY_AUDIO = 'playAudio',
|
||||||
|
PLAY_AUDIO_LOOP = 'playAudioLoop',
|
||||||
|
READABLE_BY = 'readableBy',
|
||||||
|
SCRIPT = 'script',
|
||||||
|
SILENT = 'silent',
|
||||||
|
START = 'start',
|
||||||
|
START_LAYER = 'startLayer',
|
||||||
|
URL = 'url',
|
||||||
|
WRITABLE_BY = 'writableBy',
|
||||||
|
ZONE = 'zone',
|
||||||
|
}
|
@ -1,26 +1,42 @@
|
|||||||
import type { GameScene } from "./GameScene";
|
import type { GameScene } from "./GameScene";
|
||||||
import type { GameMap } from "./GameMap";
|
import type { GameMap } from "./GameMap";
|
||||||
import { scriptUtils } from "../../Api/ScriptUtils";
|
import { scriptUtils } from "../../Api/ScriptUtils";
|
||||||
|
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
||||||
|
import { get } from 'svelte/store';
|
||||||
import {
|
import {
|
||||||
ON_ACTION_TRIGGER_BUTTON,
|
ON_ACTION_TRIGGER_BUTTON,
|
||||||
TRIGGER_WEBSITE_PROPERTIES,
|
|
||||||
WEBSITE_MESSAGE_PROPERTIES,
|
|
||||||
} from "../../WebRtc/LayoutManager";
|
} from "../../WebRtc/LayoutManager";
|
||||||
|
import type { ITiledMapLayer } from "../Map/ITiledMap";
|
||||||
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
|
|
||||||
|
enum OpenCoWebsiteState {
|
||||||
|
LOADING,
|
||||||
|
OPENED,
|
||||||
|
MUST_BE_CLOSE,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OpenCoWebsite {
|
||||||
|
coWebsite: CoWebsite | undefined,
|
||||||
|
state: OpenCoWebsiteState
|
||||||
|
}
|
||||||
|
|
||||||
export class GameMapPropertiesListener {
|
export class GameMapPropertiesListener {
|
||||||
|
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
|
||||||
|
private coWebsitesActionTriggerByLayer = new Map<ITiledMapLayer, string>();
|
||||||
|
|
||||||
constructor(private scene: GameScene, private gameMap: GameMap) {}
|
constructor(private scene: GameScene, private gameMap: GameMap) {}
|
||||||
|
|
||||||
register() {
|
register() {
|
||||||
this.gameMap.onPropertyChange("openTab", (newValue, oldvalue, allProps) => {
|
this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldvalue, allProps) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
layoutManagerActionStore.removeAction("openTab");
|
layoutManagerActionStore.removeAction("openTab");
|
||||||
}
|
}
|
||||||
if (typeof newValue == "string" && newValue.length) {
|
if (typeof newValue == "string" && newValue.length) {
|
||||||
const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES);
|
const openWebsiteTriggerValue = allProps.get(GameMapProperties.OPEN_WEBSITE_TRIGGER);
|
||||||
if (openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
if (openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
||||||
let message = allProps.get(WEBSITE_MESSAGE_PROPERTIES);
|
let message = allProps.get(GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE);
|
||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
message = "Press SPACE or touch here to open web site in new tab";
|
message = "Press SPACE or touch here to open web site in new tab";
|
||||||
}
|
}
|
||||||
@ -36,38 +52,181 @@ export class GameMapPropertiesListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("openWebsite", (newValue, oldValue, allProps) => {
|
|
||||||
if (newValue === undefined) {
|
// Open a new co-website by the property.
|
||||||
layoutManagerActionStore.removeAction("openWebsite");
|
this.gameMap.onEnterLayer((newLayers) => {
|
||||||
coWebsiteManager.closeCoWebsite();
|
const handler = () => {
|
||||||
} else {
|
newLayers.forEach(layer => {
|
||||||
|
if (!layer.properties) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let openWebsiteProperty: string | undefined;
|
||||||
|
let allowApiProperty: boolean | undefined;
|
||||||
|
let websitePolicyProperty: string | undefined;
|
||||||
|
let websiteWidthProperty: number | undefined;
|
||||||
|
let websitePositionProperty: number | undefined;
|
||||||
|
let websiteTriggerProperty: string | undefined;
|
||||||
|
let websiteTriggerMessageProperty: string | undefined;
|
||||||
|
|
||||||
|
layer.properties.forEach(property => {
|
||||||
|
switch(property.name) {
|
||||||
|
case GameMapProperties.OPEN_WEBSITE:
|
||||||
|
openWebsiteProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_ALLOW_API:
|
||||||
|
allowApiProperty = property.value as boolean | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_POLICY:
|
||||||
|
websitePolicyProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_WIDTH:
|
||||||
|
websiteWidthProperty = property.value as number | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_POSITION:
|
||||||
|
websitePositionProperty = property.value as number | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_TRIGGER:
|
||||||
|
websiteTriggerProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE:
|
||||||
|
websiteTriggerMessageProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!openWebsiteProperty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionUuid = "openWebsite-" + (Math.random() + 1).toString(36).substring(7);
|
||||||
|
|
||||||
|
if (this.coWebsitesOpenByLayer.has(layer)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coWebsitesOpenByLayer.set(layer, {
|
||||||
|
coWebsite: undefined,
|
||||||
|
state: OpenCoWebsiteState.LOADING,
|
||||||
|
});
|
||||||
|
|
||||||
const openWebsiteFunction = () => {
|
const openWebsiteFunction = () => {
|
||||||
coWebsiteManager.loadCoWebsite(
|
coWebsiteManager.loadCoWebsite(
|
||||||
newValue as string,
|
openWebsiteProperty as string,
|
||||||
this.scene.MapUrlFile,
|
this.scene.MapUrlFile,
|
||||||
allProps.get("openWebsiteAllowApi") as boolean | undefined,
|
allowApiProperty,
|
||||||
allProps.get("openWebsitePolicy") as string | undefined,
|
websitePolicyProperty,
|
||||||
allProps.get("openWebsiteWidth") as number | undefined
|
websiteWidthProperty,
|
||||||
);
|
websitePositionProperty,
|
||||||
layoutManagerActionStore.removeAction("openWebsite");
|
).then(coWebsite => {
|
||||||
};
|
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
||||||
const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES);
|
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
|
||||||
if (openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
coWebsiteManager.closeCoWebsite(coWebsite);
|
||||||
let message = allProps.get(WEBSITE_MESSAGE_PROPERTIES);
|
this.coWebsitesOpenByLayer.delete(layer);
|
||||||
if (message === undefined) {
|
this.coWebsitesActionTriggerByLayer.delete(layer);
|
||||||
message = "Press SPACE or touch here to open web site";
|
} else {
|
||||||
|
this.coWebsitesOpenByLayer.set(layer, {
|
||||||
|
coWebsite,
|
||||||
|
state: OpenCoWebsiteState.OPENED
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
layoutManagerActionStore.removeAction(actionUuid);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (websiteTriggerProperty && websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON) {
|
||||||
|
if (!websiteTriggerMessageProperty) {
|
||||||
|
websiteTriggerMessageProperty = "Press SPACE or touch here to open web site";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coWebsitesActionTriggerByLayer.set(layer, actionUuid);
|
||||||
|
|
||||||
layoutManagerActionStore.addAction({
|
layoutManagerActionStore.addAction({
|
||||||
uuid: "openWebsite",
|
uuid: actionUuid,
|
||||||
type: "message",
|
type: "message",
|
||||||
message: message,
|
message: websiteTriggerMessageProperty,
|
||||||
callback: () => openWebsiteFunction(),
|
callback: () => openWebsiteFunction(),
|
||||||
userInputManager: this.scene.userInputManager,
|
userInputManager: this.scene.userInputManager,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
openWebsiteFunction();
|
openWebsiteFunction();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handler();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close opened co-websites on leave the layer who contain the property.
|
||||||
|
this.gameMap.onLeaveLayer((oldLayers) => {
|
||||||
|
const handler = () => {
|
||||||
|
oldLayers.forEach(layer => {
|
||||||
|
if (!layer.properties) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let openWebsiteProperty: string | undefined;
|
||||||
|
let websiteTriggerProperty: string | undefined;
|
||||||
|
|
||||||
|
layer.properties.forEach(property => {
|
||||||
|
switch(property.name) {
|
||||||
|
case GameMapProperties.OPEN_WEBSITE:
|
||||||
|
openWebsiteProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_TRIGGER:
|
||||||
|
websiteTriggerProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!openWebsiteProperty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
||||||
|
|
||||||
|
if (!coWebsiteOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coWebsiteOpen.state === OpenCoWebsiteState.LOADING) {
|
||||||
|
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coWebsiteOpen.state !== OpenCoWebsiteState.OPENED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coWebsiteOpen.coWebsite !== undefined) {
|
||||||
|
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coWebsitesOpenByLayer.delete(layer);
|
||||||
|
|
||||||
|
if (!websiteTriggerProperty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionStore = get(layoutManagerActionStore);
|
||||||
|
const actionTriggerUuid = this.coWebsitesActionTriggerByLayer.get(layer);
|
||||||
|
|
||||||
|
if (!actionTriggerUuid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const action = actionStore && actionStore.length > 0 ?
|
||||||
|
actionStore.find(action => action.uuid === actionTriggerUuid) : undefined;
|
||||||
|
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
layoutManagerActionStore.removeAction(actionTriggerUuid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,8 @@ import type {
|
|||||||
import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
import { Queue } from "queue-typescript";
|
import { Queue } from "queue-typescript";
|
||||||
import {
|
import { Box, ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
|
||||||
AUDIO_LOOP_PROPERTY,
|
import { CoWebsite, coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
AUDIO_VOLUME_PROPERTY,
|
|
||||||
Box,
|
|
||||||
JITSI_MESSAGE_PROPERTIES,
|
|
||||||
ON_ACTION_TRIGGER_BUTTON,
|
|
||||||
TRIGGER_JITSI_PROPERTIES,
|
|
||||||
TRIGGER_WEBSITE_PROPERTIES,
|
|
||||||
WEBSITE_MESSAGE_PROPERTIES,
|
|
||||||
} from "../../WebRtc/LayoutManager";
|
|
||||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
|
||||||
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
|
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
|
||||||
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
||||||
import type { RoomConnection } from "../../Connexion/RoomConnection";
|
import type { RoomConnection } from "../../Connexion/RoomConnection";
|
||||||
@ -95,8 +86,8 @@ import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
|||||||
import { GameMapPropertiesListener } from "./GameMapPropertiesListener";
|
import { GameMapPropertiesListener } from "./GameMapPropertiesListener";
|
||||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import type { RadialMenuItem } from "../Components/RadialMenu";
|
|
||||||
import { contactPageStore } from "../../Stores/MenuStore";
|
import { contactPageStore } from "../../Stores/MenuStore";
|
||||||
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
@ -187,6 +178,8 @@ export class GameScene extends DirtyScene {
|
|||||||
moving: false,
|
moving: false,
|
||||||
x: -1000,
|
x: -1000,
|
||||||
y: -1000,
|
y: -1000,
|
||||||
|
oldX: -1000,
|
||||||
|
oldY: -1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
private gameMap!: GameMap;
|
private gameMap!: GameMap;
|
||||||
@ -290,6 +283,12 @@ export class GameScene extends DirtyScene {
|
|||||||
this.onMapLoad(data);
|
this.onMapLoad(data);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// If the map has already been loaded as part of another GameScene, the "on load" event will not be triggered.
|
||||||
|
// In this case, we check in the cache to see if the map is here and trigger the event manually.
|
||||||
|
if (this.cache.tilemap.exists(this.MapUrlFile)) {
|
||||||
|
const data = this.cache.tilemap.get(this.MapUrlFile);
|
||||||
|
this.onMapLoad(data);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,11 +490,14 @@ export class GameScene extends DirtyScene {
|
|||||||
if (object.type === "website") {
|
if (object.type === "website") {
|
||||||
// Let's load iframes in the map
|
// Let's load iframes in the map
|
||||||
const url = PropertyUtils.mustFindStringProperty(
|
const url = PropertyUtils.mustFindStringProperty(
|
||||||
"url",
|
GameMapProperties.URL,
|
||||||
object.properties,
|
object.properties,
|
||||||
'in the "' + object.name + '" object of type "website"'
|
'in the "' + object.name + '" object of type "website"'
|
||||||
);
|
);
|
||||||
const allowApi = PropertyUtils.findBooleanProperty("allowApi", object.properties);
|
const allowApi = PropertyUtils.findBooleanProperty(
|
||||||
|
GameMapProperties.ALLOW_API,
|
||||||
|
object.properties
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: add a "allow" property to iframe
|
// TODO: add a "allow" property to iframe
|
||||||
this.embeddedWebsiteManager.createEmbeddedWebsite(
|
this.embeddedWebsiteManager.createEmbeddedWebsite(
|
||||||
@ -612,10 +614,10 @@ export class GameScene extends DirtyScene {
|
|||||||
oldPeerNumber = newPeerNumber;
|
oldPeerNumber = newPeerNumber;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emoteUnsubscribe = emoteStore.subscribe((emoteKey) => {
|
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
||||||
if (emoteKey) {
|
if (emote) {
|
||||||
this.CurrentPlayer?.playEmote(emoteKey);
|
this.CurrentPlayer?.playEmote(emote.url);
|
||||||
this.connection?.emitEmoteEvent(emoteKey);
|
this.connection?.emitEmoteEvent(emote.url);
|
||||||
emoteStore.set(null);
|
emoteStore.set(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -759,6 +761,19 @@ export class GameScene extends DirtyScene {
|
|||||||
|
|
||||||
//init user position and play trigger to check layers properties
|
//init user position and play trigger to check layers properties
|
||||||
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
||||||
|
|
||||||
|
// Init layer change listener
|
||||||
|
this.gameMap.onEnterLayer((layers) => {
|
||||||
|
layers.forEach((layer) => {
|
||||||
|
iframeListener.sendEnterLayerEvent(layer.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gameMap.onLeaveLayer((layers) => {
|
||||||
|
layers.forEach((layer) => {
|
||||||
|
iframeListener.sendLeaveLayerEvent(layer.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,7 +823,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private triggerOnMapLayerPropertyChange() {
|
private triggerOnMapLayerPropertyChange() {
|
||||||
this.gameMap.onPropertyChange("exitSceneUrl", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue, oldValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
this.onMapExit(
|
this.onMapExit(
|
||||||
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
|
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
|
||||||
@ -819,7 +834,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("exitUrl", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()));
|
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()));
|
||||||
} else {
|
} else {
|
||||||
@ -829,16 +844,16 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gameMap.onPropertyChange("jitsiRoom", (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange(GameMapProperties.JITSI_ROOM, (newValue, oldValue, allProps) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
layoutManagerActionStore.removeAction("jitsi");
|
layoutManagerActionStore.removeAction("jitsi");
|
||||||
this.stopJitsi();
|
this.stopJitsi();
|
||||||
} else {
|
} else {
|
||||||
const openJitsiRoomFunction = () => {
|
const openJitsiRoomFunction = () => {
|
||||||
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance);
|
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance);
|
||||||
const jitsiUrl = allProps.get("jitsiUrl") as string | undefined;
|
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||||
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
|
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
|
||||||
const adminTag = allProps.get("jitsiRoomAdminTag") as string | undefined;
|
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
|
||||||
|
|
||||||
this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
|
this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
|
||||||
} else {
|
} else {
|
||||||
@ -847,9 +862,9 @@ export class GameScene extends DirtyScene {
|
|||||||
layoutManagerActionStore.removeAction("jitsi");
|
layoutManagerActionStore.removeAction("jitsi");
|
||||||
};
|
};
|
||||||
|
|
||||||
const jitsiTriggerValue = allProps.get(TRIGGER_JITSI_PROPERTIES);
|
const jitsiTriggerValue = allProps.get(GameMapProperties.JITSI_TRIGGER);
|
||||||
if (jitsiTriggerValue && jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
if (jitsiTriggerValue && jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
||||||
let message = allProps.get(JITSI_MESSAGE_PROPERTIES);
|
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
|
||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
message = "Press SPACE or touch here to enter Jitsi Meet room";
|
message = "Press SPACE or touch here to enter Jitsi Meet room";
|
||||||
}
|
}
|
||||||
@ -865,7 +880,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("silent", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue, oldValue) => {
|
||||||
if (newValue === undefined || newValue === false || newValue === "") {
|
if (newValue === undefined || newValue === false || newValue === "") {
|
||||||
this.connection?.setSilent(false);
|
this.connection?.setSilent(false);
|
||||||
this.CurrentPlayer.noSilent();
|
this.CurrentPlayer.noSilent();
|
||||||
@ -874,23 +889,24 @@ export class GameScene extends DirtyScene {
|
|||||||
this.CurrentPlayer.isSilent();
|
this.CurrentPlayer.isSilent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("playAudio", (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO, (newValue, oldValue, allProps) => {
|
||||||
const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number | undefined;
|
const volume = allProps.get(GameMapProperties.AUDIO_VOLUME) as number | undefined;
|
||||||
const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean | undefined;
|
const loop = allProps.get(GameMapProperties.AUDIO_LOOP) as boolean | undefined;
|
||||||
newValue === undefined
|
newValue === undefined
|
||||||
? audioManagerFileStore.unloadAudio()
|
? audioManagerFileStore.unloadAudio()
|
||||||
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), volume, loop);
|
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), volume, loop);
|
||||||
audioManagerVisibilityStore.set(!(newValue === undefined));
|
audioManagerVisibilityStore.set(!(newValue === undefined));
|
||||||
});
|
});
|
||||||
// TODO: This legacy property should be removed at some point
|
// TODO: This legacy property should be removed at some point
|
||||||
this.gameMap.onPropertyChange("playAudioLoop", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue, oldValue) => {
|
||||||
newValue === undefined
|
newValue === undefined
|
||||||
? audioManagerFileStore.unloadAudio()
|
? audioManagerFileStore.unloadAudio()
|
||||||
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), undefined, true);
|
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), undefined, true);
|
||||||
audioManagerVisibilityStore.set(!(newValue === undefined));
|
audioManagerVisibilityStore.set(!(newValue === undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gameMap.onPropertyChange("zone", (newValue, oldValue) => {
|
// TODO: Legacy functionnality replace by layer change
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.ZONE, (newValue, oldValue) => {
|
||||||
if (oldValue) {
|
if (oldValue) {
|
||||||
iframeListener.sendLeaveEvent(oldValue as string);
|
iframeListener.sendLeaveEvent(oldValue as string);
|
||||||
}
|
}
|
||||||
@ -1075,6 +1091,58 @@ ${escapedMessage}
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
iframeListener.registerAnswerer("openCoWebsite", async (openCoWebsite, source) => {
|
||||||
|
if (!source) {
|
||||||
|
throw new Error("Unknown query source");
|
||||||
|
}
|
||||||
|
|
||||||
|
const coWebsite = await coWebsiteManager.loadCoWebsite(
|
||||||
|
openCoWebsite.url,
|
||||||
|
iframeListener.getBaseUrlFromSource(source),
|
||||||
|
openCoWebsite.allowApi,
|
||||||
|
openCoWebsite.allowPolicy,
|
||||||
|
openCoWebsite.position
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!coWebsite) {
|
||||||
|
throw new Error("Error on opening co-website");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: coWebsite.iframe.id,
|
||||||
|
position: coWebsite.position,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
iframeListener.registerAnswerer("getCoWebsites", () => {
|
||||||
|
const coWebsites = coWebsiteManager.getCoWebsites();
|
||||||
|
|
||||||
|
return coWebsites.map((coWebsite: CoWebsite) => {
|
||||||
|
return {
|
||||||
|
id: coWebsite.iframe.id,
|
||||||
|
position: coWebsite.position,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
iframeListener.registerAnswerer("closeCoWebsite", async (coWebsiteId) => {
|
||||||
|
const coWebsite = coWebsiteManager.getCoWebsiteById(coWebsiteId);
|
||||||
|
|
||||||
|
if (!coWebsite) {
|
||||||
|
throw new Error("Unknown co-website");
|
||||||
|
}
|
||||||
|
|
||||||
|
return coWebsiteManager.closeCoWebsite(coWebsite).catch((error) => {
|
||||||
|
throw new Error("Error on closing co-website");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
iframeListener.registerAnswerer("closeCoWebsites", async () => {
|
||||||
|
return await coWebsiteManager.closeCoWebsites().catch((error) => {
|
||||||
|
throw new Error("Error on closing all co-websites");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer("getMapData", () => {
|
iframeListener.registerAnswerer("getMapData", () => {
|
||||||
return {
|
return {
|
||||||
data: this.gameMap.getMap(),
|
data: this.gameMap.getMap(),
|
||||||
@ -1185,27 +1253,6 @@ ${escapedMessage}
|
|||||||
iframeListener.registerAnswerer("removeActionMessage", (message) => {
|
iframeListener.registerAnswerer("removeActionMessage", (message) => {
|
||||||
layoutManagerActionStore.removeAction(message.uuid);
|
layoutManagerActionStore.removeAction(message.uuid);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.iframeSubscriptionList.push(
|
|
||||||
iframeListener.modifyEmbeddedWebsiteStream.subscribe((embeddedWebsite) => {
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
// TODO
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setPropertyLayer(
|
private setPropertyLayer(
|
||||||
@ -1213,7 +1260,7 @@ ${escapedMessage}
|
|||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertyValue: string | number | boolean | undefined
|
propertyValue: string | number | boolean | undefined
|
||||||
): void {
|
): void {
|
||||||
if (propertyName === "exitUrl" && typeof propertyValue === "string") {
|
if (propertyName === GameMapProperties.EXIT_URL && typeof propertyValue === "string") {
|
||||||
this.loadNextGameFromExitUrl(propertyValue);
|
this.loadNextGameFromExitUrl(propertyValue);
|
||||||
}
|
}
|
||||||
this.gameMap.setLayerProperty(layerName, propertyName, propertyValue);
|
this.gameMap.setLayerProperty(layerName, propertyName, propertyValue);
|
||||||
@ -1299,7 +1346,7 @@ ${escapedMessage}
|
|||||||
|
|
||||||
public cleanupClosingScene(): void {
|
public cleanupClosingScene(): void {
|
||||||
// stop playing audio, close any open website, stop any open Jitsi
|
// stop playing audio, close any open website, stop any open Jitsi
|
||||||
coWebsiteManager.closeCoWebsite();
|
coWebsiteManager.closeCoWebsites();
|
||||||
// Stop the script, if any
|
// Stop the script, if any
|
||||||
const scripts = this.getScriptUrls(this.mapFile);
|
const scripts = this.getScriptUrls(this.mapFile);
|
||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
@ -1325,6 +1372,8 @@ ${escapedMessage}
|
|||||||
iframeListener.unregisterAnswerer("getMapData");
|
iframeListener.unregisterAnswerer("getMapData");
|
||||||
iframeListener.unregisterAnswerer("triggerActionMessage");
|
iframeListener.unregisterAnswerer("triggerActionMessage");
|
||||||
iframeListener.unregisterAnswerer("removeActionMessage");
|
iframeListener.unregisterAnswerer("removeActionMessage");
|
||||||
|
iframeListener.unregisterAnswerer("openCoWebsite");
|
||||||
|
iframeListener.unregisterAnswerer("getCoWebsites");
|
||||||
this.sharedVariablesManager?.close();
|
this.sharedVariablesManager?.close();
|
||||||
this.embeddedWebsiteManager?.close();
|
this.embeddedWebsiteManager?.close();
|
||||||
|
|
||||||
@ -1349,18 +1398,18 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getExitUrl(layer: ITiledMapLayer): string | undefined {
|
private getExitUrl(layer: ITiledMapLayer): string | undefined {
|
||||||
return this.getProperty(layer, "exitUrl") as string | undefined;
|
return this.getProperty(layer, GameMapProperties.EXIT_URL) as string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated the map property exitSceneUrl is deprecated
|
* @deprecated the map property exitSceneUrl is deprecated
|
||||||
*/
|
*/
|
||||||
private getExitSceneUrl(layer: ITiledMapLayer): string | undefined {
|
private getExitSceneUrl(layer: ITiledMapLayer): string | undefined {
|
||||||
return this.getProperty(layer, "exitSceneUrl") as string | undefined;
|
return this.getProperty(layer, GameMapProperties.EXIT_SCENE_URL) as string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getScriptUrls(map: ITiledMap): string[] {
|
private getScriptUrls(map: ITiledMap): string[] {
|
||||||
return (this.getProperties(map, "script") as string[]).map((script) =>
|
return (this.getProperties(map, GameMapProperties.SCRIPT) as string[]).map((script) =>
|
||||||
new URL(script, this.MapUrlFile).toString()
|
new URL(script, this.MapUrlFile).toString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1711,7 +1760,11 @@ ${escapedMessage}
|
|||||||
const playerMovement = new PlayerMovement(
|
const playerMovement = new PlayerMovement(
|
||||||
{ x: player.x, y: player.y },
|
{ x: player.x, y: player.y },
|
||||||
this.currentTick,
|
this.currentTick,
|
||||||
message.position,
|
{
|
||||||
|
...message.position,
|
||||||
|
oldX: undefined,
|
||||||
|
oldY: undefined,
|
||||||
|
},
|
||||||
this.currentTick + POSITION_DELAY
|
this.currentTick + POSITION_DELAY
|
||||||
);
|
);
|
||||||
this.playersPositionInterpolator.updatePlayerPosition(player.userId, playerMovement);
|
this.playersPositionInterpolator.updatePlayerPosition(player.userId, playerMovement);
|
||||||
@ -1814,13 +1867,16 @@ ${escapedMessage}
|
|||||||
|
|
||||||
public startJitsi(roomName: string, jwt?: string): void {
|
public startJitsi(roomName: string, jwt?: string): void {
|
||||||
const allProps = this.gameMap.getCurrentProperties();
|
const allProps = this.gameMap.getCurrentProperties();
|
||||||
const jitsiConfig = this.safeParseJSONstring(allProps.get("jitsiConfig") as string | undefined, "jitsiConfig");
|
const jitsiConfig = this.safeParseJSONstring(
|
||||||
const jitsiInterfaceConfig = this.safeParseJSONstring(
|
allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined,
|
||||||
allProps.get("jitsiInterfaceConfig") as string | undefined,
|
GameMapProperties.JITSI_CONFIG
|
||||||
"jitsiInterfaceConfig"
|
|
||||||
);
|
);
|
||||||
const jitsiUrl = allProps.get("jitsiUrl") as string | undefined;
|
const jitsiInterfaceConfig = this.safeParseJSONstring(
|
||||||
const jitsiWidth = allProps.get("jitsiWidth") as number | undefined;
|
allProps.get(GameMapProperties.JITSI_INTERFACE_CONFIG) as string | undefined,
|
||||||
|
GameMapProperties.JITSI_INTERFACE_CONFIG
|
||||||
|
);
|
||||||
|
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||||
|
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
|
||||||
|
|
||||||
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth);
|
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth);
|
||||||
this.connection?.setSilent(true);
|
this.connection?.setSilent(true);
|
||||||
@ -1834,7 +1890,7 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
|
|
||||||
public stopJitsi(): void {
|
public stopJitsi(): void {
|
||||||
const silent = this.gameMap.getCurrentProperties().get("silent");
|
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT);
|
||||||
this.connection?.setSilent(!!silent);
|
this.connection?.setSilent(!!silent);
|
||||||
jitsiFactory.stop();
|
jitsiFactory.stop();
|
||||||
mediaManager.showGameOverlay();
|
mediaManager.showGameOverlay();
|
||||||
|
@ -38,6 +38,8 @@ export class PlayerMovement {
|
|||||||
return {
|
return {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
oldX: this.startPosition.x,
|
||||||
|
oldY: this.startPosition.y,
|
||||||
direction: this.endPosition.direction,
|
direction: this.endPosition.direction,
|
||||||
moving: true,
|
moving: true,
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ import type { RoomConnection } from "../../Connexion/RoomConnection";
|
|||||||
import { iframeListener } from "../../Api/IframeListener";
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
import type { GameMap } from "./GameMap";
|
import type { GameMap } from "./GameMap";
|
||||||
import type { ITiledMapLayer, ITiledMapObject, ITiledMapObjectLayer } from "../Map/ITiledMap";
|
import type { ITiledMapLayer, ITiledMapObject, ITiledMapObjectLayer } from "../Map/ITiledMap";
|
||||||
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
|
|
||||||
interface Variable {
|
interface Variable {
|
||||||
defaultValue: unknown;
|
defaultValue: unknown;
|
||||||
@ -133,10 +134,10 @@ export class SharedVariablesManager {
|
|||||||
for (const property of object.properties) {
|
for (const property of object.properties) {
|
||||||
const value = property.value;
|
const value = property.value;
|
||||||
switch (property.name) {
|
switch (property.name) {
|
||||||
case "default":
|
case GameMapProperties.DEFAULT:
|
||||||
variable.defaultValue = value;
|
variable.defaultValue = value;
|
||||||
break;
|
break;
|
||||||
case "writableBy":
|
case GameMapProperties.WRITABLE_BY:
|
||||||
if (typeof value !== "string") {
|
if (typeof value !== "string") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The writableBy property of variable "' + object.name + '" must be a string'
|
'The writableBy property of variable "' + object.name + '" must be a string'
|
||||||
@ -146,7 +147,7 @@ export class SharedVariablesManager {
|
|||||||
variable.writableBy = value;
|
variable.writableBy = value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "readableBy":
|
case GameMapProperties.READABLE_BY:
|
||||||
if (typeof value !== "string") {
|
if (typeof value !== "string") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The readableBy property of variable "' + object.name + '" must be a string'
|
'The readableBy property of variable "' + object.name + '" must be a string'
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
||||||
import type { ITiledMap, ITiledMapLayer, ITiledMapProperty, ITiledMapTileLayer } from "../Map/ITiledMap";
|
import type { ITiledMap, ITiledMapLayer, ITiledMapProperty, ITiledMapTileLayer } from "../Map/ITiledMap";
|
||||||
import type { GameMap } from "./GameMap";
|
import type { GameMap } from "./GameMap";
|
||||||
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
|
|
||||||
const defaultStartLayerName = "start";
|
const defaultStartLayerName = "start";
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ export class StartPositionCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isStartLayer(layer: ITiledMapLayer): boolean {
|
private isStartLayer(layer: ITiledMapLayer): boolean {
|
||||||
return this.getProperty(layer, "startLayer") == true;
|
return this.getProperty(layer, GameMapProperties.START_LAYER) == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,8 +3,6 @@ import type { GameScene } from "../Game/GameScene";
|
|||||||
import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
|
import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
|
||||||
import { Character } from "../Entity/Character";
|
import { Character } from "../Entity/Character";
|
||||||
import { userMovingStore } from "../../Stores/GameStore";
|
import { userMovingStore } from "../../Stores/GameStore";
|
||||||
import { get } from "svelte/store";
|
|
||||||
import { emoteMenuStore } from "../../Stores/EmoteStore";
|
|
||||||
|
|
||||||
export const hasMovedEventName = "hasMoved";
|
export const hasMovedEventName = "hasMoved";
|
||||||
export const requestEmoteEventName = "requestEmote";
|
export const requestEmoteEventName = "requestEmote";
|
||||||
@ -64,14 +62,28 @@ export class Player extends Character {
|
|||||||
|
|
||||||
if (x !== 0 || y !== 0) {
|
if (x !== 0 || y !== 0) {
|
||||||
this.move(x, y);
|
this.move(x, y);
|
||||||
this.emit(hasMovedEventName, { moving, direction, x: this.x, y: this.y });
|
this.emit(hasMovedEventName, { moving, direction, x: this.x, y: this.y, oldX: x, oldY: y });
|
||||||
} else if (this.wasMoving && moving) {
|
} else if (this.wasMoving && moving) {
|
||||||
// slow joystick movement
|
// slow joystick movement
|
||||||
this.move(0, 0);
|
this.move(0, 0);
|
||||||
this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y });
|
this.emit(hasMovedEventName, {
|
||||||
|
moving,
|
||||||
|
direction: this.previousDirection,
|
||||||
|
x: this.x,
|
||||||
|
y: this.y,
|
||||||
|
oldX: x,
|
||||||
|
oldY: y,
|
||||||
|
});
|
||||||
} else if (this.wasMoving && !moving) {
|
} else if (this.wasMoving && !moving) {
|
||||||
this.stop();
|
this.stop();
|
||||||
this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y });
|
this.emit(hasMovedEventName, {
|
||||||
|
moving,
|
||||||
|
direction: this.previousDirection,
|
||||||
|
x: this.x,
|
||||||
|
y: this.y,
|
||||||
|
oldX: x,
|
||||||
|
oldY: y,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction !== null) {
|
if (direction !== null) {
|
||||||
|
@ -82,13 +82,20 @@ function createChatMessagesStore() {
|
|||||||
date: new Date(),
|
date: new Date(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iframeListener.sendUserInputChat(text);
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
addExternalMessage(authorId: number, text: string) {
|
addExternalMessage(authorId: number, text: string) {
|
||||||
update((list) => {
|
update((list) => {
|
||||||
const lastMessage = list[list.length - 1];
|
const lastMessage = list[list.length - 1];
|
||||||
if (lastMessage && lastMessage.type === ChatMessageTypes.text && lastMessage.text) {
|
if (
|
||||||
|
lastMessage &&
|
||||||
|
lastMessage.type === ChatMessageTypes.text &&
|
||||||
|
lastMessage.text &&
|
||||||
|
lastMessage?.author?.userId === authorId
|
||||||
|
) {
|
||||||
lastMessage.text.push(text);
|
lastMessage.text.push(text);
|
||||||
} else {
|
} else {
|
||||||
list.push({
|
list.push({
|
||||||
@ -98,6 +105,8 @@ function createChatMessagesStore() {
|
|||||||
date: new Date(),
|
date: new Date(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iframeListener.sendUserInputChat(text);
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
chatVisibilityStore.set(true);
|
chatVisibilityStore.set(true);
|
||||||
@ -120,4 +129,4 @@ function createChatSubMenuVisibilityStore() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const chatSubMenuVisbilityStore = createChatSubMenuVisibilityStore();
|
export const chatSubMenuVisibilityStore = createChatSubMenuVisibilityStore();
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export interface Emoji {
|
||||||
|
unicode: string;
|
||||||
|
url: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
function createEmoteMenuStore() {
|
function createEmoteMenuStore() {
|
||||||
const { subscribe, set } = writable(false);
|
const { subscribe, set } = writable(false);
|
||||||
|
|
||||||
@ -14,5 +20,5 @@ function createEmoteMenuStore() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const emoteStore = writable<string | null>(null);
|
export const emoteStore = writable<Emoji | null>(null);
|
||||||
export const emoteMenuStore = createEmoteMenuStore();
|
export const emoteMenuStore = createEmoteMenuStore();
|
||||||
|
@ -9,7 +9,9 @@ export interface LayoutManagerAction {
|
|||||||
userInputManager: UserInputManager | undefined;
|
userInputManager: UserInputManager | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function createLayoutManagerAction() {
|
function createLayoutManagerAction() {
|
||||||
|
|
||||||
const { subscribe, set, update } = writable<LayoutManagerAction[]>([]);
|
const { subscribe, set, update } = writable<LayoutManagerAction[]>([]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -34,20 +34,20 @@ export const warningContainerStore = createWarningContainerStore();
|
|||||||
export enum SubMenusInterface {
|
export enum SubMenusInterface {
|
||||||
settings = "Settings",
|
settings = "Settings",
|
||||||
profile = "Profile",
|
profile = "Profile",
|
||||||
createMap = "Create a Map",
|
invite = "Invite",
|
||||||
aboutRoom = "About the Room",
|
aboutRoom = "Credit",
|
||||||
globalMessages = "Global Messages",
|
globalMessages = "Global Messages",
|
||||||
contact = "Contact",
|
contact = "Contact",
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSubMenusStore() {
|
function createSubMenusStore() {
|
||||||
const { subscribe, update } = writable<string[]>([
|
const { subscribe, update } = writable<string[]>([
|
||||||
SubMenusInterface.settings,
|
|
||||||
SubMenusInterface.profile,
|
SubMenusInterface.profile,
|
||||||
SubMenusInterface.createMap,
|
|
||||||
SubMenusInterface.aboutRoom,
|
|
||||||
SubMenusInterface.globalMessages,
|
SubMenusInterface.globalMessages,
|
||||||
SubMenusInterface.contact,
|
SubMenusInterface.contact,
|
||||||
|
SubMenusInterface.settings,
|
||||||
|
SubMenusInterface.invite,
|
||||||
|
SubMenusInterface.aboutRoom,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -3,6 +3,7 @@ import { Subject } from "rxjs";
|
|||||||
import { iframeListener } from "../Api/IframeListener";
|
import { iframeListener } from "../Api/IframeListener";
|
||||||
import { touchScreenManager } from "../Touch/TouchScreenManager";
|
import { touchScreenManager } from "../Touch/TouchScreenManager";
|
||||||
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
||||||
|
import { ICON_URL } from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
enum iframeStates {
|
enum iframeStates {
|
||||||
closed = 1,
|
closed = 1,
|
||||||
@ -10,9 +11,12 @@ enum iframeStates {
|
|||||||
opened,
|
opened,
|
||||||
}
|
}
|
||||||
|
|
||||||
const cowebsiteDivId = "cowebsite"; // the id of the whole container.
|
const cowebsiteDomId = "cowebsite"; // the id of the whole container.
|
||||||
const cowebsiteMainDomId = "cowebsite-main"; // the id of the parent div of the iframe.
|
const cowebsiteContainerDomId = "cowebsite-container"; // the id of the whole container.
|
||||||
|
const cowebsiteMainDomId = "cowebsite-slot-0"; // the id of the parent div of the iframe.
|
||||||
|
const cowebsiteBufferDomId = "cowebsite-buffer"; // the id of the container who contains cowebsite iframes.
|
||||||
const cowebsiteAsideDomId = "cowebsite-aside"; // the id of the parent div of the iframe.
|
const cowebsiteAsideDomId = "cowebsite-aside"; // the id of the parent div of the iframe.
|
||||||
|
const cowebsiteSubIconsDomId = "cowebsite-sub-icons";
|
||||||
export const cowebsiteCloseButtonId = "cowebsite-close";
|
export const cowebsiteCloseButtonId = "cowebsite-close";
|
||||||
const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
|
const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
|
||||||
const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
|
const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
|
||||||
@ -24,8 +28,19 @@ interface TouchMoveCoordinates {
|
|||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CoWebsite = {
|
||||||
|
iframe: HTMLIFrameElement;
|
||||||
|
icon: HTMLDivElement;
|
||||||
|
position: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CoWebsiteSlot = {
|
||||||
|
container: HTMLElement;
|
||||||
|
position: number;
|
||||||
|
};
|
||||||
|
|
||||||
class CoWebsiteManager {
|
class CoWebsiteManager {
|
||||||
private opened: iframeStates = iframeStates.closed;
|
private openedMain: iframeStates = iframeStates.closed;
|
||||||
|
|
||||||
private _onResize: Subject<void> = new Subject();
|
private _onResize: Subject<void> = new Subject();
|
||||||
public onResize = this._onResize.asObservable();
|
public onResize = this._onResize.asObservable();
|
||||||
@ -34,30 +49,41 @@ class CoWebsiteManager {
|
|||||||
* So we use this promise to queue up every cowebsite state transition
|
* So we use this promise to queue up every cowebsite state transition
|
||||||
*/
|
*/
|
||||||
private currentOperationPromise: Promise<void> = Promise.resolve();
|
private currentOperationPromise: Promise<void> = Promise.resolve();
|
||||||
private cowebsiteDiv: HTMLDivElement;
|
private cowebsiteDom: HTMLDivElement;
|
||||||
|
private cowebsiteContainerDom: HTMLDivElement;
|
||||||
private resizing: boolean = false;
|
private resizing: boolean = false;
|
||||||
private cowebsiteMainDom: HTMLDivElement;
|
private cowebsiteMainDom: HTMLDivElement;
|
||||||
|
private cowebsiteBufferDom: HTMLDivElement;
|
||||||
private cowebsiteAsideDom: HTMLDivElement;
|
private cowebsiteAsideDom: HTMLDivElement;
|
||||||
|
private cowebsiteSubIconsDom: HTMLDivElement;
|
||||||
private previousTouchMoveCoordinates: TouchMoveCoordinates | null = null; //only use on touchscreens to track touch movement
|
private previousTouchMoveCoordinates: TouchMoveCoordinates | null = null; //only use on touchscreens to track touch movement
|
||||||
|
|
||||||
|
private coWebsites: CoWebsite[] = [];
|
||||||
|
|
||||||
|
private slots: CoWebsiteSlot[];
|
||||||
|
|
||||||
|
private resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
this.resizeAllIframes();
|
||||||
|
});
|
||||||
|
|
||||||
get width(): number {
|
get width(): number {
|
||||||
return this.cowebsiteDiv.clientWidth;
|
return this.cowebsiteDom.clientWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
set width(width: number) {
|
set width(width: number) {
|
||||||
this.cowebsiteDiv.style.width = width + "px";
|
this.cowebsiteDom.style.width = width + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
set widthPercent(width: number) {
|
set widthPercent(width: number) {
|
||||||
this.cowebsiteDiv.style.width = width + "%";
|
this.cowebsiteDom.style.width = width + "%";
|
||||||
}
|
}
|
||||||
|
|
||||||
get height(): number {
|
get height(): number {
|
||||||
return this.cowebsiteDiv.clientHeight;
|
return this.cowebsiteDom.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
set height(height: number) {
|
set height(height: number) {
|
||||||
this.cowebsiteDiv.style.height = height + "px";
|
this.cowebsiteDom.style.height = height + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
get verticalMode(): boolean {
|
get verticalMode(): boolean {
|
||||||
@ -69,19 +95,59 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
this.cowebsiteDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDomId);
|
||||||
|
this.cowebsiteContainerDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteContainerDomId);
|
||||||
this.cowebsiteMainDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteMainDomId);
|
this.cowebsiteMainDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteMainDomId);
|
||||||
|
this.cowebsiteBufferDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteBufferDomId);
|
||||||
this.cowebsiteAsideDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteAsideDomId);
|
this.cowebsiteAsideDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteAsideDomId);
|
||||||
|
this.cowebsiteSubIconsDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteSubIconsDomId);
|
||||||
|
this.initResizeListeners(touchScreenManager.supportTouchScreen);
|
||||||
|
|
||||||
if (touchScreenManager.supportTouchScreen) {
|
this.resizeObserver.observe(this.cowebsiteDom);
|
||||||
this.initResizeListeners(true);
|
this.resizeObserver.observe(this.cowebsiteContainerDom);
|
||||||
|
|
||||||
|
this.slots = [
|
||||||
|
{
|
||||||
|
container: this.cowebsiteMainDom,
|
||||||
|
position: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
container: HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite-slot-1"),
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
container: HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite-slot-2"),
|
||||||
|
position: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
container: HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite-slot-3"),
|
||||||
|
position: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
container: HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite-slot-4"),
|
||||||
|
position: 4,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
this.slots.forEach((slot) => {
|
||||||
|
this.resizeObserver.observe(slot.container);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.initActionsListeners();
|
||||||
|
|
||||||
|
const buttonCloseCoWebsites = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||||
|
buttonCloseCoWebsites.addEventListener("click", () => {
|
||||||
|
if (this.isSmallScreen() && this.coWebsites.length > 1) {
|
||||||
|
const coWebsite = this.getCoWebsiteByPosition(0);
|
||||||
|
|
||||||
|
if (coWebsite) {
|
||||||
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.initResizeListeners(false);
|
|
||||||
|
|
||||||
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
buttonCloseCoWebsites.blur();
|
||||||
buttonCloseFrame.addEventListener("click", () => {
|
this.closeCoWebsites();
|
||||||
buttonCloseFrame.blur();
|
|
||||||
this.closeCoWebsite();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
||||||
@ -91,6 +157,19 @@ class CoWebsiteManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getDevicePixelRatio(): number {
|
||||||
|
//on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels
|
||||||
|
//so on chrome-based browser we need to adjust using 'devicePixelRatio'
|
||||||
|
return window.navigator.userAgent.includes("Firefox") ? 1 : window.devicePixelRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSmallScreen(): boolean {
|
||||||
|
return (
|
||||||
|
window.matchMedia("(max-aspect-ratio: 1/1)").matches ||
|
||||||
|
window.matchMedia("(max-width:960px) and (max-height:768px)").matches
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private initResizeListeners(touchMode: boolean) {
|
private initResizeListeners(touchMode: boolean) {
|
||||||
const movecallback = (event: MouseEvent | TouchEvent) => {
|
const movecallback = (event: MouseEvent | TouchEvent) => {
|
||||||
let x, y;
|
let x, y;
|
||||||
@ -111,8 +190,8 @@ class CoWebsiteManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.cowebsiteAsideDom.addEventListener(touchMode ? "touchstart" : "mousedown", (event) => {
|
this.cowebsiteAsideDom.addEventListener(touchMode ? "touchstart" : "mousedown", (event) => {
|
||||||
|
this.cowebsiteMainDom.style.display = "none";
|
||||||
this.resizing = true;
|
this.resizing = true;
|
||||||
this.getIframeDom().style.display = "none";
|
|
||||||
if (touchMode) {
|
if (touchMode) {
|
||||||
const touchEvent = (event as TouchEvent).touches[0];
|
const touchEvent = (event as TouchEvent).touches[0];
|
||||||
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
|
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
|
||||||
@ -127,43 +206,243 @@ class CoWebsiteManager {
|
|||||||
this.previousTouchMoveCoordinates = null;
|
this.previousTouchMoveCoordinates = null;
|
||||||
}
|
}
|
||||||
document.removeEventListener(touchMode ? "touchmove" : "mousemove", movecallback);
|
document.removeEventListener(touchMode ? "touchmove" : "mousemove", movecallback);
|
||||||
this.getIframeDom().style.display = "block";
|
this.cowebsiteMainDom.style.display = "block";
|
||||||
this.resizing = false;
|
this.resizing = false;
|
||||||
|
this.cowebsiteMainDom.style.display = "flex";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDevicePixelRatio(): number {
|
private closeMain(): void {
|
||||||
//on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels
|
this.cowebsiteDom.classList.remove("loaded"); //edit the css class to trigger the transition
|
||||||
//so on chrome-based browser we need to adjust using 'devicePixelRatio'
|
this.cowebsiteDom.classList.add("hidden");
|
||||||
return window.navigator.userAgent.includes("Firefox") ? 1 : window.devicePixelRatio;
|
this.openedMain = iframeStates.closed;
|
||||||
|
this.resetStyleMain();
|
||||||
|
this.cowebsiteDom.style.display = "none";
|
||||||
|
}
|
||||||
|
private loadMain(): void {
|
||||||
|
this.cowebsiteDom.style.display = "flex";
|
||||||
|
this.cowebsiteDom.classList.remove("hidden"); //edit the css class to trigger the transition
|
||||||
|
this.cowebsiteDom.classList.add("loading");
|
||||||
|
this.openedMain = iframeStates.loading;
|
||||||
|
}
|
||||||
|
private openMain(): void {
|
||||||
|
this.cowebsiteDom.classList.remove("loading", "hidden"); //edit the css class to trigger the transition
|
||||||
|
this.openedMain = iframeStates.opened;
|
||||||
|
this.resetStyleMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private close(): void {
|
public resetStyleMain() {
|
||||||
this.cowebsiteDiv.classList.remove("loaded"); //edit the css class to trigger the transition
|
this.cowebsiteDom.style.width = "";
|
||||||
this.cowebsiteDiv.classList.add("hidden");
|
this.cowebsiteDom.style.height = "";
|
||||||
this.opened = iframeStates.closed;
|
|
||||||
this.resetStyle();
|
|
||||||
}
|
|
||||||
private load(): void {
|
|
||||||
this.cowebsiteDiv.classList.remove("hidden"); //edit the css class to trigger the transition
|
|
||||||
this.cowebsiteDiv.classList.add("loading");
|
|
||||||
this.opened = iframeStates.loading;
|
|
||||||
}
|
|
||||||
private open(): void {
|
|
||||||
this.cowebsiteDiv.classList.remove("loading", "hidden"); //edit the css class to trigger the transition
|
|
||||||
this.opened = iframeStates.opened;
|
|
||||||
this.resetStyle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetStyle() {
|
private initActionsListeners() {
|
||||||
this.cowebsiteDiv.style.width = "";
|
this.slots.forEach((slot: CoWebsiteSlot) => {
|
||||||
this.cowebsiteDiv.style.height = "";
|
const expandButton = slot.container.querySelector(".expand");
|
||||||
|
const highlightButton = slot.container.querySelector(".hightlight");
|
||||||
|
const closeButton = slot.container.querySelector(".close");
|
||||||
|
|
||||||
|
if (expandButton) {
|
||||||
|
expandButton.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const coWebsite = this.getCoWebsiteByPosition(slot.position);
|
||||||
|
|
||||||
|
if (!coWebsite) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getIframeDom(): HTMLIFrameElement {
|
this.moveRightPreviousCoWebsite(coWebsite, 0);
|
||||||
const iframe = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId).querySelector("iframe");
|
});
|
||||||
if (!iframe) throw new Error("Could not find iframe!");
|
}
|
||||||
return iframe;
|
|
||||||
|
if (highlightButton) {
|
||||||
|
highlightButton.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const coWebsite = this.getCoWebsiteByPosition(slot.position);
|
||||||
|
|
||||||
|
if (!coWebsite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveRightPreviousCoWebsite(coWebsite, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closeButton) {
|
||||||
|
closeButton.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const coWebsite = this.getCoWebsiteByPosition(slot.position);
|
||||||
|
|
||||||
|
if (!coWebsite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCoWebsites(): CoWebsite[] {
|
||||||
|
return this.coWebsites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined {
|
||||||
|
return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSlotByPosition(position: number): CoWebsiteSlot | undefined {
|
||||||
|
return this.slots.find((slot: CoWebsiteSlot) => slot.position === position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCoWebsiteByPosition(position: number): CoWebsite | undefined {
|
||||||
|
return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.position === position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setIframeOffset(coWebsite: CoWebsite, slot: CoWebsiteSlot) {
|
||||||
|
const bounding = slot.container.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (coWebsite.iframe.classList.contains("thumbnail")) {
|
||||||
|
coWebsite.iframe.style.width = (bounding.right - bounding.left) * 2 + "px";
|
||||||
|
coWebsite.iframe.style.height = (bounding.bottom - bounding.top) * 2 + "px";
|
||||||
|
coWebsite.iframe.style.top = bounding.top - Math.floor(bounding.height * 0.5) + "px";
|
||||||
|
coWebsite.iframe.style.left = bounding.left - Math.floor(bounding.width * 0.5) + "px";
|
||||||
|
} else {
|
||||||
|
coWebsite.iframe.style.top = bounding.top + "px";
|
||||||
|
coWebsite.iframe.style.left = bounding.left + "px";
|
||||||
|
coWebsite.iframe.style.width = bounding.right - bounding.left + "px";
|
||||||
|
coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private resizeAllIframes() {
|
||||||
|
this.coWebsites.forEach((coWebsite: CoWebsite) => {
|
||||||
|
const slot = this.getSlotByPosition(coWebsite.position);
|
||||||
|
|
||||||
|
if (slot) {
|
||||||
|
this.setIframeOffset(coWebsite, slot);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveCoWebsite(coWebsite: CoWebsite, newPosition: number) {
|
||||||
|
const oldSlot = this.getSlotByPosition(coWebsite.position);
|
||||||
|
const newSlot = this.getSlotByPosition(newPosition);
|
||||||
|
|
||||||
|
if (!newSlot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
coWebsite.iframe.scrolling = newPosition === 0 || newPosition === 1 ? "yes" : "no";
|
||||||
|
|
||||||
|
if (newPosition === 0) {
|
||||||
|
coWebsite.iframe.classList.add("main");
|
||||||
|
coWebsite.icon.style.display = "none";
|
||||||
|
} else {
|
||||||
|
coWebsite.iframe.classList.remove("main");
|
||||||
|
coWebsite.icon.style.display = "flex";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPosition === 1) {
|
||||||
|
coWebsite.iframe.classList.add("sub-main");
|
||||||
|
} else {
|
||||||
|
coWebsite.iframe.classList.remove("sub-main");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPosition >= 2) {
|
||||||
|
coWebsite.iframe.classList.add("thumbnail");
|
||||||
|
} else {
|
||||||
|
coWebsite.iframe.classList.remove("thumbnail");
|
||||||
|
}
|
||||||
|
|
||||||
|
coWebsite.position = newPosition;
|
||||||
|
|
||||||
|
if (oldSlot && !this.getCoWebsiteByPosition(oldSlot.position)) {
|
||||||
|
oldSlot.container.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
newSlot.container.style.display = "block";
|
||||||
|
|
||||||
|
coWebsite.iframe.classList.remove("pixel");
|
||||||
|
|
||||||
|
this.resizeAllIframes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveLeftPreviousCoWebsite(coWebsite: CoWebsite, newPosition: number) {
|
||||||
|
const nextCoWebsite = this.getCoWebsiteByPosition(coWebsite.position + 1);
|
||||||
|
|
||||||
|
this.moveCoWebsite(coWebsite, newPosition);
|
||||||
|
|
||||||
|
if (nextCoWebsite) {
|
||||||
|
this.moveLeftPreviousCoWebsite(nextCoWebsite, nextCoWebsite.position - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveRightPreviousCoWebsite(coWebsite: CoWebsite, newPosition: number) {
|
||||||
|
if (newPosition >= 5) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentCoWebsite = this.getCoWebsiteByPosition(newPosition);
|
||||||
|
|
||||||
|
this.moveCoWebsite(coWebsite, newPosition);
|
||||||
|
|
||||||
|
if (newPosition === 4 || !currentCoWebsite || currentCoWebsite.iframe.id === coWebsite.iframe.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentCoWebsite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveRightPreviousCoWebsite(currentCoWebsite, currentCoWebsite.position + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeCoWebsiteFromStack(coWebsite: CoWebsite) {
|
||||||
|
this.coWebsites = this.coWebsites.filter(
|
||||||
|
(coWebsiteToRemove: CoWebsite) => coWebsiteToRemove.iframe.id !== coWebsite.iframe.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.coWebsites.length < 1) {
|
||||||
|
this.closeMain();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coWebsite.position > 0) {
|
||||||
|
const slot = this.getSlotByPosition(coWebsite.position);
|
||||||
|
if (slot) {
|
||||||
|
slot.container.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousCoWebsite = this.coWebsites.find(
|
||||||
|
(coWebsiteToCheck: CoWebsite) => coWebsite.position + 1 === coWebsiteToCheck.position
|
||||||
|
);
|
||||||
|
|
||||||
|
if (previousCoWebsite) {
|
||||||
|
this.moveLeftPreviousCoWebsite(previousCoWebsite, coWebsite.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
coWebsite.icon.remove();
|
||||||
|
coWebsite.iframe.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public searchJitsi(): CoWebsite | undefined {
|
||||||
|
return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.iframe.id.toLowerCase().includes("jitsi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateCoWebsiteIcon(iframe: HTMLIFrameElement): HTMLDivElement {
|
||||||
|
const icon = document.createElement("div");
|
||||||
|
icon.id = "cowebsite-icon-" + iframe.id;
|
||||||
|
icon.style.display = "none";
|
||||||
|
|
||||||
|
const iconImage = document.createElement("img");
|
||||||
|
iconImage.src = `${ICON_URL}/icon?url=${iframe.src}&size=16..30..256`;
|
||||||
|
const url = new URL(iframe.src);
|
||||||
|
iconImage.alt = url.hostname;
|
||||||
|
|
||||||
|
icon.appendChild(iconImage);
|
||||||
|
|
||||||
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadCoWebsite(
|
public loadCoWebsite(
|
||||||
@ -171,89 +450,149 @@ class CoWebsiteManager {
|
|||||||
base: string,
|
base: string,
|
||||||
allowApi?: boolean,
|
allowApi?: boolean,
|
||||||
allowPolicy?: string,
|
allowPolicy?: string,
|
||||||
widthPercent?: number
|
widthPercent?: number,
|
||||||
): void {
|
position?: number
|
||||||
this.load();
|
): Promise<CoWebsite> {
|
||||||
this.cowebsiteMainDom.innerHTML = ``;
|
return this.addCoWebsite(
|
||||||
|
(iframeBuffer) => {
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
iframe.id = "cowebsite-iframe";
|
|
||||||
iframe.src = new URL(url, base).toString();
|
iframe.src = new URL(url, base).toString();
|
||||||
|
|
||||||
if (allowPolicy) {
|
if (allowPolicy) {
|
||||||
iframe.allow = allowPolicy;
|
iframe.allow = allowPolicy;
|
||||||
}
|
}
|
||||||
const onloadPromise = new Promise<void>((resolve) => {
|
|
||||||
iframe.onload = () => resolve();
|
|
||||||
});
|
|
||||||
if (allowApi) {
|
if (allowApi) {
|
||||||
iframeListener.registerIframe(iframe);
|
iframeListener.registerIframe(iframe);
|
||||||
}
|
}
|
||||||
this.cowebsiteMainDom.appendChild(iframe);
|
|
||||||
|
iframeBuffer.appendChild(iframe);
|
||||||
|
|
||||||
|
return iframe;
|
||||||
|
},
|
||||||
|
widthPercent,
|
||||||
|
position
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async addCoWebsite(
|
||||||
|
callback: (iframeBuffer: HTMLDivElement) => PromiseLike<HTMLIFrameElement> | HTMLIFrameElement,
|
||||||
|
widthPercent?: number,
|
||||||
|
position?: number
|
||||||
|
): Promise<CoWebsite> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (this.coWebsites.length < 1) {
|
||||||
|
this.loadMain();
|
||||||
|
} else if (this.coWebsites.length === 5) {
|
||||||
|
throw new Error("Too many we");
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.resolve(callback(this.cowebsiteBufferDom)).then((iframe) => {
|
||||||
|
iframe?.classList.add("pixel");
|
||||||
|
|
||||||
|
if (!iframe.id) {
|
||||||
|
do {
|
||||||
|
iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
|
||||||
|
} while (this.getCoWebsiteById(iframe.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
const onloadPromise = new Promise<void>((resolve) => {
|
||||||
|
iframe.onload = () => resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
const icon = this.generateCoWebsiteIcon(iframe);
|
||||||
|
|
||||||
|
const coWebsite = {
|
||||||
|
iframe,
|
||||||
|
icon,
|
||||||
|
position: position ?? this.coWebsites.length,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iframe management on mobile
|
||||||
|
icon.addEventListener("click", () => {
|
||||||
|
if (this.isSmallScreen()) {
|
||||||
|
this.moveRightPreviousCoWebsite(coWebsite, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.coWebsites.push(coWebsite);
|
||||||
|
this.cowebsiteSubIconsDom.appendChild(icon);
|
||||||
|
|
||||||
const onTimeoutPromise = new Promise<void>((resolve) => {
|
const onTimeoutPromise = new Promise<void>((resolve) => {
|
||||||
setTimeout(() => resolve(), 2000);
|
setTimeout(() => resolve(), 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.currentOperationPromise = this.currentOperationPromise
|
this.currentOperationPromise = this.currentOperationPromise
|
||||||
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.open();
|
if (coWebsite.position === 0) {
|
||||||
|
this.openMain();
|
||||||
if (widthPercent) {
|
if (widthPercent) {
|
||||||
this.widthPercent = widthPercent;
|
this.widthPercent = widthPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
|
position !== undefined
|
||||||
|
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
|
||||||
|
: this.moveCoWebsite(coWebsite, coWebsite.position);
|
||||||
}, animationTime);
|
}, animationTime);
|
||||||
|
} else {
|
||||||
|
position !== undefined
|
||||||
|
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
|
||||||
|
: this.moveCoWebsite(coWebsite, coWebsite.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(coWebsite);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Error loadCoWebsite => ", err);
|
console.error("Error loadCoWebsite => ", err);
|
||||||
this.closeCoWebsite();
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
|
return reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public closeCoWebsite(coWebsite: CoWebsite): Promise<void> {
|
||||||
* Just like loadCoWebsite but the div can be filled by the user.
|
|
||||||
*/
|
|
||||||
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>, widthPercent?: number): void {
|
|
||||||
this.load();
|
|
||||||
this.cowebsiteMainDom.innerHTML = ``;
|
|
||||||
this.currentOperationPromise = this.currentOperationPromise
|
|
||||||
.then(() => callback(this.cowebsiteMainDom))
|
|
||||||
.then(() => {
|
|
||||||
this.open();
|
|
||||||
if (widthPercent) {
|
|
||||||
this.widthPercent = widthPercent;
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
this.fire();
|
|
||||||
}, animationTime);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("Error insertCoWebsite => ", err);
|
|
||||||
this.closeCoWebsite();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeCoWebsite(): Promise<void> {
|
|
||||||
this.currentOperationPromise = this.currentOperationPromise.then(
|
this.currentOperationPromise = this.currentOperationPromise.then(
|
||||||
() =>
|
() =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve) => {
|
||||||
if (this.opened === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example
|
if (this.coWebsites.length === 1) {
|
||||||
this.close();
|
if (this.openedMain === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example
|
||||||
|
this.closeMain();
|
||||||
this.fire();
|
this.fire();
|
||||||
const iframe = this.cowebsiteDiv.querySelector("iframe");
|
|
||||||
if (iframe) {
|
|
||||||
iframeListener.unregisterIframe(iframe);
|
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
|
||||||
this.cowebsiteMainDom.innerHTML = ``;
|
if (coWebsite) {
|
||||||
|
iframeListener.unregisterIframe(coWebsite.iframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
resolve();
|
resolve();
|
||||||
}, animationTime);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return this.currentOperationPromise;
|
return this.currentOperationPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public closeJitsi() {
|
||||||
|
const jitsi = this.searchJitsi();
|
||||||
|
if (jitsi) {
|
||||||
|
this.closeCoWebsite(jitsi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeCoWebsites(): Promise<void> {
|
||||||
|
this.currentOperationPromise = this.currentOperationPromise.then(() => {
|
||||||
|
this.coWebsites.forEach((coWebsite: CoWebsite) => {
|
||||||
|
this.closeCoWebsite(coWebsite);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return this.currentOperationPromise;
|
||||||
|
}
|
||||||
|
|
||||||
public getGameSize(): { width: number; height: number } {
|
public getGameSize(): { width: number; height: number } {
|
||||||
if (this.opened !== iframeStates.opened) {
|
if (this.openedMain !== iframeStates.opened) {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
@ -279,7 +618,7 @@ class CoWebsiteManager {
|
|||||||
|
|
||||||
private fullscreen(): void {
|
private fullscreen(): void {
|
||||||
if (this.isFullScreen) {
|
if (this.isFullScreen) {
|
||||||
this.resetStyle();
|
this.resetStyleMain();
|
||||||
this.fire();
|
this.fire();
|
||||||
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = "inline";
|
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = "inline";
|
||||||
|
@ -141,7 +141,7 @@ class JitsiFactory {
|
|||||||
jitsiUrl?: string,
|
jitsiUrl?: string,
|
||||||
jitsiWidth?: number
|
jitsiWidth?: number
|
||||||
): void {
|
): void {
|
||||||
coWebsiteManager.insertCoWebsite(async (cowebsiteDiv) => {
|
coWebsiteManager.addCoWebsite(async (cowebsiteDiv) => {
|
||||||
// Jitsi meet external API maintains some data in local storage
|
// Jitsi meet external API maintains some data in local storage
|
||||||
// which is sent via the appData URL parameter when joining a
|
// which is sent via the appData URL parameter when joining a
|
||||||
// conference. Problem is that this data grows indefinitely. Thus
|
// conference. Problem is that this data grows indefinitely. Thus
|
||||||
@ -170,22 +170,35 @@ class JitsiFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
options.onload = () => resolve(); //we want for the iframe to be loaded before triggering animations.
|
const doResolve = (): void => {
|
||||||
setTimeout(() => resolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
const iframe = cowebsiteDiv.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
||||||
|
if (iframe === null) {
|
||||||
|
throw new Error("Could not find Jitsi Iframe");
|
||||||
|
}
|
||||||
|
resolve(iframe);
|
||||||
|
}
|
||||||
|
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
|
||||||
|
setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
||||||
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
||||||
this.jitsiApi.executeCommand("displayName", playerName);
|
this.jitsiApi.executeCommand("displayName", playerName);
|
||||||
|
|
||||||
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
||||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
||||||
});
|
});
|
||||||
}, jitsiWidth);
|
}, jitsiWidth, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async stop(): Promise<void> {
|
public stop() {
|
||||||
if (!this.jitsiApi) {
|
if (!this.jitsiApi) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await coWebsiteManager.closeCoWebsite();
|
|
||||||
|
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
|
||||||
|
|
||||||
|
if (jitsiCoWebsite) {
|
||||||
|
coWebsiteManager.closeJitsi();
|
||||||
|
}
|
||||||
|
|
||||||
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
|
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
|
||||||
this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback);
|
this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback);
|
||||||
this.jitsiApi?.dispose();
|
this.jitsiApi?.dispose();
|
||||||
|
@ -14,13 +14,4 @@ export enum DivImportance {
|
|||||||
|
|
||||||
export const ON_ACTION_TRIGGER_BUTTON = "onaction";
|
export const ON_ACTION_TRIGGER_BUTTON = "onaction";
|
||||||
|
|
||||||
export const TRIGGER_WEBSITE_PROPERTIES = "openWebsiteTrigger";
|
|
||||||
export const TRIGGER_JITSI_PROPERTIES = "jitsiTrigger";
|
|
||||||
|
|
||||||
export const WEBSITE_MESSAGE_PROPERTIES = "openWebsiteTriggerMessage";
|
|
||||||
export const JITSI_MESSAGE_PROPERTIES = "jitsiTriggerMessage";
|
|
||||||
|
|
||||||
export const AUDIO_VOLUME_PROPERTY = "audioVolume";
|
|
||||||
export const AUDIO_LOOP_PROPERTY = "audioLoop";
|
|
||||||
|
|
||||||
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };
|
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };
|
||||||
|
@ -141,7 +141,7 @@ const game = new Game(config);
|
|||||||
waScaleManager.setGame(game);
|
waScaleManager.setGame(game);
|
||||||
|
|
||||||
window.addEventListener("resize", function (event) {
|
window.addEventListener("resize", function (event) {
|
||||||
coWebsiteManager.resetStyle();
|
coWebsiteManager.resetStyleMain();
|
||||||
|
|
||||||
waScaleManager.applyNewSize();
|
waScaleManager.applyNewSize();
|
||||||
});
|
});
|
||||||
|
@ -25,26 +25,112 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
aside {
|
aside {
|
||||||
height: 30px;
|
height: 50px;
|
||||||
min-height: 30px;
|
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
#cowebsite-aside-holder {
|
||||||
|
pointer-events: none;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-sub-icons {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 0;
|
||||||
|
height: 100%;
|
||||||
|
visibility: visible;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
cursor: pointer !important;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-aside-buttons {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-fullscreen {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-right-btn {
|
||||||
|
img {
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:960px) and (max-height:768px) {
|
||||||
|
#cowebsite {
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
#cowebsite-sub-icons {
|
||||||
|
display: inline-flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 0;
|
||||||
|
height: 100%;
|
||||||
|
visibility: visible;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 28px;
|
||||||
|
width: 28px;
|
||||||
|
cursor: pointer !important;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-right-btn {
|
|
||||||
&#cowebsite-close {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
&#cowebsite-fullscreen {
|
|
||||||
left: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#cowebsite {
|
#cowebsite {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
z-index: 200;
|
||||||
transition: transform 0.5s;
|
transition: transform 0.5s;
|
||||||
background-color: white;
|
background-color: whitesmoke;
|
||||||
|
display: none;
|
||||||
|
|
||||||
&.loading {
|
&.loading {
|
||||||
background-color: gray;
|
background-color: gray;
|
||||||
@ -22,30 +24,163 @@
|
|||||||
background: gray;
|
background: gray;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
img {
|
#cowebsite-aside-holder {
|
||||||
margin: 3px;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 80%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cowebsite-aside-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: auto;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
.top-right-btn{
|
.top-right-btn{
|
||||||
position: absolute;
|
transform: scale(0.5);
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||||
|
|
||||||
img {
|
|
||||||
height: 25px;
|
|
||||||
padding: 4px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img:hover {
|
#cowebsite-sub-icons {
|
||||||
background-color: rgba(0,0,0,0.4);
|
display: flex;
|
||||||
|
margin-top: auto;
|
||||||
|
visibility: hidden;
|
||||||
|
justify-content: end;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&-main {
|
||||||
|
padding: 2% 5%;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-sub {
|
||||||
|
position: absolute !important;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
bottom: 23%;
|
||||||
|
height: 20% !important;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-slot-0 {
|
||||||
|
z-index: 70 !important;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from 1 through 4 {
|
||||||
|
&-slot-#{$i} {
|
||||||
|
transition: transform 0.5s;
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
display: none;
|
||||||
|
background-color: #333333;
|
||||||
|
|
||||||
|
@if $i == 1 {
|
||||||
|
width: 100%;
|
||||||
|
} @else {
|
||||||
|
width: 33%;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 50;
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.actions-move {
|
||||||
|
display: none;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
gap: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba($color: #333333, $alpha: 0.6);
|
||||||
|
|
||||||
|
.actions-move {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
pointer-events: all !important;
|
||||||
|
margin: 3% 2%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: end;
|
||||||
|
position: relative;
|
||||||
|
z-index: 50;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
margin: 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-buffer {
|
||||||
|
iframe {
|
||||||
|
z-index: 45 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
pointer-events: all !important;
|
||||||
|
z-index: 205 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-main {
|
||||||
|
pointer-events: all !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
transform: scale(0.5, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pixel {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 1px;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-aspect-ratio: 1/1) {
|
@media (min-aspect-ratio: 1/1) {
|
||||||
@ -54,7 +189,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: none;
|
||||||
|
|
||||||
&.loading {
|
&.loading {
|
||||||
transform: translateX(90%);
|
transform: translateX(90%);
|
||||||
@ -77,15 +212,5 @@
|
|||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-right-btn{
|
|
||||||
left: -6px;
|
|
||||||
&#cowebsite-close {
|
|
||||||
top: 0px;
|
|
||||||
}
|
|
||||||
&#cowebsite-fullscreen {
|
|
||||||
top: 25px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1111,3 +1111,18 @@ div.emoji-picker {
|
|||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.noselect {
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-khtml-user-select: none; /* Konqueror HTML */
|
||||||
|
-moz-user-select: none; /* Old versions of Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none; /* Non-prefixed version, currently
|
||||||
|
supported by Chrome, Edge, Opera and Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.pixel {
|
||||||
|
height: 1px !important;
|
||||||
|
width: 1px !important;
|
||||||
|
}
|
||||||
|
@ -7,7 +7,12 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
x: 100, y: 200
|
x: 100, y: 200
|
||||||
}, 42000,
|
}, 42000,
|
||||||
{
|
{
|
||||||
x: 200, y: 100, moving: true, direction: "up"
|
x: 200,
|
||||||
|
y: 100,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
|
moving: true,
|
||||||
|
direction: "up"
|
||||||
},
|
},
|
||||||
42200
|
42200
|
||||||
);
|
);
|
||||||
@ -19,6 +24,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
expect(playerMovement.getPosition(42100)).toEqual({
|
expect(playerMovement.getPosition(42100)).toEqual({
|
||||||
x: 150,
|
x: 150,
|
||||||
y: 150,
|
y: 150,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: 'up',
|
||||||
moving: true
|
moving: true
|
||||||
});
|
});
|
||||||
@ -26,6 +33,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
expect(playerMovement.getPosition(42200)).toEqual({
|
expect(playerMovement.getPosition(42200)).toEqual({
|
||||||
x: 200,
|
x: 200,
|
||||||
y: 100,
|
y: 100,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: 'up',
|
||||||
moving: true
|
moving: true
|
||||||
});
|
});
|
||||||
@ -33,6 +42,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
expect(playerMovement.getPosition(42300)).toEqual({
|
expect(playerMovement.getPosition(42300)).toEqual({
|
||||||
x: 250,
|
x: 250,
|
||||||
y: 50,
|
y: 50,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: 'up',
|
||||||
moving: true
|
moving: true
|
||||||
});
|
});
|
||||||
@ -43,7 +54,12 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
x: 100, y: 200
|
x: 100, y: 200
|
||||||
}, 42000,
|
}, 42000,
|
||||||
{
|
{
|
||||||
x: 200, y: 100, moving: false, direction: "up"
|
x: 200,
|
||||||
|
y: 100,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
|
moving: false,
|
||||||
|
direction: "up"
|
||||||
},
|
},
|
||||||
42200
|
42200
|
||||||
);
|
);
|
||||||
@ -51,6 +67,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
expect(playerMovement.getPosition(42300)).toEqual({
|
expect(playerMovement.getPosition(42300)).toEqual({
|
||||||
x: 200,
|
x: 200,
|
||||||
y: 100,
|
y: 100,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: 'up',
|
||||||
moving: false
|
moving: false
|
||||||
});
|
});
|
||||||
@ -61,7 +79,12 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
x: 100, y: 200
|
x: 100, y: 200
|
||||||
}, 42000,
|
}, 42000,
|
||||||
{
|
{
|
||||||
x: 200, y: 100, moving: false, direction: "up"
|
x: 200,
|
||||||
|
y: 100,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
|
moving: false,
|
||||||
|
direction: "up"
|
||||||
},
|
},
|
||||||
42200
|
42200
|
||||||
);
|
);
|
||||||
@ -69,6 +92,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
expect(playerMovement.getPosition(42100)).toEqual({
|
expect(playerMovement.getPosition(42100)).toEqual({
|
||||||
x: 150,
|
x: 150,
|
||||||
y: 150,
|
y: 150,
|
||||||
|
oldX: 100,
|
||||||
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: 'up',
|
||||||
moving: true
|
moving: true
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,6 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
|||||||
import sveltePreprocess from "svelte-preprocess";
|
import sveltePreprocess from "svelte-preprocess";
|
||||||
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
|
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
|
||||||
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
|
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
|
||||||
import { POSTHOG_API_KEY, PROFILE_URL } from "./src/Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
const mode = process.env.NODE_ENV ?? "development";
|
const mode = process.env.NODE_ENV ?? "development";
|
||||||
const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS;
|
const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS;
|
||||||
@ -193,6 +192,7 @@ module.exports = {
|
|||||||
ADMIN_URL: undefined,
|
ADMIN_URL: undefined,
|
||||||
CONTACT_URL: null,
|
CONTACT_URL: null,
|
||||||
PROFILE_URL: null,
|
PROFILE_URL: null,
|
||||||
|
ICON_URL: null,
|
||||||
DEBUG_MODE: null,
|
DEBUG_MODE: null,
|
||||||
STUN_SERVER: null,
|
STUN_SERVER: null,
|
||||||
TURN_SERVER: null,
|
TURN_SERVER: null,
|
||||||
@ -207,6 +207,8 @@ module.exports = {
|
|||||||
POSTHOG_API_KEY: null,
|
POSTHOG_API_KEY: null,
|
||||||
POSTHOG_URL: null,
|
POSTHOG_URL: null,
|
||||||
NODE_ENV: mode,
|
NODE_ENV: mode,
|
||||||
|
DISABLE_ANONYMOUS: false,
|
||||||
|
OPID_LOGIN_SCREEN_PROVIDER: null,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
} as Configuration & WebpackDevServer.Configuration;
|
} as Configuration & WebpackDevServer.Configuration;
|
||||||
|
617
maps/tests/ChangeLayerApi/change_layer_api.json
Normal file
617
maps/tests/ChangeLayerApi/change_layer_api.json
Normal file
@ -0,0 +1,617 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23],
|
||||||
|
"height":10,
|
||||||
|
"id":5,
|
||||||
|
"name":"myLayer",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":111.874771331266,
|
||||||
|
"id":1,
|
||||||
|
"name":"Tests",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":8,
|
||||||
|
"text":"Test 1:\nGo on the blue carpet.\nResult:\nA message has been sent to the chat.\n\nTest 2:\nGo outside the blue carpet.\nResult:\nAnother message has been sent to the chat.\n",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":316.770833333333,
|
||||||
|
"x":1.64026713939023,
|
||||||
|
"y":206.086424886945
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 27, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":8,
|
||||||
|
"name":"objects",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":9,
|
||||||
|
"nextobjectid":3,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"script",
|
||||||
|
"type":"string",
|
||||||
|
"value":"script.js"
|
||||||
|
}],
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.2",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"..\/tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"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":5,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":6,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":7,
|
||||||
|
"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":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
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":21,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":23,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":24,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":25,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":26,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":27,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":28,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":29,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":30,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":31,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":32,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":34,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":35,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":42,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":43,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":45,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":46,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":59,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":60,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":70,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":71,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":80,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":81,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":89,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":91,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":93,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":94,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":95,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":96,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":97,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":100,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":102,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":103,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":104,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":105,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":106,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":107,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":108,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":114,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":115,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
7
maps/tests/ChangeLayerApi/script.js
Normal file
7
maps/tests/ChangeLayerApi/script.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
WA.room.onEnterLayer('myLayer').subscribe(() => {
|
||||||
|
WA.chat.sendChatMessage("Hello!", 'Wooka');
|
||||||
|
});
|
||||||
|
|
||||||
|
WA.room.onLeaveLayer('myLayer').subscribe(() => {
|
||||||
|
WA.chat.sendChatMessage("Goodbye!", 'Wooka');
|
||||||
|
});
|
640
maps/tests/CoWebsite/cowebsite_api.json
Normal file
640
maps/tests/CoWebsite/cowebsite_api.json
Normal file
@ -0,0 +1,640 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23],
|
||||||
|
"height":10,
|
||||||
|
"id":5,
|
||||||
|
"name":"first_cowebsite",
|
||||||
|
"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, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"second_cowebsite",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"jitsiRoom",
|
||||||
|
"type":"string",
|
||||||
|
"value":"ChillZone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"jitsiTrigger",
|
||||||
|
"type":"string",
|
||||||
|
"value":"onaction"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":220.405430001517,
|
||||||
|
"id":1,
|
||||||
|
"name":"Tests",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":8,
|
||||||
|
"text":"Test 1:\nEnter \/cowebsite open https:\/\/wikipedia.com on the chat\nResult:\nA cowebsite must have been opened\n\nDo the first test 4 more times\n\nTest 2:\nEnter \/cowebsite close 0 on the chat\nResult:\nThe main co-website has been closed\n\nTest 3:\nEnter \/cowebsite close all on the chat\nResult:\nAll co-websites has been closed\n\nTest 4:\nGo on the white carpet to open a Jitsi & open a co-website \/cowebsite open https:\/\/wikipedia.com on the chat\nResult:\nThere are two co-websites",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":316.770833333333,
|
||||||
|
"x":1.64026713939023,
|
||||||
|
"y":97.5557662166938
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 27, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":8,
|
||||||
|
"name":"objects",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":9,
|
||||||
|
"nextobjectid":3,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"script",
|
||||||
|
"type":"string",
|
||||||
|
"value":"script.js"
|
||||||
|
}],
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.2",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"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":5,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":6,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":7,
|
||||||
|
"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":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
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":21,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":23,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":24,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":25,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":26,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":27,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":28,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":29,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":30,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":31,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":32,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":34,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":35,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":42,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":43,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":45,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":46,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":59,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":60,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":70,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":71,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":80,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":81,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":89,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":91,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":93,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":94,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":95,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":96,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":97,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":100,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":102,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":103,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":104,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":105,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":106,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":107,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":108,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":114,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":115,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
118
maps/tests/CoWebsite/cowebsite_jitsiroom.json
Normal file
118
maps/tests/CoWebsite/cowebsite_jitsiroom.json
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23],
|
||||||
|
"height":10,
|
||||||
|
"id":5,
|
||||||
|
"name":"jitsiRoom",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"jitsiRoom",
|
||||||
|
"type":"string",
|
||||||
|
"value":"testJitsiRoomCoWebsite"
|
||||||
|
}],
|
||||||
|
"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, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"openWebsite",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"https:\/\/workadventu.re\/"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":141,
|
||||||
|
"id":1,
|
||||||
|
"name":"Tests",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":11,
|
||||||
|
"text":"Test:\nWalk on the blue carpet, an iframe open, walk on the white carpet another one to open another one\nResult:\n2 co-websites must be opened\n\nTest:\nGo outside of carpets\nResult:\nAll co-websites must disapeared",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":316.770833333333,
|
||||||
|
"x":0.28125,
|
||||||
|
"y":187.833333333333
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":8,
|
||||||
|
"nextobjectid":3,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.2",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
118
maps/tests/CoWebsite/cowebsite_property.json
Normal file
118
maps/tests/CoWebsite/cowebsite_property.json
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23],
|
||||||
|
"height":10,
|
||||||
|
"id":5,
|
||||||
|
"name":"first_cowebsite",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"https:\/\/wikipedia.org"
|
||||||
|
}],
|
||||||
|
"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, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"second_cowebsite",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"https:\/\/workadventu.re\/"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":141,
|
||||||
|
"id":1,
|
||||||
|
"name":"Tests",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":11,
|
||||||
|
"text":"Test:\nWalk on the blue carpet, an iframe open, walk on the white carpet another one to open another one\nResult:\n2 co-websites must be opened\n\nTest:\nGo outside of carpets\nResult:\nAll co-websites must disapeared",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":316.770833333333,
|
||||||
|
"x":0.28125,
|
||||||
|
"y":187.833333333333
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":8,
|
||||||
|
"nextobjectid":3,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.1",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
108
maps/tests/CoWebsite/script.js
Normal file
108
maps/tests/CoWebsite/script.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
WA.onInit().then(() => {
|
||||||
|
WA.chat.onChatMessage((message) => {
|
||||||
|
|
||||||
|
if (!message.startsWith('/')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitedMessage = message.trim().split(' ');
|
||||||
|
const command = splitedMessage.shift().substr(1);
|
||||||
|
|
||||||
|
executeCommand(command, splitedMessage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function wookaSendMessage(message) {
|
||||||
|
WA.chat.sendChatMessage(message, 'Wooka');
|
||||||
|
}
|
||||||
|
|
||||||
|
function unknownCommand() {
|
||||||
|
wookaSendMessage('Unknown command');
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeCommand(command, args) {
|
||||||
|
switch(command) {
|
||||||
|
case 'cowebsite':
|
||||||
|
coWebsiteCommand(args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unknownCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function coWebsiteCommand(args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
wookaSendMessage('Too few arguments');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subCommand = args.shift();
|
||||||
|
|
||||||
|
switch(subCommand) {
|
||||||
|
case 'open':
|
||||||
|
openCoWebsite(args);
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
closeCoWebsite(args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unknownCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openCoWebsite(args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
wookaSendMessage('Too few arguments');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = new URL(args[0]);
|
||||||
|
} catch (exception) {
|
||||||
|
wookaSendMessage('Parameter is not a valid URL !');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await WA.nav.openCoWebSite(args[0]).then(() => {
|
||||||
|
wookaSendMessage('Co-website has been opened !');
|
||||||
|
}).catch((error) => {
|
||||||
|
wookaSendMessage(`Something wrong happen during co-website opening: ${error.message}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function closeCoWebsite(args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
wookaSendMessage('Too few arguments');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coWebsites = await WA.nav.getCoWebSites();
|
||||||
|
|
||||||
|
// All
|
||||||
|
if (args[0] === "all" || args[0] === "*") {
|
||||||
|
coWebsites.forEach(coWebsite => {
|
||||||
|
coWebsite.close();
|
||||||
|
});
|
||||||
|
wookaSendMessage('All co-websites has been closed !');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const position = parseInt(args[0]);
|
||||||
|
|
||||||
|
// By ID or Position
|
||||||
|
const coWebsite =
|
||||||
|
isNaN(position) ?
|
||||||
|
coWebsites.find((coWebsite) => coWebsite.id === args[0]) :
|
||||||
|
coWebsites.find((coWebsite) => coWebsite.position === position);
|
||||||
|
|
||||||
|
if (!coWebsite) {
|
||||||
|
wookaSendMessage('Unknown co-website');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await coWebsite.close().then(() => {
|
||||||
|
wookaSendMessage('This co-websites has been closed !');
|
||||||
|
}).catch((error) => {
|
||||||
|
wookaSendMessage(`Something wrong happen during co-website closing: ${error.message}`);
|
||||||
|
});
|
||||||
|
}
|
BIN
maps/tests/CoWebsite/tileset1.png
Normal file
BIN
maps/tests/CoWebsite/tileset1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
167
maps/tests/exit1.json
Normal file
167
maps/tests/exit1.json
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"walls",
|
||||||
|
"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, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":8,
|
||||||
|
"name":"exit",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"exitUrl",
|
||||||
|
"type":"string",
|
||||||
|
"value":"exit2.json"
|
||||||
|
}],
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":"from_exit2",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"startLayer",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":263.008397229317,
|
||||||
|
"id":1,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"You are on Map 1\n\nTest:\nWalk through the exit.\n\nResult:\nYou should arrive to Map 2\n",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":249.954975648686,
|
||||||
|
"x":35.2740564642832,
|
||||||
|
"y":34.4372323693377
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":10,
|
||||||
|
"nextobjectid":2,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"2021.03.23",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.5,
|
||||||
|
"width":10
|
||||||
|
}
|
149
maps/tests/exit2.json
Normal file
149
maps/tests/exit2.json
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"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, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"walls",
|
||||||
|
"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, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":8,
|
||||||
|
"name":"exit",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"exitUrl",
|
||||||
|
"type":"string",
|
||||||
|
"value":"exit1.json#from_exit2"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":263.008397229317,
|
||||||
|
"id":1,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"You are on Map 2\n\nTest:\nWalk back through the exit.\n\nResult:\nYou should arrive back to Map 1\n",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":249.954975648686,
|
||||||
|
"x":35.2740564642832,
|
||||||
|
"y":34.4372323693377
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":9,
|
||||||
|
"nextobjectid":2,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"2021.03.23",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.5,
|
||||||
|
"width":10
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
|
||||||
|
<title>Map Tests</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -55,6 +56,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="start-tile.json#S2" target="_blank">Test start tile (S2)</a>
|
<a href="#" class="testLink" data-testmap="start-tile.json#S2" target="_blank">Test start tile (S2)</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-exits"> Success <input type="radio" name="test-exits"> Failure <input type="radio" name="test-exits" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="exit1.json" target="_blank">Test exits</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio" name="test-start-tile-s1tos2"> Success <input type="radio" name="test-start-tile-s1tos2"> Failure <input type="radio" name="test-start-tile-s1tos2" checked> Pending
|
<input type="radio" name="test-start-tile-s1tos2"> Success <input type="radio" name="test-start-tile-s1tos2"> Failure <input type="radio" name="test-start-tile-s1tos2" checked> Pending
|
||||||
@ -226,6 +235,41 @@
|
|||||||
<a href="#" class="testLink" data-testmap="EmbeddedWebsite/website_in_map_script.json" target="_blank">Testing scripting API for websites inside a map</a>
|
<a href="#" class="testLink" data-testmap="EmbeddedWebsite/website_in_map_script.json" target="_blank">Testing scripting API for websites inside a map</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-change-layer-api"> Success <input type="radio" name="test-change-layer-api"> Failure <input type="radio" name="test-change-layer-api" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="ChangeLayerApi/change_layer_api.json" target="_blank">Testing scripting API for enters/leaves layer</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h2>CoWebsite</h2>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-cowebsite-property"> Success <input type="radio" name="test-cowebsite-property"> Failure <input type="radio" name="test-cowebsite-property" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="CoWebsite/cowebsite_property.json" target="_blank">Open co-websites by map property</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-cowebsite-api"> Success <input type="radio" name="test-cowebsite-api"> Failure <input type="radio" name="test-cowebsite-api" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="CoWebsite/cowebsite_api.json" target="_blank">Open co-websites by scripting api</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-cowebsite_jitsiroom-layer-properties"> Success <input type="radio" name="test-cowebsite_jitsiroom-layer-properties"> Failure <input type="radio" name="test-cowebsite_jitsiroom-layer-properties" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="CoWebsite/cowebsite_jitsiroom.json" target="_blank">Open co-websites and Jitsi room by layer properties</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h2>Mobile</h2>
|
<h2>Mobile</h2>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
@ -40,6 +40,7 @@ WA.chat.onChatMessage((message => {
|
|||||||
|
|
||||||
WA.room.onEnterZone('myTrigger', () => {
|
WA.room.onEnterZone('myTrigger', () => {
|
||||||
WA.chat.sendChatMessage("Don't step on my carpet!", 'Poly Parrot');
|
WA.chat.sendChatMessage("Don't step on my carpet!", 'Poly Parrot');
|
||||||
|
WA.chat.sendChatMessage("Yeah, don't step on her carpet!", 'Peter Parrot');
|
||||||
})
|
})
|
||||||
|
|
||||||
WA.room.onLeaveZone('popupZone', () => {
|
WA.room.onLeaveZone('popupZone', () => {
|
||||||
|
@ -98,7 +98,7 @@
|
|||||||
{
|
{
|
||||||
"fontfamily":"Sans Serif",
|
"fontfamily":"Sans Serif",
|
||||||
"pixelsize":11,
|
"pixelsize":11,
|
||||||
"text":"Test:\nWalk on top carpet\nResult:\nA message \"Don't step on my carpet\" is displayed",
|
"text":"Test:\nWalk on top carpet\nResult:\nA message \"Don't step on my carpet\" is displayed from Poly Parrot and another message from Peter Parrot",
|
||||||
"wrap":true
|
"wrap":true
|
||||||
},
|
},
|
||||||
"type":"",
|
"type":"",
|
||||||
|
@ -6,6 +6,7 @@ import { PrometheusController } from "./Controller/PrometheusController";
|
|||||||
import { DebugController } from "./Controller/DebugController";
|
import { DebugController } from "./Controller/DebugController";
|
||||||
import { App as uwsApp } from "./Server/sifrr.server";
|
import { App as uwsApp } from "./Server/sifrr.server";
|
||||||
import { AdminController } from "./Controller/AdminController";
|
import { AdminController } from "./Controller/AdminController";
|
||||||
|
import { OpenIdProfileController } from "./Controller/OpenIdProfileController";
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
public app: uwsApp;
|
public app: uwsApp;
|
||||||
@ -15,6 +16,7 @@ class App {
|
|||||||
public prometheusController: PrometheusController;
|
public prometheusController: PrometheusController;
|
||||||
private debugController: DebugController;
|
private debugController: DebugController;
|
||||||
private adminController: AdminController;
|
private adminController: AdminController;
|
||||||
|
private openIdProfileController: OpenIdProfileController;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.app = new uwsApp();
|
this.app = new uwsApp();
|
||||||
@ -26,6 +28,7 @@ class App {
|
|||||||
this.prometheusController = new PrometheusController(this.app);
|
this.prometheusController = new PrometheusController(this.app);
|
||||||
this.debugController = new DebugController(this.app);
|
this.debugController = new DebugController(this.app);
|
||||||
this.adminController = new AdminController(this.app);
|
this.adminController = new AdminController(this.app);
|
||||||
|
this.openIdProfileController = new OpenIdProfileController(this.app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
|||||||
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
||||||
import { parse } from "query-string";
|
import { parse } from "query-string";
|
||||||
import { openIDClient } from "../Services/OpenIDClient";
|
import { openIDClient } from "../Services/OpenIDClient";
|
||||||
|
import { DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
export interface TokenInterface {
|
export interface TokenInterface {
|
||||||
userUuid: string;
|
userUuid: string;
|
||||||
@ -62,21 +63,13 @@ export class AuthenticateController extends BaseController {
|
|||||||
if (token != undefined) {
|
if (token != undefined) {
|
||||||
try {
|
try {
|
||||||
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
if (authTokenData.hydraAccessToken == undefined) {
|
if (authTokenData.accessToken == undefined) {
|
||||||
throw Error("Token cannot to be check on Hydra");
|
throw Error("Token cannot to be check on Hydra");
|
||||||
}
|
}
|
||||||
await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken);
|
const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
||||||
|
|
||||||
//Get user data from Admin Back Office
|
|
||||||
//This is very important to create User Local in LocalStorage in WorkAdventure
|
|
||||||
const data = await this.getUserByUserIdentifier(
|
|
||||||
authTokenData.identifier,
|
|
||||||
playUri as string,
|
|
||||||
IPAddress
|
|
||||||
);
|
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
return res.end(JSON.stringify({ ...data, authToken: token }));
|
return res.end(JSON.stringify({ ...resCheckTokenAuth, authToken: token }));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.info("User was not connected", err);
|
console.info("User was not connected", err);
|
||||||
}
|
}
|
||||||
@ -113,10 +106,10 @@ export class AuthenticateController extends BaseController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
if (authTokenData.hydraAccessToken == undefined) {
|
if (authTokenData.accessToken == undefined) {
|
||||||
throw Error("Token cannot to be logout on Hydra");
|
throw Error("Token cannot to be logout on Hydra");
|
||||||
}
|
}
|
||||||
await openIDClient.logoutUser(authTokenData.hydraAccessToken);
|
await openIDClient.logoutUser(authTokenData.accessToken);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("openIDCallback => logout-callback", error);
|
console.error("openIDCallback => logout-callback", error);
|
||||||
} finally {
|
} finally {
|
||||||
@ -189,6 +182,10 @@ export class AuthenticateController extends BaseController {
|
|||||||
console.warn("Login request was aborted");
|
console.warn("Login request was aborted");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (DISABLE_ANONYMOUS) {
|
||||||
|
res.writeStatus("403 FORBIDDEN");
|
||||||
|
res.end();
|
||||||
|
} else {
|
||||||
const userUuid = v4();
|
const userUuid = v4();
|
||||||
const authToken = jwtTokenManager.createAuthToken(userUuid);
|
const authToken = jwtTokenManager.createAuthToken(userUuid);
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
@ -199,6 +196,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
userUuid,
|
userUuid,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,20 +208,20 @@ export class AuthenticateController extends BaseController {
|
|||||||
res.onAborted(() => {
|
res.onAborted(() => {
|
||||||
console.warn("/message request was aborted");
|
console.warn("/message request was aborted");
|
||||||
});
|
});
|
||||||
const { userIdentify, token } = parse(req.getQuery());
|
const { token } = parse(req.getQuery());
|
||||||
try {
|
try {
|
||||||
//verify connected by token
|
//verify connected by token
|
||||||
if (token != undefined) {
|
if (token != undefined) {
|
||||||
try {
|
try {
|
||||||
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
if (authTokenData.hydraAccessToken == undefined) {
|
if (authTokenData.accessToken == undefined) {
|
||||||
throw Error("Token cannot to be check on Hydra");
|
throw Error("Token cannot to be check on Hydra");
|
||||||
}
|
}
|
||||||
await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken);
|
await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
||||||
|
|
||||||
//get login profile
|
//get login profile
|
||||||
res.writeStatus("302");
|
res.writeStatus("302");
|
||||||
res.writeHeader("Location", adminApi.getProfileUrl(authTokenData.hydraAccessToken));
|
res.writeHeader("Location", adminApi.getProfileUrl(authTokenData.accessToken));
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
// eslint-disable-next-line no-unsafe-finally
|
// eslint-disable-next-line no-unsafe-finally
|
||||||
return res.end();
|
return res.end();
|
||||||
|
@ -26,7 +26,7 @@ import { jwtTokenManager, tokenInvalidException } from "../Services/JWTTokenMana
|
|||||||
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
||||||
import { SocketManager, socketManager } from "../Services/SocketManager";
|
import { SocketManager, socketManager } from "../Services/SocketManager";
|
||||||
import { emitInBatch } from "../Services/IoSocketHelpers";
|
import { emitInBatch } from "../Services/IoSocketHelpers";
|
||||||
import { ADMIN_SOCKETS_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
import { ADMIN_SOCKETS_TOKEN, ADMIN_API_URL, DISABLE_ANONYMOUS, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "_Model/Zone";
|
||||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
import { CharacterTexture } from "../Services/AdminApi/CharacterTexture";
|
import { CharacterTexture } from "../Services/AdminApi/CharacterTexture";
|
||||||
@ -176,6 +176,11 @@ export class IoSocketController {
|
|||||||
|
|
||||||
const tokenData =
|
const tokenData =
|
||||||
token && typeof token === "string" ? jwtTokenManager.verifyJWTToken(token) : null;
|
token && typeof token === "string" ? jwtTokenManager.verifyJWTToken(token) : null;
|
||||||
|
|
||||||
|
if (DISABLE_ANONYMOUS && !tokenData) {
|
||||||
|
throw new Error("Expecting token");
|
||||||
|
}
|
||||||
|
|
||||||
const userIdentifier = tokenData ? tokenData.identifier : "";
|
const userIdentifier = tokenData ? tokenData.identifier : "";
|
||||||
|
|
||||||
let memberTags: string[] = [];
|
let memberTags: string[] = [];
|
||||||
|
@ -2,9 +2,9 @@ import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js";
|
|||||||
import { BaseController } from "./BaseController";
|
import { BaseController } from "./BaseController";
|
||||||
import { parse } from "query-string";
|
import { parse } from "query-string";
|
||||||
import { adminApi } from "../Services/AdminApi";
|
import { adminApi } from "../Services/AdminApi";
|
||||||
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL, DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable";
|
||||||
import { GameRoomPolicyTypes } from "../Model/PusherRoom";
|
import { GameRoomPolicyTypes } from "../Model/PusherRoom";
|
||||||
import { MapDetailsData } from "../Services/AdminApi/MapDetailsData";
|
import { isMapDetailsData, MapDetailsData } from "../Services/AdminApi/MapDetailsData";
|
||||||
import { socketManager } from "../Services/SocketManager";
|
import { socketManager } from "../Services/SocketManager";
|
||||||
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
@ -64,6 +64,7 @@ export class MapController extends BaseController {
|
|||||||
tags: [],
|
tags: [],
|
||||||
textures: [],
|
textures: [],
|
||||||
contactPage: undefined,
|
contactPage: undefined,
|
||||||
|
authenticationMandatory: DISABLE_ANONYMOUS,
|
||||||
} as MapDetailsData)
|
} as MapDetailsData)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -87,6 +88,10 @@ export class MapController extends BaseController {
|
|||||||
}
|
}
|
||||||
const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId);
|
const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId);
|
||||||
|
|
||||||
|
if (isMapDetailsData(mapDetails) && DISABLE_ANONYMOUS) {
|
||||||
|
mapDetails.authenticationMandatory = true;
|
||||||
|
}
|
||||||
|
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
res.end(JSON.stringify(mapDetails));
|
res.end(JSON.stringify(mapDetails));
|
||||||
|
80
pusher/src/Controller/OpenIdProfileController.ts
Normal file
80
pusher/src/Controller/OpenIdProfileController.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { BaseController } from "./BaseController";
|
||||||
|
import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js";
|
||||||
|
import { parse } from "query-string";
|
||||||
|
import { openIDClient } from "../Services/OpenIDClient";
|
||||||
|
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
||||||
|
import { adminApi } from "../Services/AdminApi";
|
||||||
|
import { OPID_CLIENT_ISSUER } from "../Enum/EnvironmentVariable";
|
||||||
|
import { IntrospectionResponse } from "openid-client";
|
||||||
|
|
||||||
|
export class OpenIdProfileController extends BaseController {
|
||||||
|
constructor(private App: TemplatedApp) {
|
||||||
|
super();
|
||||||
|
this.profileOpenId();
|
||||||
|
}
|
||||||
|
|
||||||
|
profileOpenId() {
|
||||||
|
//eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
this.App.get("/profile", async (res: HttpResponse, req: HttpRequest) => {
|
||||||
|
res.onAborted(() => {
|
||||||
|
console.warn("/message request was aborted");
|
||||||
|
});
|
||||||
|
|
||||||
|
const { accessToken } = parse(req.getQuery());
|
||||||
|
if (!accessToken) {
|
||||||
|
throw Error("Access token expected cannot to be check on Hydra");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const resCheckTokenAuth = await openIDClient.checkTokenAuth(accessToken as string);
|
||||||
|
if (!resCheckTokenAuth.email) {
|
||||||
|
throw "Email was not found";
|
||||||
|
}
|
||||||
|
res.end(
|
||||||
|
this.buildHtml(
|
||||||
|
OPID_CLIENT_ISSUER,
|
||||||
|
resCheckTokenAuth.email as string,
|
||||||
|
resCheckTokenAuth.picture as string | undefined
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("profileCallback => ERROR", error);
|
||||||
|
this.errorToResponse(error, res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
buildHtml(domain: string, email: string, pictureUrl?: string) {
|
||||||
|
return `
|
||||||
|
<!DOCTYPE>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
*{
|
||||||
|
font-family: PixelFont-7, monospace;
|
||||||
|
}
|
||||||
|
body{
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
section{
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<section>
|
||||||
|
<img src="${pictureUrl ? pictureUrl : "/images/profile"}">
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
Profile validated by domain: <span style="font-weight: bold">${domain}</span>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
Your email: <span style="font-weight: bold">${email}</span>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,9 @@ export const FRONT_URL = process.env.FRONT_URL || "http://localhost";
|
|||||||
export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || "";
|
export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || "";
|
||||||
export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || "";
|
export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || "";
|
||||||
export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || "";
|
export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || "";
|
||||||
|
export const OPID_CLIENT_REDIRECT_URL = process.env.OPID_CLIENT_REDIRECT_URL || FRONT_URL + "/jwt";
|
||||||
|
export const OPID_PROFILE_SCREEN_PROVIDER = process.env.OPID_PROFILE_SCREEN_PROVIDER || ADMIN_URL + "/profile";
|
||||||
|
export const DISABLE_ANONYMOUS = process.env.DISABLE_ANONYMOUS || false;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SECRET_KEY,
|
SECRET_KEY,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL, OPID_PROFILE_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import { GameRoomPolicyTypes } from "_Model/PusherRoom";
|
import { GameRoomPolicyTypes } from "_Model/PusherRoom";
|
||||||
import { CharacterTexture } from "./AdminApi/CharacterTexture";
|
import { CharacterTexture } from "./AdminApi/CharacterTexture";
|
||||||
@ -142,13 +142,19 @@ class AdminApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*TODO add constant to use profile companny*/
|
/**
|
||||||
|
*
|
||||||
|
* @param accessToken
|
||||||
|
*/
|
||||||
getProfileUrl(accessToken: string): string {
|
getProfileUrl(accessToken: string): string {
|
||||||
if (!ADMIN_URL) {
|
if (!OPID_PROFILE_SCREEN_PROVIDER) {
|
||||||
throw new Error("No admin backoffice set!");
|
throw new Error("No admin backoffice set!");
|
||||||
}
|
}
|
||||||
|
return `${OPID_PROFILE_SCREEN_PROVIDER}?accessToken=${accessToken}`;
|
||||||
|
}
|
||||||
|
|
||||||
return ADMIN_URL + `/profile?token=${accessToken}`;
|
async logoutOauth(token: string) {
|
||||||
|
await Axios.get(ADMIN_API_URL + `/oauth/logout?token=${token}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ export const isMapDetailsData = new tg.IsInterface()
|
|||||||
tags: tg.isArray(tg.isString),
|
tags: tg.isArray(tg.isString),
|
||||||
textures: tg.isArray(isCharacterTexture),
|
textures: tg.isArray(isCharacterTexture),
|
||||||
contactPage: tg.isUnion(tg.isString, tg.isUndefined),
|
contactPage: tg.isUnion(tg.isString, tg.isUndefined),
|
||||||
|
authenticationMandatory: tg.isUnion(tg.isBoolean, tg.isUndefined),
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { adminApi, AdminBannedData } from "../Services/AdminApi";
|
|||||||
|
|
||||||
export interface AuthTokenData {
|
export interface AuthTokenData {
|
||||||
identifier: string; //will be a email if logged in or an uuid if anonymous
|
identifier: string; //will be a email if logged in or an uuid if anonymous
|
||||||
hydraAccessToken?: string;
|
accessToken?: string;
|
||||||
}
|
}
|
||||||
export interface AdminSocketTokenData {
|
export interface AdminSocketTokenData {
|
||||||
authorizedRoomIds: string[]; //the list of rooms the client is authorized to read from.
|
authorizedRoomIds: string[]; //the list of rooms the client is authorized to read from.
|
||||||
@ -18,8 +18,8 @@ class JWTTokenManager {
|
|||||||
return Jwt.verify(token, ADMIN_SOCKETS_TOKEN) as AdminSocketTokenData;
|
return Jwt.verify(token, ADMIN_SOCKETS_TOKEN) as AdminSocketTokenData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createAuthToken(identifier: string, hydraAccessToken?: string) {
|
public createAuthToken(identifier: string, accessToken?: string) {
|
||||||
return Jwt.sign({ identifier, hydraAccessToken }, SECRET_KEY, { expiresIn: "30d" });
|
return Jwt.sign({ identifier, accessToken }, SECRET_KEY, { expiresIn: "30d" });
|
||||||
}
|
}
|
||||||
|
|
||||||
public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData {
|
public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData {
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import { Issuer, Client, IntrospectionResponse } from "openid-client";
|
import { Issuer, Client, IntrospectionResponse } from "openid-client";
|
||||||
import { OPID_CLIENT_ID, OPID_CLIENT_SECRET, OPID_CLIENT_ISSUER, FRONT_URL } from "../Enum/EnvironmentVariable";
|
import {
|
||||||
|
OPID_CLIENT_ID,
|
||||||
const opidRedirectUri = FRONT_URL + "/jwt";
|
OPID_CLIENT_SECRET,
|
||||||
|
OPID_CLIENT_ISSUER,
|
||||||
|
OPID_CLIENT_REDIRECT_URL,
|
||||||
|
} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
class OpenIDClient {
|
class OpenIDClient {
|
||||||
private issuerPromise: Promise<Client> | null = null;
|
private issuerPromise: Promise<Client> | null = null;
|
||||||
@ -12,7 +15,7 @@ class OpenIDClient {
|
|||||||
return new issuer.Client({
|
return new issuer.Client({
|
||||||
client_id: OPID_CLIENT_ID,
|
client_id: OPID_CLIENT_ID,
|
||||||
client_secret: OPID_CLIENT_SECRET,
|
client_secret: OPID_CLIENT_SECRET,
|
||||||
redirect_uris: [opidRedirectUri],
|
redirect_uris: [OPID_CLIENT_REDIRECT_URL],
|
||||||
response_types: ["code"],
|
response_types: ["code"],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -35,7 +38,7 @@ class OpenIDClient {
|
|||||||
|
|
||||||
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> {
|
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> {
|
||||||
return this.initClient().then((client) => {
|
return this.initClient().then((client) => {
|
||||||
return client.callback(opidRedirectUri, { code }, { nonce }).then((tokenSet) => {
|
return client.callback(OPID_CLIENT_REDIRECT_URL, { code }, { nonce }).then((tokenSet) => {
|
||||||
return client.userinfo(tokenSet).then((res) => {
|
return client.userinfo(tokenSet).then((res) => {
|
||||||
return {
|
return {
|
||||||
...res,
|
...res,
|
||||||
|
@ -231,12 +231,12 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
try {
|
try {
|
||||||
client.viewport = viewport;
|
client.viewport = viewport;
|
||||||
|
|
||||||
const world = this.rooms.get(client.roomId);
|
const room = this.rooms.get(client.roomId);
|
||||||
if (!world) {
|
if (!room) {
|
||||||
console.error("In SET_VIEWPORT, could not find world with id '", client.roomId, "'");
|
console.error("In SET_VIEWPORT, could not find world with id '", client.roomId, "'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
world.setViewport(client, client.viewport);
|
room.setViewport(client, client.viewport);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('An error occurred on "SET_VIEWPORT" event');
|
console.error('An error occurred on "SET_VIEWPORT" event');
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
Loading…
Reference in New Issue
Block a user