Merge branch 'develop' into vite
This commit is contained in:
commit
29cdb1a8e5
@ -1,20 +1,118 @@
|
|||||||
|
# Security
|
||||||
|
#
|
||||||
|
|
||||||
|
SECRET_KEY=
|
||||||
|
ADMIN_API_TOKEN=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Networking
|
||||||
|
#
|
||||||
|
|
||||||
# The base domain
|
# The base domain
|
||||||
DOMAIN=workadventure.localhost
|
DOMAIN=workadventure.localhost
|
||||||
|
|
||||||
DEBUG_MODE=false
|
# Subdomains
|
||||||
|
# MUST match the DOMAIN variable above
|
||||||
|
FRONT_HOST=front.workadventure.localhost
|
||||||
|
PUSHER_HOST=pusher.workadventure.localhost
|
||||||
|
BACK_HOST=api.workadventure.localhost
|
||||||
|
MAPS_HOST=maps.workadventure.localhost
|
||||||
|
ICON_HOST=icon.workadventure.localhost
|
||||||
|
|
||||||
|
# SAAS admin panel
|
||||||
|
ADMIN_API_URL=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Basic configuration
|
||||||
|
#
|
||||||
|
|
||||||
|
# The directory to store data in
|
||||||
|
DATA_DIR=./wa
|
||||||
|
|
||||||
|
# The URL used by default, in the form: "/_/global/map/url.json"
|
||||||
|
START_ROOM_URL=/_/global/maps.workadventu.re/Floor0/floor0.json
|
||||||
|
|
||||||
|
# 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=
|
||||||
|
|
||||||
|
MAX_PER_GROUP=4
|
||||||
|
MAX_USERNAME_LENGTH=8
|
||||||
|
DISABLE_ANONYMOUS=false
|
||||||
|
|
||||||
|
# The version of the docker image to use
|
||||||
|
# MUST uncomment "image" keys in the docker-compose file for it to be effective
|
||||||
|
VERSION=master
|
||||||
|
|
||||||
|
TZ=Europe/Paris
|
||||||
|
|
||||||
|
#
|
||||||
|
# Jitsi
|
||||||
|
#
|
||||||
|
|
||||||
JITSI_URL=meet.jit.si
|
JITSI_URL=meet.jit.si
|
||||||
# If your Jitsi environment has authentication set up, you MUST set JITSI_PRIVATE_MODE to "true" and you MUST pass a SECRET_JITSI_KEY to generate the JWT secret
|
# If your Jitsi environment has authentication set up,
|
||||||
|
# you MUST set JITSI_PRIVATE_MODE to "true"
|
||||||
|
# and you MUST pass a SECRET_JITSI_KEY to generate the JWT secret
|
||||||
JITSI_PRIVATE_MODE=false
|
JITSI_PRIVATE_MODE=false
|
||||||
JITSI_ISS=
|
JITSI_ISS=
|
||||||
SECRET_JITSI_KEY=
|
SECRET_JITSI_KEY=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Turn/Stun
|
||||||
|
#
|
||||||
|
|
||||||
# URL of the TURN server (needed to "punch a hole" through some networks for P2P connections)
|
# URL of the TURN server (needed to "punch a hole" through some networks for P2P connections)
|
||||||
TURN_SERVER=
|
TURN_SERVER=
|
||||||
TURN_USER=
|
TURN_USER=
|
||||||
TURN_PASSWORD=
|
TURN_PASSWORD=
|
||||||
|
# If your Turn server is configured to use the Turn REST API, you MUST put the shared auth secret here.
|
||||||
|
# If you are using Coturn, this is the value of the "static-auth-secret" parameter in your coturn config file.
|
||||||
|
# Keep empty if you are sharing hard coded / clear text credentials.
|
||||||
|
TURN_STATIC_AUTH_SECRET=
|
||||||
|
# URL of the STUN server
|
||||||
|
STUN_SERVER=
|
||||||
|
|
||||||
# The URL used by default, in the form: "/_/global/map/url.json"
|
#
|
||||||
START_ROOM_URL=/_/global/maps.workadventu.re/Floor0/floor0.json
|
# Certificate config
|
||||||
|
#
|
||||||
|
|
||||||
# The email address used by Let's encrypt to send renewal warnings (compulsory)
|
# The email address used by Let's encrypt to send renewal warnings (compulsory)
|
||||||
ACME_EMAIL=
|
ACME_EMAIL=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Additional app configs
|
||||||
|
# Configuration for apps which are not workadventure itself
|
||||||
|
#
|
||||||
|
|
||||||
|
# openID
|
||||||
|
OPID_CLIENT_ID=
|
||||||
|
OPID_CLIENT_SECRET=
|
||||||
|
OPID_CLIENT_ISSUER=
|
||||||
|
OPID_CLIENT_REDIRECT_URL=
|
||||||
|
OPID_LOGIN_SCREEN_PROVIDER=http://pusher.workadventure.localhost/login-screen
|
||||||
|
OPID_PROFILE_SCREEN_PROVIDER=
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Advanced configuration
|
||||||
|
# Generally does not need to be changed
|
||||||
|
#
|
||||||
|
|
||||||
|
# Networking
|
||||||
|
HTTP_PORT=80
|
||||||
|
HTTPS_PORT=443
|
||||||
|
|
||||||
|
# Workadventure settings
|
||||||
|
DISABLE_NOTIFICATIONS=false
|
||||||
|
SKIP_RENDER_OPTIMIZATIONS=false
|
||||||
|
STORE_VARIABLES_FOR_LOCAL_MAPS=true
|
||||||
|
|
||||||
|
# Debugging options
|
||||||
|
DEBUG_MODE=false
|
||||||
|
LOG_LEVEL=WARN
|
||||||
|
|
||||||
|
# Internal URLs
|
||||||
|
API_URL=back:50051
|
||||||
|
|
||||||
|
RESTART_POLICY=unless-stopped
|
||||||
|
@ -1,114 +1,128 @@
|
|||||||
version: "3.3"
|
version: "3.5"
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik:v2.3
|
image: traefik:v2.6
|
||||||
command:
|
command:
|
||||||
- --log.level=WARN
|
- --log.level=${LOG_LEVEL}
|
||||||
#- --api.insecure=true
|
|
||||||
- --providers.docker
|
- --providers.docker
|
||||||
- --entryPoints.web.address=:80
|
# Entry points
|
||||||
|
- --entryPoints.web.address=:${HTTP_PORT}
|
||||||
- --entrypoints.web.http.redirections.entryPoint.to=websecure
|
- --entrypoints.web.http.redirections.entryPoint.to=websecure
|
||||||
- --entrypoints.web.http.redirections.entryPoint.scheme=https
|
- --entrypoints.web.http.redirections.entryPoint.scheme=https
|
||||||
- --entryPoints.websecure.address=:443
|
- --entryPoints.websecure.address=:${HTTPS_PORT}
|
||||||
|
# HTTP challenge
|
||||||
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
|
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
|
||||||
- --certificatesresolvers.myresolver.acme.storage=/acme.json
|
- --certificatesresolvers.myresolver.acme.storage=/acme.json
|
||||||
# used during the challenge
|
|
||||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||||
|
# Let's Encrypt's staging server
|
||||||
|
# uncomment during testing to avoid rate limiting
|
||||||
|
#- --certificatesresolvers.dnsresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "${HTTP_PORT}:80"
|
||||||
- "443:443"
|
- "${HTTPS_PORT}:443"
|
||||||
# The Web UI (enabled by --api.insecure=true)
|
|
||||||
#- "8080:8080"
|
|
||||||
depends_on:
|
|
||||||
- pusher
|
|
||||||
- front
|
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ./acme.json:/acme.json
|
- ${DATA_DIR}/letsencrypt/acme.json:/acme.json
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
|
|
||||||
front:
|
front:
|
||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: front/Dockerfile
|
dockerfile: front/Dockerfile
|
||||||
#image: thecodingmachine/workadventure-front:master
|
#image: thecodingmachine/workadventure-front:${VERSION}
|
||||||
environment:
|
environment:
|
||||||
DEBUG_MODE: "$DEBUG_MODE"
|
- DEBUG_MODE
|
||||||
JITSI_URL: $JITSI_URL
|
- JITSI_URL
|
||||||
JITSI_PRIVATE_MODE: "$JITSI_PRIVATE_MODE"
|
- JITSI_PRIVATE_MODE
|
||||||
PUSHER_URL: //pusher.${DOMAIN}
|
- PUSHER_URL=//${PUSHER_HOST}
|
||||||
ICON_URL: //icon.${DOMAIN}
|
- ICON_URL=//${ICON_HOST}
|
||||||
TURN_SERVER: "${TURN_SERVER}"
|
- TURN_SERVER
|
||||||
TURN_USER: "${TURN_USER}"
|
- TURN_USER
|
||||||
TURN_PASSWORD: "${TURN_PASSWORD}"
|
- TURN_PASSWORD
|
||||||
START_ROOM_URL: "${START_ROOM_URL}"
|
- TURN_STATIC_AUTH_SECRET
|
||||||
|
- STUN_SERVER
|
||||||
|
- START_ROOM_URL
|
||||||
|
- SKIP_RENDER_OPTIMIZATIONS
|
||||||
|
- MAX_PER_GROUP
|
||||||
|
- MAX_USERNAME_LENGTH
|
||||||
|
- DISABLE_ANONYMOUS
|
||||||
|
- DISABLE_NOTIFICATIONS
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.front.rule=Host(`play.${DOMAIN}`)"
|
- "traefik.http.routers.front.rule=Host(`${FRONT_HOST}`)"
|
||||||
- "traefik.http.routers.front.entryPoints=web,traefik"
|
- "traefik.http.routers.front.entryPoints=web"
|
||||||
- "traefik.http.services.front.loadbalancer.server.port=80"
|
- "traefik.http.services.front.loadbalancer.server.port=80"
|
||||||
- "traefik.http.routers.front-ssl.rule=Host(`play.${DOMAIN}`)"
|
- "traefik.http.routers.front-ssl.rule=Host(`${FRONT_HOST}`)"
|
||||||
- "traefik.http.routers.front-ssl.entryPoints=websecure"
|
- "traefik.http.routers.front-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.front-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.front-ssl.service=front"
|
- "traefik.http.routers.front-ssl.service=front"
|
||||||
|
- "traefik.http.routers.front-ssl.tls=true"
|
||||||
- "traefik.http.routers.front-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.front-ssl.tls.certresolver=myresolver"
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
pusher:
|
pusher:
|
||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: pusher/Dockerfile
|
dockerfile: pusher/Dockerfile
|
||||||
#image: thecodingmachine/workadventure-pusher:master
|
#image: thecodingmachine/workadventure-pusher:${VERSION}
|
||||||
command: yarn run runprod
|
command: yarn run runprod
|
||||||
environment:
|
environment:
|
||||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
- SECRET_JITSI_KEY
|
||||||
SECRET_KEY: yourSecretKey
|
- SECRET_KEY
|
||||||
API_URL: back:50051
|
- API_URL
|
||||||
JITSI_URL: $JITSI_URL
|
- FRONT_URL=https://${FRONT_HOST}
|
||||||
JITSI_ISS: $JITSI_ISS
|
- JITSI_URL
|
||||||
FRONT_URL: https://play.${DOMAIN}
|
- JITSI_ISS
|
||||||
|
- DISABLE_ANONYMOUS
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.pusher.rule=Host(`pusher.${DOMAIN}`)"
|
- "traefik.http.routers.pusher.rule=Host(`${PUSHER_HOST}`)"
|
||||||
- "traefik.http.routers.pusher.entryPoints=web,traefik"
|
- "traefik.http.routers.pusher.entryPoints=web"
|
||||||
- "traefik.http.services.pusher.loadbalancer.server.port=8080"
|
- "traefik.http.services.pusher.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.pusher-ssl.rule=Host(`pusher.${DOMAIN}`)"
|
- "traefik.http.routers.pusher-ssl.rule=Host(${PUSHER_HOST}`)"
|
||||||
- "traefik.http.routers.pusher-ssl.entryPoints=websecure"
|
- "traefik.http.routers.pusher-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.pusher-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.pusher-ssl.service=pusher"
|
- "traefik.http.routers.pusher-ssl.service=pusher"
|
||||||
|
- "traefik.http.routers.pusher-ssl.tls=true"
|
||||||
- "traefik.http.routers.pusher-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.pusher-ssl.tls.certresolver=myresolver"
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
back:
|
back:
|
||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: back/Dockerfile
|
dockerfile: back/Dockerfile
|
||||||
#image: thecodingmachine/workadventure-back:master
|
#image: thecodingmachine/workadventure-back:${VERSION}
|
||||||
command: yarn run runprod
|
command: yarn run runprod
|
||||||
environment:
|
environment:
|
||||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
- SECRET_JITSI_KEY
|
||||||
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
- SECRET_KEY
|
||||||
ADMIN_API_URL: "$ADMIN_API_URL"
|
- ADMIN_API_TOKEN
|
||||||
JITSI_URL: $JITSI_URL
|
- ADMIN_API_URL
|
||||||
JITSI_ISS: $JITSI_ISS
|
- TURN_SERVER
|
||||||
|
- TURN_USER
|
||||||
|
- TURN_PASSWORD
|
||||||
|
- TURN_STATIC_AUTH_SECRET
|
||||||
|
- STUN_SERVER
|
||||||
|
- JITSI_URL
|
||||||
|
- JITSI_ISS
|
||||||
|
- MAX_PER_GROUP
|
||||||
|
- STORE_VARIABLES_FOR_LOCAL_MAPS
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.back.rule=Host(`api.${DOMAIN}`)"
|
- "traefik.http.routers.back.rule=Host(`${BACK_HOST}`)"
|
||||||
- "traefik.http.routers.back.entryPoints=web"
|
- "traefik.http.routers.back.entryPoints=web"
|
||||||
- "traefik.http.services.back.loadbalancer.server.port=8080"
|
- "traefik.http.services.back.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.back-ssl.rule=Host(`api.${DOMAIN}`)"
|
- "traefik.http.routers.back-ssl.rule=Host(`${BACK_HOST}`)"
|
||||||
- "traefik.http.routers.back-ssl.entryPoints=websecure"
|
- "traefik.http.routers.back-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.back-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.back-ssl.service=back"
|
- "traefik.http.routers.back-ssl.service=back"
|
||||||
|
- "traefik.http.routers.back-ssl.tls=true"
|
||||||
- "traefik.http.routers.back-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.back-ssl.tls.certresolver=myresolver"
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
icon:
|
icon:
|
||||||
image: matthiasluedtke/iconserver:v3.13.0
|
image: matthiasluedtke/iconserver:v3.13.0
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.icon.rule=Host(`icon.${DOMAIN}`)"
|
- "traefik.http.routers.icon.rule=Host(`${ICON_HOST}`)"
|
||||||
- "traefik.http.routers.icon.entryPoints=web,traefik"
|
- "traefik.http.routers.icon.entryPoints=web,traefik"
|
||||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.icon-ssl.rule=Host(`icon.${DOMAIN}`)"
|
- "traefik.http.routers.icon-ssl.rule=Host(`${ICON_HOST}`)"
|
||||||
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.icon-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.icon-ssl.service=icon"
|
- "traefik.http.routers.icon-ssl.service=icon"
|
||||||
|
- "traefik.http.routers.icon-ssl.tls=true"
|
||||||
- "traefik.http.routers.icon-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.icon-ssl.tls.certresolver=myresolver"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
### Opening a web page in a new tab
|
### Opening a web page in a new tab
|
||||||
|
|
||||||
```
|
```ts
|
||||||
WA.nav.openTab(url: string): void
|
WA.nav.openTab(url: string): void
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -11,13 +11,13 @@ Opens the webpage at "url" in your browser, in a new tab.
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```ts
|
||||||
WA.nav.openTab('https://www.wikipedia.org/');
|
WA.nav.openTab('https://www.wikipedia.org/');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Opening a web page in the current tab
|
### Opening a web page in the current tab
|
||||||
|
|
||||||
```
|
```ts
|
||||||
WA.nav.goToPage(url: string): void
|
WA.nav.goToPage(url: string): void
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -25,14 +25,13 @@ Opens the webpage at "url" in your browser in place of WorkAdventure. WorkAdvent
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```ts
|
||||||
WA.nav.goToPage('https://www.wikipedia.org/');
|
WA.nav.goToPage('https://www.wikipedia.org/');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Going to a different map from the script
|
### Going to a different map from the script
|
||||||
|
|
||||||
```
|
```ts
|
||||||
|
|
||||||
WA.nav.goToRoom(url: string): void
|
WA.nav.goToRoom(url: string): void
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ global urls: "/_/global/domain/path/map.json[#start-layer-name]"
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```ts
|
||||||
WA.nav.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls
|
WA.nav.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls
|
||||||
WA.nav.goToRoom('../otherMap/map.json');
|
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")
|
||||||
@ -51,25 +50,25 @@ WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
|
|||||||
|
|
||||||
### Opening/closing web page in Co-Websites
|
### Opening/closing web page in Co-Websites
|
||||||
|
|
||||||
```
|
```ts
|
||||||
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number, closable: boolean, lazy: boolean): Promise<CoWebsite>
|
WA.nav.openCoWebSite(url: string, allowApi?: boolean = false, allowPolicy?: string = "", percentWidth?: number, position?: number, closable?: boolean, lazy?: boolean): Promise<CoWebsite>
|
||||||
```
|
```
|
||||||
|
|
||||||
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, closable allow to close the webpage also you need to close it by the api and lazy
|
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),widthPercent define the width of the main cowebsite beetween the min size and the max size (70% of the viewport), position in whitch slot the web page will be open, closable allow to close the webpage also you need to close it by the api and lazy
|
||||||
it's to add the cowebsite but don't load it.
|
it's to add the cowebsite but don't load it.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```ts
|
||||||
const coWebsite = await 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, true, true);
|
const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 70, 1, true, true);
|
||||||
// ...
|
// ...
|
||||||
coWebsite.close();
|
coWebsite.close();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get all Co-Websites
|
### Get all Co-Websites
|
||||||
|
|
||||||
```
|
```ts
|
||||||
WA.nav.getCoWebSites(): Promise<CoWebsite[]>
|
WA.nav.getCoWebSites(): Promise<CoWebsite[]>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -77,6 +76,6 @@ Get all opened co-websites with their ids and positions.
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```javascript
|
```ts
|
||||||
const coWebsites = await WA.nav.getCowebSites();
|
const coWebsites = await WA.nav.getCowebSites();
|
||||||
```
|
```
|
||||||
|
@ -82,7 +82,11 @@ We are able to direct a Woka to the desired place immediately after spawn. To ma
|
|||||||
```
|
```
|
||||||
.../my_map.json#moveTo=meeting-room&start
|
.../my_map.json#moveTo=meeting-room&start
|
||||||
```
|
```
|
||||||
|
*...or even like this!*
|
||||||
|
```
|
||||||
|
.../my_map.json#start&moveTo=200,100
|
||||||
|
```
|
||||||
|
|
||||||
For this to work, moveTo must be equal to the layer name of interest. This layer should have at least one tile defined. In case of layer having many tiles, user will go to one of them, randomly selected.
|
For this to work, moveTo must be equal to the x and y position, layer name, or object name of interest. Layer should have at least one tile defined. In case of layer having many tiles, user will go to one of them, randomly selected.
|
||||||
|
|
||||||
![](images/moveTo-layer-example.png)
|
![](images/moveTo-layer-example.png)
|
BIN
docs/maps/images/icon_open_website.png
Normal file
BIN
docs/maps/images/icon_open_website.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
@ -52,6 +52,13 @@ If you set `openWebsiteTrigger: onaction`, when the user walks on the layer, an
|
|||||||
|
|
||||||
If you set `openWebsiteTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to open the web site'.
|
If you set `openWebsiteTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to open the web site'.
|
||||||
|
|
||||||
|
If you set `openWebsiteTrigger: onicon`, when the user walks on the layer, an icon will be displayed at the bottom of the screen:
|
||||||
|
|
||||||
|
<figure class="figure">
|
||||||
|
<img src="images/icon_open_website.png" class="figure-img img-fluid rounded" alt="" />
|
||||||
|
<figcaption class="figure-caption">The iFrame will only open if the user clicks on icon</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
### Setting the iFrame "allow" attribute
|
### Setting the iFrame "allow" attribute
|
||||||
|
|
||||||
By default, iFrames have limited rights in browsers. For instance, they cannot put their content in fullscreen, they cannot start your webcam, etc...
|
By default, iFrames have limited rights in browsers. For instance, they cannot put their content in fullscreen, they cannot start your webcam, etc...
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4
|
||||||
"plugins": ["prettier-plugin-svelte"]
|
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
"zod": "^3.11.6"
|
"zod": "^3.11.6"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "run-p templater serve watch-iframe-api svelte-check-watch typesafe-i18n",
|
"start": "run-p templater serve watch-iframe-api svelte-check-watch typesafe-i18n-watch",
|
||||||
"templater": "cross-env ./templater.sh",
|
"templater": "cross-env ./templater.sh",
|
||||||
"serve": "cross-env vite --host",
|
"serve": "cross-env vite --host",
|
||||||
"build": "cross-env vite build",
|
"build": "cross-env vite build",
|
||||||
@ -77,7 +77,8 @@
|
|||||||
"pretty": "yarn prettier --write 'src/**/*.{ts,svelte}'",
|
"pretty": "yarn prettier --write 'src/**/*.{ts,svelte}'",
|
||||||
"pretty-check": "yarn prettier --check 'src/**/*.{ts,svelte}'",
|
"pretty-check": "yarn prettier --check 'src/**/*.{ts,svelte}'",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"typesafe-i18n": "typesafe-i18n --no-watch"
|
"typesafe-i18n": "typesafe-i18n --no-watch",
|
||||||
|
"typesafe-i18n-watch": "typesafe-i18n"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.svelte": [
|
"*.svelte": [
|
||||||
|
49
front/public/resources/logos/meet.svg
Normal file
49
front/public/resources/logos/meet.svg
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="452.388px" height="452.388px" viewBox="0 0 452.388 452.388" style="enable-background:new 0 0 452.388 452.388;"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g id="Layer_8_38_">
|
||||||
|
<path d="M441.677,43.643H10.687C4.785,43.643,0,48.427,0,54.329v297.425c0,5.898,4.785,10.676,10.687,10.676h162.069v25.631
|
||||||
|
c0,0.38,0.074,0.722,0.112,1.089h-23.257c-5.407,0-9.796,4.389-9.796,9.795c0,5.408,4.389,9.801,9.796,9.801h158.506
|
||||||
|
c5.406,0,9.795-4.389,9.795-9.801c0-5.406-4.389-9.795-9.795-9.795h-23.256c0.032-0.355,0.115-0.709,0.115-1.089V362.43H441.7
|
||||||
|
c5.898,0,10.688-4.782,10.688-10.676V54.329C452.37,48.427,447.589,43.643,441.677,43.643z M422.089,305.133
|
||||||
|
c0,5.903-4.784,10.687-10.683,10.687H40.96c-5.898,0-10.684-4.783-10.684-10.687V79.615c0-5.898,4.786-10.684,10.684-10.684
|
||||||
|
h370.446c5.898,0,10.683,4.785,10.683,10.684V305.133z M303.942,290.648H154.025c0-29.872,17.472-55.661,42.753-67.706
|
||||||
|
c-15.987-10.501-26.546-28.571-26.546-49.13c0-32.449,26.306-58.755,58.755-58.755c32.448,0,58.753,26.307,58.753,58.755
|
||||||
|
c0,20.553-10.562,38.629-26.545,49.13C286.475,234.987,303.942,260.781,303.942,290.648z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -5,6 +5,7 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface()
|
|||||||
url: tg.isString,
|
url: tg.isString,
|
||||||
allowApi: tg.isOptional(tg.isBoolean),
|
allowApi: tg.isOptional(tg.isBoolean),
|
||||||
allowPolicy: tg.isOptional(tg.isString),
|
allowPolicy: tg.isOptional(tg.isString),
|
||||||
|
widthPercent: tg.isOptional(tg.isNumber),
|
||||||
position: tg.isOptional(tg.isNumber),
|
position: tg.isOptional(tg.isNumber),
|
||||||
closable: tg.isOptional(tg.isBoolean),
|
closable: tg.isOptional(tg.isBoolean),
|
||||||
lazy: tg.isOptional(tg.isBoolean),
|
lazy: tg.isOptional(tg.isBoolean),
|
||||||
|
@ -45,6 +45,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
url: string,
|
url: string,
|
||||||
allowApi?: boolean,
|
allowApi?: boolean,
|
||||||
allowPolicy?: string,
|
allowPolicy?: string,
|
||||||
|
widthPercent?: number,
|
||||||
position?: number,
|
position?: number,
|
||||||
closable?: boolean,
|
closable?: boolean,
|
||||||
lazy?: boolean
|
lazy?: boolean
|
||||||
@ -55,6 +56,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
url,
|
url,
|
||||||
allowApi,
|
allowApi,
|
||||||
allowPolicy,
|
allowPolicy,
|
||||||
|
widthPercent,
|
||||||
position,
|
position,
|
||||||
closable,
|
closable,
|
||||||
lazy,
|
lazy,
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
import { ICON_URL } from "../../Enum/EnvironmentVariable";
|
import { ICON_URL } from "../../Enum/EnvironmentVariable";
|
||||||
import { coWebsitesNotAsleep, mainCoWebsite } from "../../Stores/CoWebsiteStore";
|
import { mainCoWebsite } from "../../Stores/CoWebsiteStore";
|
||||||
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||||
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
|
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
|
|
||||||
export let index: number;
|
export let index: number;
|
||||||
@ -13,14 +15,15 @@
|
|||||||
|
|
||||||
let icon: HTMLImageElement;
|
let icon: HTMLImageElement;
|
||||||
let iconLoaded = false;
|
let iconLoaded = false;
|
||||||
let state = coWebsite.state;
|
let state = coWebsite.getStateSubscriber();
|
||||||
|
let isJitsi: boolean = coWebsite instanceof JitsiCoWebsite;
|
||||||
const coWebsiteUrl = coWebsite.iframe.src;
|
const mainState = coWebsiteManager.getMainStateSubscriber();
|
||||||
const urlObject = new URL(coWebsiteUrl);
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
icon.src = `${ICON_URL}/icon?url=${urlObject.hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
icon.src = isJitsi
|
||||||
icon.alt = coWebsite.altMessage ?? urlObject.hostname;
|
? "/resources/logos/meet.svg"
|
||||||
|
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
||||||
|
icon.alt = coWebsite.getUrl().hostname;
|
||||||
icon.onload = () => {
|
icon.onload = () => {
|
||||||
iconLoaded = true;
|
iconLoaded = true;
|
||||||
};
|
};
|
||||||
@ -30,12 +33,18 @@
|
|||||||
if (vertical) {
|
if (vertical) {
|
||||||
coWebsiteManager.goToMain(coWebsite);
|
coWebsiteManager.goToMain(coWebsite);
|
||||||
} else if ($mainCoWebsite) {
|
} else if ($mainCoWebsite) {
|
||||||
if ($mainCoWebsite.iframe.id === coWebsite.iframe.id) {
|
if ($mainCoWebsite.getId() === coWebsite.getId()) {
|
||||||
const coWebsites = $coWebsitesNotAsleep;
|
if (coWebsiteManager.getMainState() === iframeStates.closed) {
|
||||||
const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined;
|
coWebsiteManager.displayMain();
|
||||||
if (newMain) {
|
} else if ($highlightedEmbedScreen?.type === "cowebsite") {
|
||||||
coWebsiteManager.goToMain(coWebsite);
|
coWebsiteManager.goToMain($highlightedEmbedScreen.embed);
|
||||||
|
} else {
|
||||||
|
coWebsiteManager.hideMain();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (coWebsiteManager.getMainState() === iframeStates.closed) {
|
||||||
|
coWebsiteManager.goToMain(coWebsite);
|
||||||
|
coWebsiteManager.displayMain();
|
||||||
} else {
|
} else {
|
||||||
highlightedEmbedScreen.toggleHighlight({
|
highlightedEmbedScreen.toggleHighlight({
|
||||||
type: "cowebsite",
|
type: "cowebsite",
|
||||||
@ -43,6 +52,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($state === "asleep") {
|
if ($state === "asleep") {
|
||||||
await coWebsiteManager.loadCoWebsite(coWebsite);
|
await coWebsiteManager.loadCoWebsite(coWebsite);
|
||||||
@ -58,11 +68,14 @@
|
|||||||
let isHighlight: boolean = false;
|
let isHighlight: boolean = false;
|
||||||
let isMain: boolean = false;
|
let isMain: boolean = false;
|
||||||
$: {
|
$: {
|
||||||
isMain = $mainCoWebsite !== undefined && $mainCoWebsite.iframe === coWebsite.iframe;
|
isMain =
|
||||||
|
$mainState === iframeStates.opened &&
|
||||||
|
$mainCoWebsite !== undefined &&
|
||||||
|
$mainCoWebsite.getId() === coWebsite.getId();
|
||||||
isHighlight =
|
isHighlight =
|
||||||
$highlightedEmbedScreen !== null &&
|
$highlightedEmbedScreen !== null &&
|
||||||
$highlightedEmbedScreen.type === "cowebsite" &&
|
$highlightedEmbedScreen.type === "cowebsite" &&
|
||||||
$highlightedEmbedScreen.embed.iframe === coWebsite.iframe;
|
$highlightedEmbedScreen.embed.getId() === coWebsite.getId();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -79,6 +92,7 @@
|
|||||||
<img
|
<img
|
||||||
class="cowebsite-icon noselect nes-pointer"
|
class="cowebsite-icon noselect nes-pointer"
|
||||||
class:hide={!iconLoaded}
|
class:hide={!iconLoaded}
|
||||||
|
class:jitsi={isJitsi}
|
||||||
bind:this={icon}
|
bind:this={icon}
|
||||||
on:dragstart|preventDefault={noDrag}
|
on:dragstart|preventDefault={noDrag}
|
||||||
alt=""
|
alt=""
|
||||||
@ -205,7 +219,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(.vertical) {
|
&:not(.vertical) {
|
||||||
animation: bounce 0.35s ease 6 alternate;
|
transition: all 300ms;
|
||||||
|
transform: translateY(0px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
@ -226,7 +241,7 @@
|
|||||||
|
|
||||||
&.displayed {
|
&.displayed {
|
||||||
&:not(.vertical) {
|
&:not(.vertical) {
|
||||||
animation: activeThumbnail 300ms ease-in 0s forwards;
|
transform: translateY(-15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,16 +270,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes activeThumbnail {
|
|
||||||
0% {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translateY(-15px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes bounce {
|
@keyframes bounce {
|
||||||
from {
|
from {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
@ -308,6 +313,12 @@
|
|||||||
&.hide {
|
&.hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.jitsi {
|
||||||
|
filter: invert(100%);
|
||||||
|
-webkit-filter: invert(100%);
|
||||||
|
padding: 7px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
{#if $coWebsites.length > 0}
|
{#if $coWebsites.length > 0}
|
||||||
<div id="cowebsite-thumbnail-container" class:vertical>
|
<div id="cowebsite-thumbnail-container" class:vertical>
|
||||||
{#each [...$coWebsites.values()] as coWebsite, index (coWebsite.iframe.id)}
|
{#each [...$coWebsites.values()] as coWebsite, index (coWebsite.getId())}
|
||||||
<CoWebsiteThumbnail {index} {coWebsite} {vertical} />
|
<CoWebsiteThumbnail {index} {coWebsite} {vertical} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,8 +23,9 @@
|
|||||||
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
||||||
<MediaBox
|
<MediaBox
|
||||||
streamable={peer}
|
streamable={peer}
|
||||||
|
mozaicSolo={$streamableCollectionStore.size === 1}
|
||||||
mozaicFullWidth={$streamableCollectionStore.size === 1 || $streamableCollectionStore.size === 2}
|
mozaicFullWidth={$streamableCollectionStore.size === 1 || $streamableCollectionStore.size === 2}
|
||||||
mozaicQuarter={$streamableCollectionStore.size === 3 || $streamableCollectionStore.size === 4}
|
mozaicQuarter={$streamableCollectionStore.size === 3 || $streamableCollectionStore.size >= 4}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,13 +9,11 @@
|
|||||||
|
|
||||||
function closeCoWebsite() {
|
function closeCoWebsite() {
|
||||||
if ($highlightedEmbedScreen?.type === "cowebsite") {
|
if ($highlightedEmbedScreen?.type === "cowebsite") {
|
||||||
if ($highlightedEmbedScreen.embed.closable) {
|
if ($highlightedEmbedScreen.embed.isClosable()) {
|
||||||
coWebsiteManager.closeCoWebsite($highlightedEmbedScreen.embed).catch(() => {
|
coWebsiteManager.closeCoWebsite($highlightedEmbedScreen.embed);
|
||||||
console.error("Error during co-website highlighted closing");
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
coWebsiteManager.unloadCoWebsite($highlightedEmbedScreen.embed).catch(() => {
|
coWebsiteManager.unloadCoWebsite($highlightedEmbedScreen.embed).catch((err) => {
|
||||||
console.error("Error during co-website highlighted unloading");
|
console.error("Cannot unload co-website", err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,9 +66,9 @@
|
|||||||
/>
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
{:else if $highlightedEmbedScreen.type === "cowebsite"}
|
{:else if $highlightedEmbedScreen.type === "cowebsite"}
|
||||||
{#key $highlightedEmbedScreen.embed.iframe.id}
|
{#key $highlightedEmbedScreen.embed.getId()}
|
||||||
<div
|
<div
|
||||||
id={"cowebsite-slot-" + $highlightedEmbedScreen.embed.iframe.id}
|
id={"cowebsite-slot-" + $highlightedEmbedScreen.embed.getId()}
|
||||||
class="highlighted-cowebsite nes-container is-rounded"
|
class="highlighted-cowebsite nes-container is-rounded"
|
||||||
>
|
>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
<section class="terms-and-conditions">
|
<section class="terms-and-conditions">
|
||||||
<a style="display: none;" href="traduction">Need for traduction</a>
|
<a style="display: none;" href="traduction">Need for traduction</a>
|
||||||
<p>
|
<p>
|
||||||
{$LL.login.terms()}
|
{@html $LL.login.terms()}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import LL from "../../i18n/i18n-svelte";
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||||
|
|
||||||
|
let entryPoint: string = $startLayerNamesStore[0];
|
||||||
|
let walkAutomatically: boolean = false;
|
||||||
|
const currentPlayer = gameManager.getCurrentGameScene().CurrentPlayer;
|
||||||
|
const playerPos = { x: Math.floor(currentPlayer.x), y: Math.floor(currentPlayer.y) };
|
||||||
|
|
||||||
function copyLink() {
|
function copyLink() {
|
||||||
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
|
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
|
||||||
@ -8,8 +15,23 @@
|
|||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLink() {
|
||||||
|
return `${location.origin}${location.pathname}#${entryPoint}${
|
||||||
|
walkAutomatically ? `&moveTo=${playerPos.x},${playerPos.y}` : ""
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateInputFieldValue() {
|
||||||
|
const input = document.getElementById("input-share-link");
|
||||||
|
if (input) {
|
||||||
|
(input as HTMLInputElement).value = getLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let canShare = navigator.share !== undefined;
|
||||||
|
|
||||||
async function shareLink() {
|
async function shareLink() {
|
||||||
const shareData = { url: location.toString() };
|
const shareData = { url: getLink() };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await navigator.share(shareData);
|
await navigator.share(shareData);
|
||||||
@ -22,16 +44,43 @@
|
|||||||
|
|
||||||
<div class="guest-main">
|
<div class="guest-main">
|
||||||
<section class="container-overflow">
|
<section class="container-overflow">
|
||||||
|
{#if !canShare}
|
||||||
<section class="share-url not-mobile">
|
<section class="share-url not-mobile">
|
||||||
<h3>{$LL.menu.invite.description()}</h3>
|
<h3>{$LL.menu.invite.description()}</h3>
|
||||||
<input type="text" readonly id="input-share-link" value={location.toString()} />
|
<input type="text" readonly id="input-share-link" class="link-url" value={location.toString()} />
|
||||||
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button>
|
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button>
|
||||||
</section>
|
</section>
|
||||||
|
{:else}
|
||||||
<section class="is-mobile">
|
<section class="is-mobile">
|
||||||
<h3>{$LL.menu.invite.description()}</h3>
|
<h3>{$LL.menu.invite.description()}</h3>
|
||||||
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
||||||
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button>
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button>
|
||||||
</section>
|
</section>
|
||||||
|
{/if}
|
||||||
|
<h3>Select an entry point</h3>
|
||||||
|
<section class="nes-select is-dark starting-points">
|
||||||
|
<select
|
||||||
|
bind:value={entryPoint}
|
||||||
|
on:blur={() => {
|
||||||
|
updateInputFieldValue();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#each $startLayerNamesStore as entryPointName}
|
||||||
|
<option value={entryPointName}>{entryPointName}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</section>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="nes-checkbox is-dark"
|
||||||
|
bind:checked={walkAutomatically}
|
||||||
|
on:change={() => {
|
||||||
|
updateInputFieldValue();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>{$LL.menu.invite.walk_automatically_to_position()}</span>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -39,14 +88,27 @@
|
|||||||
@import "../../../style/breakpoints.scss";
|
@import "../../../style/breakpoints.scss";
|
||||||
|
|
||||||
div.guest-main {
|
div.guest-main {
|
||||||
|
width: 50%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
text-align: center;
|
input.link-url {
|
||||||
|
width: calc(100% - 200px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.starting-points {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section.nes-select select:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
section.container-overflow {
|
section.container-overflow {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -55,25 +117,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
section.is-mobile {
|
section.is-mobile {
|
||||||
display: none;
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
div.guest-main {
|
div.guest-main {
|
||||||
section.share-url.not-mobile {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.is-mobile {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.container-overflow {
|
section.container-overflow {
|
||||||
height: calc(100% - 120px);
|
height: calc(100% - 120px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
div.guest-main {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
} else {
|
} else {
|
||||||
const customMenu = customMenuIframe.get(menu.label);
|
const customMenu = customMenuIframe.get(menu.label);
|
||||||
if (customMenu !== undefined) {
|
if (customMenu !== undefined) {
|
||||||
|
activeSubMenu = menu;
|
||||||
props = { url: customMenu.url, allowApi: customMenu.allowApi };
|
props = { url: customMenu.url, allowApi: customMenu.allowApi };
|
||||||
activeComponent = CustomSubMenu;
|
activeComponent = CustomSubMenu;
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
export let streamable: Streamable;
|
export let streamable: Streamable;
|
||||||
export let isHightlighted = false;
|
export let isHightlighted = false;
|
||||||
export let isClickable = false;
|
export let isClickable = false;
|
||||||
|
export let mozaicSolo = false;
|
||||||
export let mozaicFullWidth = false;
|
export let mozaicFullWidth = false;
|
||||||
export let mozaicQuarter = false;
|
export let mozaicQuarter = false;
|
||||||
</script>
|
</script>
|
||||||
@ -16,6 +17,7 @@
|
|||||||
<div
|
<div
|
||||||
class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}"
|
class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}"
|
||||||
class:clickable={isClickable}
|
class:clickable={isClickable}
|
||||||
|
class:mozaic-solo={mozaicSolo}
|
||||||
class:mozaic-full-width={mozaicFullWidth}
|
class:mozaic-full-width={mozaicFullWidth}
|
||||||
class:mozaic-quarter={mozaicQuarter}
|
class:mozaic-quarter={mozaicQuarter}
|
||||||
>
|
>
|
||||||
@ -66,6 +68,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.mozaic-solo {
|
||||||
|
max-height: inherit !important;
|
||||||
|
width: 90% !important;
|
||||||
|
}
|
||||||
|
|
||||||
&.mozaic-full-width {
|
&.mozaic-full-width {
|
||||||
width: 95%;
|
width: 95%;
|
||||||
max-width: 95%;
|
max-width: 95%;
|
||||||
@ -73,6 +80,7 @@
|
|||||||
margin-right: 3%;
|
margin-right: 3%;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
|
max-height: 95%;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
@ -85,6 +93,7 @@
|
|||||||
max-width: 95%;
|
max-width: 95%;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
|
max-height: 95%;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
transform: translate(-50%, 0);
|
|
||||||
font-family: Lato;
|
font-family: Lato;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
|
@ -9,4 +9,7 @@ export interface UserInputHandlerInterface {
|
|||||||
handlePointerUpEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void;
|
handlePointerUpEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void;
|
||||||
handlePointerDownEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void;
|
handlePointerDownEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void;
|
||||||
handleSpaceKeyUpEvent: (event: Event) => Event;
|
handleSpaceKeyUpEvent: (event: Event) => Event;
|
||||||
|
|
||||||
|
addSpaceEventListener: (callback: Function) => void;
|
||||||
|
removeSpaceEventListner: (callback: Function) => void;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Anima
|
|||||||
import { TexturesHelper } from "../Helpers/TexturesHelper";
|
import { TexturesHelper } from "../Helpers/TexturesHelper";
|
||||||
import { Writable, writable } from "svelte/store";
|
import { Writable, writable } from "svelte/store";
|
||||||
import type { PictureStore } from "../../Stores/PictureStore";
|
import type { PictureStore } from "../../Stores/PictureStore";
|
||||||
|
import type CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
export interface CompanionStatus {
|
export interface CompanionStatus {
|
||||||
x: number;
|
x: number;
|
||||||
@ -25,8 +26,9 @@ export class Companion extends Container {
|
|||||||
private direction: PlayerAnimationDirections;
|
private direction: PlayerAnimationDirections;
|
||||||
private animationType: PlayerAnimationTypes;
|
private animationType: PlayerAnimationTypes;
|
||||||
private readonly _pictureStore: Writable<string | undefined>;
|
private readonly _pictureStore: Writable<string | undefined>;
|
||||||
|
private texturePromise: CancelablePromise<string | void> | undefined;
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, x: number, y: number, name: string, texturePromise: Promise<string>) {
|
constructor(scene: Phaser.Scene, x: number, y: number, name: string, texturePromise: CancelablePromise<string>) {
|
||||||
super(scene, x + 14, y + 4);
|
super(scene, x + 14, y + 4);
|
||||||
|
|
||||||
this.sprites = new Map<string, Sprite>();
|
this.sprites = new Map<string, Sprite>();
|
||||||
@ -41,7 +43,7 @@ export class Companion extends Container {
|
|||||||
this.companionName = name;
|
this.companionName = name;
|
||||||
this._pictureStore = writable(undefined);
|
this._pictureStore = writable(undefined);
|
||||||
|
|
||||||
texturePromise
|
this.texturePromise = texturePromise
|
||||||
.then((resource) => {
|
.then((resource) => {
|
||||||
this.addResource(resource);
|
this.addResource(resource);
|
||||||
this.invisible = false;
|
this.invisible = false;
|
||||||
@ -234,6 +236,7 @@ export class Companion extends Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
|
this.texturePromise?.cancel();
|
||||||
for (const sprite of this.sprites.values()) {
|
for (const sprite of this.sprites.values()) {
|
||||||
if (this.scene) {
|
if (this.scene) {
|
||||||
this.scene.sys.updateList.remove(sprite);
|
this.scene.sys.updateList.remove(sprite);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
||||||
import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures";
|
import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures";
|
||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => {
|
export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => {
|
||||||
COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => {
|
COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => {
|
||||||
@ -9,8 +10,12 @@ export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourc
|
|||||||
return COMPANION_RESOURCES;
|
return COMPANION_RESOURCES;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lazyLoadCompanionResource = (loader: LoaderPlugin, name: string): Promise<string> => {
|
export const lazyLoadCompanionResource = (loader: LoaderPlugin, name: string): CancelablePromise<string> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new CancelablePromise((resolve, reject, cancel) => {
|
||||||
|
cancel(() => {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
const resource = COMPANION_RESOURCES.find((item) => item.name === name);
|
const resource = COMPANION_RESOURCES.find((item) => item.name === name);
|
||||||
|
|
||||||
if (typeof resource === "undefined") {
|
if (typeof resource === "undefined") {
|
||||||
|
@ -59,7 +59,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
frame: string | number,
|
frame: string | number,
|
||||||
isClickable: boolean,
|
isClickable: boolean,
|
||||||
companion: string | null,
|
companion: string | null,
|
||||||
companionTexturePromise?: Promise<string>
|
companionTexturePromise?: CancelablePromise<string>
|
||||||
) {
|
) {
|
||||||
super(scene, x, y /*, texture, frame*/);
|
super(scene, x, y /*, texture, frame*/);
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
@ -142,7 +142,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
this.clickable = clickable;
|
this.clickable = clickable;
|
||||||
if (clickable) {
|
if (clickable) {
|
||||||
this.setInteractive({
|
this.setInteractive({
|
||||||
hitArea: new Phaser.Geom.Circle(0, 0, interactiveRadius),
|
hitArea: new Phaser.Geom.Circle(8, 8, interactiveRadius),
|
||||||
hitAreaCallback: Phaser.Geom.Circle.Contains, //eslint-disable-line @typescript-eslint/unbound-method
|
hitAreaCallback: Phaser.Geom.Circle.Contains, //eslint-disable-line @typescript-eslint/unbound-method
|
||||||
useHandCursor: true,
|
useHandCursor: true,
|
||||||
});
|
});
|
||||||
@ -159,6 +159,27 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
return { x: this.x, y: this.y };
|
return { x: this.x, y: this.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns position based on where player is currently facing
|
||||||
|
* @param shift How far from player should the point of interest be.
|
||||||
|
*/
|
||||||
|
public getDirectionalActivationPosition(shift: number): { x: number; y: number } {
|
||||||
|
switch (this.lastDirection) {
|
||||||
|
case PlayerAnimationDirections.Down: {
|
||||||
|
return { x: this.x, y: this.y + shift };
|
||||||
|
}
|
||||||
|
case PlayerAnimationDirections.Left: {
|
||||||
|
return { x: this.x - shift, y: this.y };
|
||||||
|
}
|
||||||
|
case PlayerAnimationDirections.Right: {
|
||||||
|
return { x: this.x + shift, y: this.y };
|
||||||
|
}
|
||||||
|
case PlayerAnimationDirections.Up: {
|
||||||
|
return { x: this.x, y: this.y - shift };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getObjectToOutline(): Phaser.GameObjects.GameObject {
|
public getObjectToOutline(): Phaser.GameObjects.GameObject {
|
||||||
return this.playerNameText;
|
return this.playerNameText;
|
||||||
}
|
}
|
||||||
@ -179,7 +200,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public addCompanion(name: string, texturePromise?: Promise<string>): void {
|
public addCompanion(name: string, texturePromise?: CancelablePromise<string>): void {
|
||||||
if (typeof texturePromise !== "undefined") {
|
if (typeof texturePromise !== "undefined") {
|
||||||
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
||||||
}
|
}
|
||||||
@ -455,16 +476,16 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
this.outlineColorStore.removeApiColor();
|
this.outlineColorStore.removeApiColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public pointerOverOutline(): void {
|
public pointerOverOutline(color: number): void {
|
||||||
this.outlineColorStore.pointerOver();
|
this.outlineColorStore.pointerOver(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public pointerOutOutline(): void {
|
public pointerOutOutline(): void {
|
||||||
this.outlineColorStore.pointerOut();
|
this.outlineColorStore.pointerOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
public characterCloseByOutline(): void {
|
public characterCloseByOutline(color: number): void {
|
||||||
this.outlineColorStore.characterCloseBy();
|
this.outlineColorStore.characterCloseBy(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public characterFarAwayOutline(): void {
|
public characterFarAwayOutline(): void {
|
||||||
|
@ -31,18 +31,18 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
|||||||
moving: boolean,
|
moving: boolean,
|
||||||
visitCardUrl: string | null,
|
visitCardUrl: string | null,
|
||||||
companion: string | null,
|
companion: string | null,
|
||||||
companionTexturePromise?: Promise<string>,
|
companionTexturePromise?: CancelablePromise<string>,
|
||||||
activationRadius?: number
|
activationRadius?: number
|
||||||
) {
|
) {
|
||||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise);
|
super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise);
|
||||||
|
|
||||||
//set data
|
//set data
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.visitCardUrl = visitCardUrl;
|
||||||
this.registeredActions = [];
|
this.registeredActions = [];
|
||||||
this.registerDefaultActionsMenuActions();
|
this.registerDefaultActionsMenuActions();
|
||||||
this.setClickable(this.registeredActions.length > 0);
|
this.setClickable(this.registeredActions.length > 0);
|
||||||
this.activationRadius = activationRadius ?? 96;
|
this.activationRadius = activationRadius ?? 96;
|
||||||
this.visitCardUrl = visitCardUrl;
|
|
||||||
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
|
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
|
||||||
this.isActionsMenuInitialized = value ? true : false;
|
this.isActionsMenuInitialized = value ? true : false;
|
||||||
});
|
});
|
||||||
@ -118,7 +118,7 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
|||||||
|
|
||||||
private bindEventHandlers(): void {
|
private bindEventHandlers(): void {
|
||||||
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
|
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
|
||||||
if (event.downElement.nodeName === "CANVAS") {
|
if (event.downElement.nodeName === "CANVAS" && event.leftButtonDown()) {
|
||||||
this.toggleActionsMenu();
|
this.toggleActionsMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -11,6 +11,11 @@ export class ActivatablesManager {
|
|||||||
|
|
||||||
private currentPlayer: Player;
|
private currentPlayer: Player;
|
||||||
|
|
||||||
|
private canSelectByDistance: boolean = true;
|
||||||
|
|
||||||
|
private readonly outlineColor = 0xffff00;
|
||||||
|
private readonly directionalActivationPositionShift = 50;
|
||||||
|
|
||||||
constructor(currentPlayer: Player) {
|
constructor(currentPlayer: Player) {
|
||||||
this.currentPlayer = currentPlayer;
|
this.currentPlayer = currentPlayer;
|
||||||
}
|
}
|
||||||
@ -27,7 +32,7 @@ export class ActivatablesManager {
|
|||||||
}
|
}
|
||||||
this.selectedActivatableObjectByPointer = object;
|
this.selectedActivatableObjectByPointer = object;
|
||||||
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
|
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
|
||||||
this.selectedActivatableObjectByPointer?.pointerOverOutline();
|
this.selectedActivatableObjectByPointer?.pointerOverOutline(this.outlineColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +42,7 @@ export class ActivatablesManager {
|
|||||||
}
|
}
|
||||||
this.selectedActivatableObjectByPointer = undefined;
|
this.selectedActivatableObjectByPointer = undefined;
|
||||||
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
|
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
|
||||||
this.selectedActivatableObjectByDistance?.characterCloseByOutline();
|
this.selectedActivatableObjectByDistance?.characterCloseByOutline(this.outlineColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,6 +51,9 @@ export class ActivatablesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public deduceSelectedActivatableObjectByDistance(): void {
|
public deduceSelectedActivatableObjectByDistance(): void {
|
||||||
|
if (!this.canSelectByDistance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const newNearestObject = this.findNearestActivatableObject();
|
const newNearestObject = this.findNearestActivatableObject();
|
||||||
if (this.selectedActivatableObjectByDistance === newNearestObject) {
|
if (this.selectedActivatableObjectByDistance === newNearestObject) {
|
||||||
return;
|
return;
|
||||||
@ -60,10 +68,42 @@ export class ActivatablesManager {
|
|||||||
}
|
}
|
||||||
this.selectedActivatableObjectByDistance = newNearestObject;
|
this.selectedActivatableObjectByDistance = newNearestObject;
|
||||||
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
|
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
|
||||||
this.selectedActivatableObjectByDistance?.characterCloseByOutline();
|
this.selectedActivatableObjectByDistance?.characterCloseByOutline(this.outlineColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateActivatableObjectsDistances(objects: ActivatableInterface[]): void {
|
||||||
|
const currentPlayerPos = this.currentPlayer.getDirectionalActivationPosition(
|
||||||
|
this.directionalActivationPositionShift
|
||||||
|
);
|
||||||
|
for (const object of objects) {
|
||||||
|
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
|
||||||
|
this.activatableObjectsDistances.set(object, distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateDistanceForSingleActivatableObject(object: ActivatableInterface): void {
|
||||||
|
this.activatableObjectsDistances.set(
|
||||||
|
object,
|
||||||
|
MathUtils.distanceBetween(
|
||||||
|
this.currentPlayer.getDirectionalActivationPosition(this.directionalActivationPositionShift),
|
||||||
|
object.getPosition()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public disableSelectingByDistance(): void {
|
||||||
|
this.canSelectByDistance = false;
|
||||||
|
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
|
||||||
|
this.selectedActivatableObjectByDistance?.characterFarAwayOutline();
|
||||||
|
}
|
||||||
|
this.selectedActivatableObjectByDistance = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enableSelectingByDistance(): void {
|
||||||
|
this.canSelectByDistance = true;
|
||||||
|
}
|
||||||
|
|
||||||
private findNearestActivatableObject(): ActivatableInterface | undefined {
|
private findNearestActivatableObject(): ActivatableInterface | undefined {
|
||||||
let shortestDistance: number = Infinity;
|
let shortestDistance: number = Infinity;
|
||||||
let closestObject: ActivatableInterface | undefined = undefined;
|
let closestObject: ActivatableInterface | undefined = undefined;
|
||||||
@ -76,18 +116,8 @@ export class ActivatablesManager {
|
|||||||
}
|
}
|
||||||
return closestObject;
|
return closestObject;
|
||||||
}
|
}
|
||||||
public updateActivatableObjectsDistances(objects: ActivatableInterface[]): void {
|
|
||||||
const currentPlayerPos = this.currentPlayer.getPosition();
|
|
||||||
for (const object of objects) {
|
|
||||||
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
|
|
||||||
this.activatableObjectsDistances.set(object, distance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateDistanceForSingleActivatableObject(object: ActivatableInterface): void {
|
public isSelectingByDistanceEnabled(): boolean {
|
||||||
this.activatableObjectsDistances.set(
|
return this.canSelectByDistance;
|
||||||
object,
|
|
||||||
MathUtils.distanceBetween(this.currentPlayer.getPosition(), object.getPosition())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,15 +26,6 @@ export class Game extends Phaser.Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/*window.addEventListener('resize', (event) => {
|
|
||||||
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
|
||||||
for (const scene of this.scene.getScenes(true)) {
|
|
||||||
if (scene instanceof ResizableScene) {
|
|
||||||
scene.onResize(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public step(time: number, delta: number) {
|
public step(time: number, delta: number) {
|
||||||
|
@ -85,6 +85,7 @@ export class GameMap {
|
|||||||
phaserMap
|
phaserMap
|
||||||
.createLayer(layer.name, terrains, (layer.x || 0) * 32, (layer.y || 0) * 32)
|
.createLayer(layer.name, terrains, (layer.x || 0) * 32, (layer.y || 0) * 32)
|
||||||
.setDepth(depth)
|
.setDepth(depth)
|
||||||
|
.setScrollFactor(layer.parallaxx ?? 1, layer.parallaxy ?? 1)
|
||||||
.setAlpha(layer.opacity)
|
.setAlpha(layer.opacity)
|
||||||
.setVisible(layer.visible)
|
.setVisible(layer.visible)
|
||||||
.setSize(layer.width, layer.height)
|
.setSize(layer.width, layer.height)
|
||||||
@ -120,7 +121,7 @@ export class GameMap {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCollisionsGrid(): number[][] {
|
public getCollisionGrid(): number[][] {
|
||||||
const grid: number[][] = [];
|
const grid: number[][] = [];
|
||||||
for (let y = 0; y < this.map.height; y += 1) {
|
for (let y = 0; y < this.map.height; y += 1) {
|
||||||
const row: number[] = [];
|
const row: number[] = [];
|
||||||
@ -322,12 +323,19 @@ export class GameMap {
|
|||||||
throw new Error("No possible position found");
|
throw new Error("No possible position found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getObjectWithName(name: string): ITiledMapObject | undefined {
|
||||||
|
return this.tiledObjects.find((object) => object.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
private getLayersByKey(key: number): Array<ITiledMapLayer> {
|
private getLayersByKey(key: number): Array<ITiledMapLayer> {
|
||||||
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
|
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private isCollidingAt(x: number, y: number): boolean {
|
private isCollidingAt(x: number, y: number): boolean {
|
||||||
for (const layer of this.phaserLayers) {
|
for (const layer of this.phaserLayers) {
|
||||||
|
if (!layer.visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (layer.getTileAt(x, y)?.properties[GameMapProperties.COLLIDES]) {
|
if (layer.getTileAt(x, y)?.properties[GameMapProperties.COLLIDES]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ export enum GameMapProperties {
|
|||||||
OPEN_WEBSITE = "openWebsite",
|
OPEN_WEBSITE = "openWebsite",
|
||||||
OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi",
|
OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi",
|
||||||
OPEN_WEBSITE_POLICY = "openWebsitePolicy",
|
OPEN_WEBSITE_POLICY = "openWebsitePolicy",
|
||||||
|
OPEN_WEBSITE_WIDTH = "openWebsiteWidth",
|
||||||
OPEN_WEBSITE_POSITION = "openWebsitePosition",
|
OPEN_WEBSITE_POSITION = "openWebsitePosition",
|
||||||
OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger",
|
OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger",
|
||||||
OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage",
|
OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage",
|
||||||
|
@ -1,33 +1,36 @@
|
|||||||
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 { localUserStore } from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
|
import { ON_ACTION_TRIGGER_BUTTON, ON_ICON_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
|
||||||
import type { ITiledMapLayer } from "../Map/ITiledMap";
|
import type { ITiledMapLayer } from "../Map/ITiledMap";
|
||||||
import { GameMapProperties } from "./GameMapProperties";
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
|
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||||
enum OpenCoWebsiteState {
|
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||||
ASLEEP,
|
import { JITSI_PRIVATE_MODE, JITSI_URL } from "../../Enum/EnvironmentVariable";
|
||||||
OPENED,
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
MUST_BE_CLOSE,
|
import { audioManagerFileStore, audioManagerVisibilityStore } from "../../Stores/AudioManagerStore";
|
||||||
}
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
|
import { Room } from "../../Connexion/Room";
|
||||||
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
|
||||||
interface OpenCoWebsite {
|
interface OpenCoWebsite {
|
||||||
coWebsite: CoWebsite;
|
actionId: string;
|
||||||
state: OpenCoWebsiteState;
|
coWebsite?: CoWebsite;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GameMapPropertiesListener {
|
export class GameMapPropertiesListener {
|
||||||
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
|
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() {
|
||||||
|
// Website on new tab
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldValue, allProps) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
layoutManagerActionStore.removeAction("openTab");
|
layoutManagerActionStore.removeAction("openTab");
|
||||||
@ -38,7 +41,7 @@ export class GameMapPropertiesListener {
|
|||||||
if (forceTrigger || openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
if (forceTrigger || openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
||||||
let message = allProps.get(GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE);
|
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 = get(LL).trigger.newTab();
|
||||||
}
|
}
|
||||||
layoutManagerActionStore.addAction({
|
layoutManagerActionStore.addAction({
|
||||||
uuid: "openTab",
|
uuid: "openTab",
|
||||||
@ -53,6 +56,129 @@ export class GameMapPropertiesListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Jitsi room
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.JITSI_ROOM, (newValue, oldValue, allProps) => {
|
||||||
|
if (newValue === undefined) {
|
||||||
|
layoutManagerActionStore.removeAction("jitsi");
|
||||||
|
coWebsiteManager.getCoWebsites().forEach((coWebsite) => {
|
||||||
|
if (coWebsite instanceof JitsiCoWebsite) {
|
||||||
|
coWebsiteManager.closeCoWebsite(coWebsite);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const openJitsiRoomFunction = () => {
|
||||||
|
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.scene.instance);
|
||||||
|
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||||
|
|
||||||
|
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
|
||||||
|
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
|
||||||
|
|
||||||
|
this.scene.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
|
||||||
|
} else {
|
||||||
|
let domain = jitsiUrl || JITSI_URL;
|
||||||
|
if (domain === undefined) {
|
||||||
|
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain.substring(0, 7) !== "http://" && domain.substring(0, 8) !== "https://") {
|
||||||
|
domain = `${location.protocol}//${domain}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
|
||||||
|
|
||||||
|
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
|
||||||
|
this.scene.initialiseJitsi(coWebsite, roomName, undefined);
|
||||||
|
}
|
||||||
|
layoutManagerActionStore.removeAction("jitsi");
|
||||||
|
};
|
||||||
|
|
||||||
|
const jitsiTriggerValue = allProps.get(GameMapProperties.JITSI_TRIGGER);
|
||||||
|
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
|
||||||
|
if (forceTrigger || jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
||||||
|
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
|
||||||
|
if (message === undefined) {
|
||||||
|
message = get(LL).trigger.jitsiRoom();
|
||||||
|
}
|
||||||
|
layoutManagerActionStore.addAction({
|
||||||
|
uuid: "jitsi",
|
||||||
|
type: "message",
|
||||||
|
message: message,
|
||||||
|
callback: () => openJitsiRoomFunction(),
|
||||||
|
userInputManager: this.scene.userInputManager,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
openJitsiRoomFunction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue, oldValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
this.scene
|
||||||
|
.onMapExit(
|
||||||
|
Room.getRoomPathFromExitSceneUrl(
|
||||||
|
newValue as string,
|
||||||
|
window.location.toString(),
|
||||||
|
this.scene.MapUrlFile
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
layoutManagerActionStore.removeAction("roomAccessDenied");
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
this.scene
|
||||||
|
.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()))
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
layoutManagerActionStore.removeAction("roomAccessDenied");
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue, oldValue) => {
|
||||||
|
if (newValue === undefined || newValue === false || newValue === "") {
|
||||||
|
this.scene.connection?.setSilent(false);
|
||||||
|
this.scene.CurrentPlayer.noSilent();
|
||||||
|
} else {
|
||||||
|
this.scene.connection?.setSilent(true);
|
||||||
|
this.scene.CurrentPlayer.isSilent();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO, (newValue, oldValue, allProps) => {
|
||||||
|
const volume = allProps.get(GameMapProperties.AUDIO_VOLUME) as number | undefined;
|
||||||
|
const loop = allProps.get(GameMapProperties.AUDIO_LOOP) as boolean | undefined;
|
||||||
|
newValue === undefined
|
||||||
|
? audioManagerFileStore.unloadAudio()
|
||||||
|
: audioManagerFileStore.playAudio(newValue, this.scene.getMapDirUrl(), volume, loop);
|
||||||
|
audioManagerVisibilityStore.set(!(newValue === undefined));
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: This legacy property should be removed at some point
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue, oldValue) => {
|
||||||
|
newValue === undefined
|
||||||
|
? audioManagerFileStore.unloadAudio()
|
||||||
|
: audioManagerFileStore.playAudio(newValue, this.scene.getMapDirUrl(), undefined, true);
|
||||||
|
audioManagerVisibilityStore.set(!(newValue === undefined));
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Legacy functionnality replace by layer change
|
||||||
|
this.gameMap.onPropertyChange(GameMapProperties.ZONE, (newValue, oldValue) => {
|
||||||
|
if (oldValue) {
|
||||||
|
iframeListener.sendLeaveEvent(oldValue as string);
|
||||||
|
}
|
||||||
|
if (newValue) {
|
||||||
|
iframeListener.sendEnterEvent(newValue as string);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Open a new co-website by the property.
|
// Open a new co-website by the property.
|
||||||
this.gameMap.onEnterLayer((newLayers) => {
|
this.gameMap.onEnterLayer((newLayers) => {
|
||||||
const handler = () => {
|
const handler = () => {
|
||||||
@ -64,6 +190,7 @@ export class GameMapPropertiesListener {
|
|||||||
let openWebsiteProperty: string | undefined;
|
let openWebsiteProperty: string | undefined;
|
||||||
let allowApiProperty: boolean | undefined;
|
let allowApiProperty: boolean | undefined;
|
||||||
let websitePolicyProperty: string | undefined;
|
let websitePolicyProperty: string | undefined;
|
||||||
|
let websiteWidthProperty: number | undefined;
|
||||||
let websitePositionProperty: number | undefined;
|
let websitePositionProperty: number | undefined;
|
||||||
let websiteTriggerProperty: string | undefined;
|
let websiteTriggerProperty: string | undefined;
|
||||||
let websiteTriggerMessageProperty: string | undefined;
|
let websiteTriggerMessageProperty: string | undefined;
|
||||||
@ -79,6 +206,9 @@ export class GameMapPropertiesListener {
|
|||||||
case GameMapProperties.OPEN_WEBSITE_POLICY:
|
case GameMapProperties.OPEN_WEBSITE_POLICY:
|
||||||
websitePolicyProperty = property.value as string | undefined;
|
websitePolicyProperty = property.value as string | undefined;
|
||||||
break;
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_WIDTH:
|
||||||
|
websiteWidthProperty = property.value as number | undefined;
|
||||||
|
break;
|
||||||
case GameMapProperties.OPEN_WEBSITE_POSITION:
|
case GameMapProperties.OPEN_WEBSITE_POSITION:
|
||||||
websitePositionProperty = property.value as number | undefined;
|
websitePositionProperty = property.value as number | undefined;
|
||||||
break;
|
break;
|
||||||
@ -95,55 +225,75 @@ export class GameMapPropertiesListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionUuid = "openWebsite-" + (Math.random() + 1).toString(36).substring(7);
|
const actionId = "openWebsite-" + (Math.random() + 1).toString(36).substring(7);
|
||||||
|
|
||||||
if (this.coWebsitesOpenByLayer.has(layer)) {
|
if (this.coWebsitesOpenByLayer.has(layer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const coWebsite = coWebsiteManager.addCoWebsite(
|
const coWebsiteOpen: OpenCoWebsite = {
|
||||||
openWebsiteProperty,
|
actionId: actionId,
|
||||||
this.scene.MapUrlFile,
|
};
|
||||||
|
|
||||||
|
this.coWebsitesOpenByLayer.set(layer, coWebsiteOpen);
|
||||||
|
|
||||||
|
const loadCoWebsiteFunction = (coWebsite: CoWebsite) => {
|
||||||
|
coWebsiteManager.loadCoWebsite(coWebsite).catch(() => {
|
||||||
|
console.error("Error during loading a co-website: " + coWebsite.getUrl());
|
||||||
|
});
|
||||||
|
|
||||||
|
layoutManagerActionStore.removeAction(actionId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openCoWebsiteFunction = () => {
|
||||||
|
const coWebsite = new SimpleCoWebsite(
|
||||||
|
new URL(openWebsiteProperty ?? "", this.scene.MapUrlFile),
|
||||||
allowApiProperty,
|
allowApiProperty,
|
||||||
websitePolicyProperty,
|
websitePolicyProperty,
|
||||||
websitePositionProperty,
|
websiteWidthProperty,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
this.coWebsitesOpenByLayer.set(layer, {
|
coWebsiteOpen.coWebsite = coWebsite;
|
||||||
coWebsite: coWebsite,
|
|
||||||
state: OpenCoWebsiteState.ASLEEP,
|
|
||||||
});
|
|
||||||
|
|
||||||
const openWebsiteFunction = () => {
|
coWebsiteManager.addCoWebsiteToStore(coWebsite, websitePositionProperty);
|
||||||
coWebsiteManager
|
|
||||||
.loadCoWebsite(coWebsite)
|
|
||||||
.then((coWebsite) => {
|
|
||||||
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
|
||||||
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
|
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
|
||||||
console.error("Error during a co-website closing");
|
|
||||||
});
|
|
||||||
this.coWebsitesOpenByLayer.delete(layer);
|
|
||||||
} else {
|
|
||||||
this.coWebsitesOpenByLayer.set(layer, {
|
|
||||||
coWebsite,
|
|
||||||
state: OpenCoWebsiteState.OPENED,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
console.error("Error during loading a co-website: " + coWebsite.url);
|
|
||||||
});
|
|
||||||
|
|
||||||
layoutManagerActionStore.removeAction(actionUuid);
|
loadCoWebsiteFunction(coWebsite);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!localUserStore.getForceCowebsiteTrigger() &&
|
localUserStore.getForceCowebsiteTrigger() ||
|
||||||
websiteTriggerProperty !== ON_ACTION_TRIGGER_BUTTON
|
websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON
|
||||||
) {
|
) {
|
||||||
openWebsiteFunction();
|
if (!websiteTriggerMessageProperty) {
|
||||||
|
websiteTriggerMessageProperty = get(LL).trigger.cowebsite();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coWebsitesActionTriggerByLayer.set(layer, actionId);
|
||||||
|
|
||||||
|
layoutManagerActionStore.addAction({
|
||||||
|
uuid: actionId,
|
||||||
|
type: "message",
|
||||||
|
message: websiteTriggerMessageProperty,
|
||||||
|
callback: () => openCoWebsiteFunction(),
|
||||||
|
userInputManager: this.scene.userInputManager,
|
||||||
|
});
|
||||||
|
} else if (websiteTriggerProperty === ON_ICON_TRIGGER_BUTTON) {
|
||||||
|
const coWebsite = new SimpleCoWebsite(
|
||||||
|
new URL(openWebsiteProperty ?? "", this.scene.MapUrlFile),
|
||||||
|
allowApiProperty,
|
||||||
|
websitePolicyProperty,
|
||||||
|
websiteWidthProperty,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
coWebsiteOpen.coWebsite = coWebsite;
|
||||||
|
|
||||||
|
coWebsiteManager.addCoWebsiteToStore(coWebsite, websitePositionProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!websiteTriggerProperty) {
|
||||||
|
openCoWebsiteFunction();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -183,15 +333,35 @@ export class GameMapPropertiesListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coWebsiteOpen.state === OpenCoWebsiteState.ASLEEP) {
|
const coWebsite = coWebsiteOpen.coWebsite;
|
||||||
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coWebsiteOpen.coWebsite !== undefined) {
|
if (coWebsite) {
|
||||||
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite).catch((e) => console.error(e));
|
coWebsiteManager.closeCoWebsite(coWebsite);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.coWebsitesOpenByLayer.delete(layer);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coWebsitesActionTriggerByLayer.delete(layer);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { get, Unsubscriber } from "svelte/store";
|
|||||||
|
|
||||||
import { userMessageManager } from "../../Administration/UserMessageManager";
|
import { userMessageManager } from "../../Administration/UserMessageManager";
|
||||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
import { CoWebsite, coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { urlManager } from "../../Url/UrlManager";
|
import { urlManager } from "../../Url/UrlManager";
|
||||||
import { mediaManager } from "../../WebRtc/MediaManager";
|
import { mediaManager } from "../../WebRtc/MediaManager";
|
||||||
import { UserInputManager } from "../UserInput/UserInputManager";
|
import { UserInputManager } from "../UserInput/UserInputManager";
|
||||||
@ -20,9 +20,8 @@ import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
|||||||
|
|
||||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||||
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
|
|
||||||
import { iframeListener } from "../../Api/IframeListener";
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||||
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
||||||
import { Room } from "../../Connexion/Room";
|
import { Room } from "../../Connexion/Room";
|
||||||
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||||
@ -76,7 +75,7 @@ import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
|
|||||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||||
import { contactPageStore } from "../../Stores/MenuStore";
|
import { contactPageStore } from "../../Stores/MenuStore";
|
||||||
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
|
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
|
||||||
import { audioManagerFileStore, audioManagerVisibilityStore } from "../../Stores/AudioManagerStore";
|
import { audioManagerFileStore } from "../../Stores/AudioManagerStore";
|
||||||
|
|
||||||
import EVENT_TYPE = Phaser.Scenes.Events;
|
import EVENT_TYPE = Phaser.Scenes.Events;
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
@ -92,6 +91,11 @@ import { MapStore } from "../../Stores/Utils/MapStore";
|
|||||||
import { followUsersColorStore } from "../../Stores/FollowStore";
|
import { followUsersColorStore } from "../../Stores/FollowStore";
|
||||||
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
|
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
|
||||||
import { locale } from "../../i18n/i18n-svelte";
|
import { locale } from "../../i18n/i18n-svelte";
|
||||||
|
import { StringUtils } from "../../Utils/StringUtils";
|
||||||
|
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||||
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
|
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||||
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
reconnecting: boolean;
|
reconnecting: boolean;
|
||||||
@ -540,6 +544,8 @@ export class GameScene extends DirtyScene {
|
|||||||
urlManager.getStartLayerNameFromUrl()
|
urlManager.getStartLayerNameFromUrl()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
startLayerNamesStore.set(this.startPositionCalculator.getStartPositionNames());
|
||||||
|
|
||||||
//add entities
|
//add entities
|
||||||
this.Objects = new Array<Phaser.Physics.Arcade.Sprite>();
|
this.Objects = new Array<Phaser.Physics.Arcade.Sprite>();
|
||||||
|
|
||||||
@ -559,7 +565,7 @@ export class GameScene extends DirtyScene {
|
|||||||
|
|
||||||
this.pathfindingManager = new PathfindingManager(
|
this.pathfindingManager = new PathfindingManager(
|
||||||
this,
|
this,
|
||||||
this.gameMap.getCollisionsGrid(),
|
this.gameMap.getCollisionGrid(),
|
||||||
this.gameMap.getTileDimensions()
|
this.gameMap.getTileDimensions()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -567,6 +573,8 @@ export class GameScene extends DirtyScene {
|
|||||||
this.createCurrentPlayer();
|
this.createCurrentPlayer();
|
||||||
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
|
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
|
||||||
|
|
||||||
|
this.tryMovePlayerWithMoveToParameter();
|
||||||
|
|
||||||
this.cameraManager = new CameraManager(
|
this.cameraManager = new CameraManager(
|
||||||
this,
|
this,
|
||||||
{ x: this.Map.widthInPixels, y: this.Map.heightInPixels },
|
{ x: this.Map.widthInPixels, y: this.Map.heightInPixels },
|
||||||
@ -575,7 +583,7 @@ export class GameScene extends DirtyScene {
|
|||||||
|
|
||||||
this.pathfindingManager = new PathfindingManager(
|
this.pathfindingManager = new PathfindingManager(
|
||||||
this,
|
this,
|
||||||
this.gameMap.getCollisionsGrid(),
|
this.gameMap.getCollisionGrid(),
|
||||||
this.gameMap.getTileDimensions()
|
this.gameMap.getTileDimensions()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -626,7 +634,6 @@ export class GameScene extends DirtyScene {
|
|||||||
);
|
);
|
||||||
|
|
||||||
new GameMapPropertiesListener(this, this.gameMap).register();
|
new GameMapPropertiesListener(this, this.gameMap).register();
|
||||||
this.triggerOnMapLayerPropertyChange();
|
|
||||||
|
|
||||||
if (!this.room.isDisconnected()) {
|
if (!this.room.isDisconnected()) {
|
||||||
this.scene.sleep();
|
this.scene.sleep();
|
||||||
@ -793,7 +800,19 @@ export class GameScene extends DirtyScene {
|
|||||||
* Triggered when we receive the JWT token to connect to Jitsi
|
* Triggered when we receive the JWT token to connect to Jitsi
|
||||||
*/
|
*/
|
||||||
this.connection.sendJitsiJwtMessageStream.subscribe((message) => {
|
this.connection.sendJitsiJwtMessageStream.subscribe((message) => {
|
||||||
this.startJitsi(message.jitsiRoom, message.jwt);
|
if (!JITSI_URL) {
|
||||||
|
throw new Error("Missing JITSI_URL environment variable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain = JITSI_URL;
|
||||||
|
|
||||||
|
if (domain.substring(0, 7) !== "http://" && domain.substring(0, 8) !== "https://") {
|
||||||
|
domain = `${location.protocol}//${domain}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
|
||||||
|
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
|
||||||
|
this.initialiseJitsi(coWebsite, message.jitsiRoom, message.jwt);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
|
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
|
||||||
@ -930,103 +949,6 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private triggerOnMapLayerPropertyChange() {
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue, oldValue) => {
|
|
||||||
if (newValue) {
|
|
||||||
this.onMapExit(
|
|
||||||
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
|
|
||||||
).catch((e) => console.error(e));
|
|
||||||
} else {
|
|
||||||
setTimeout(() => {
|
|
||||||
layoutManagerActionStore.removeAction("roomAccessDenied");
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
|
|
||||||
if (newValue) {
|
|
||||||
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString())).catch((e) =>
|
|
||||||
console.error(e)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setTimeout(() => {
|
|
||||||
layoutManagerActionStore.removeAction("roomAccessDenied");
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.JITSI_ROOM, (newValue, oldValue, allProps) => {
|
|
||||||
if (newValue === undefined) {
|
|
||||||
layoutManagerActionStore.removeAction("jitsi");
|
|
||||||
this.stopJitsi();
|
|
||||||
} else {
|
|
||||||
const openJitsiRoomFunction = () => {
|
|
||||||
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance);
|
|
||||||
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
|
||||||
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
|
|
||||||
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
|
|
||||||
|
|
||||||
this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
|
|
||||||
} else {
|
|
||||||
this.startJitsi(roomName, undefined);
|
|
||||||
}
|
|
||||||
layoutManagerActionStore.removeAction("jitsi");
|
|
||||||
};
|
|
||||||
|
|
||||||
const jitsiTriggerValue = allProps.get(GameMapProperties.JITSI_TRIGGER);
|
|
||||||
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
|
|
||||||
if (forceTrigger || jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
|
||||||
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
|
|
||||||
if (message === undefined) {
|
|
||||||
message = "Press SPACE or touch here to enter Jitsi Meet room";
|
|
||||||
}
|
|
||||||
layoutManagerActionStore.addAction({
|
|
||||||
uuid: "jitsi",
|
|
||||||
type: "message",
|
|
||||||
message: message,
|
|
||||||
callback: () => openJitsiRoomFunction(),
|
|
||||||
userInputManager: this.userInputManager,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
openJitsiRoomFunction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue, oldValue) => {
|
|
||||||
if (newValue === undefined || newValue === false || newValue === "") {
|
|
||||||
this.connection?.setSilent(false);
|
|
||||||
this.CurrentPlayer.noSilent();
|
|
||||||
} else {
|
|
||||||
this.connection?.setSilent(true);
|
|
||||||
this.CurrentPlayer.isSilent();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO, (newValue, oldValue, allProps) => {
|
|
||||||
const volume = allProps.get(GameMapProperties.AUDIO_VOLUME) as number | undefined;
|
|
||||||
const loop = allProps.get(GameMapProperties.AUDIO_LOOP) as boolean | undefined;
|
|
||||||
newValue === undefined
|
|
||||||
? audioManagerFileStore.unloadAudio()
|
|
||||||
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), volume, loop);
|
|
||||||
audioManagerVisibilityStore.set(!(newValue === undefined));
|
|
||||||
});
|
|
||||||
// TODO: This legacy property should be removed at some point
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue, oldValue) => {
|
|
||||||
newValue === undefined
|
|
||||||
? audioManagerFileStore.unloadAudio()
|
|
||||||
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), undefined, true);
|
|
||||||
audioManagerVisibilityStore.set(!(newValue === undefined));
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Legacy functionnality replace by layer change
|
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.ZONE, (newValue, oldValue) => {
|
|
||||||
if (oldValue) {
|
|
||||||
iframeListener.sendLeaveEvent(oldValue as string);
|
|
||||||
}
|
|
||||||
if (newValue) {
|
|
||||||
iframeListener.sendEnterEvent(newValue as string);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private listenToIframeEvents(): void {
|
private listenToIframeEvents(): void {
|
||||||
this.iframeSubscriptionList = [];
|
this.iframeSubscriptionList = [];
|
||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
@ -1259,12 +1181,11 @@ ${escapedMessage}
|
|||||||
throw new Error("Unknown query source");
|
throw new Error("Unknown query source");
|
||||||
}
|
}
|
||||||
|
|
||||||
const coWebsite = coWebsiteManager.addCoWebsite(
|
const coWebsite: SimpleCoWebsite = new SimpleCoWebsite(
|
||||||
openCoWebsite.url,
|
new URL(openCoWebsite.url, iframeListener.getBaseUrlFromSource(source)),
|
||||||
iframeListener.getBaseUrlFromSource(source),
|
|
||||||
openCoWebsite.allowApi,
|
openCoWebsite.allowApi,
|
||||||
openCoWebsite.allowPolicy,
|
openCoWebsite.allowPolicy,
|
||||||
openCoWebsite.position,
|
openCoWebsite.widthPercent,
|
||||||
openCoWebsite.closable ?? true
|
openCoWebsite.closable ?? true
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1273,7 +1194,7 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: coWebsite.iframe.id,
|
id: coWebsite.getId(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1282,27 +1203,23 @@ ${escapedMessage}
|
|||||||
|
|
||||||
return coWebsites.map((coWebsite: CoWebsite) => {
|
return coWebsites.map((coWebsite: CoWebsite) => {
|
||||||
return {
|
return {
|
||||||
id: coWebsite.iframe.id,
|
id: coWebsite.getId(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer("closeCoWebsite", async (coWebsiteId) => {
|
iframeListener.registerAnswerer("closeCoWebsite", (coWebsiteId) => {
|
||||||
const coWebsite = coWebsiteManager.getCoWebsiteById(coWebsiteId);
|
const coWebsite = coWebsiteManager.getCoWebsiteById(coWebsiteId);
|
||||||
|
|
||||||
if (!coWebsite) {
|
if (!coWebsite) {
|
||||||
throw new Error("Unknown co-website");
|
throw new Error("Unknown co-website");
|
||||||
}
|
}
|
||||||
|
|
||||||
return coWebsiteManager.closeCoWebsite(coWebsite).catch((error) => {
|
return coWebsiteManager.closeCoWebsite(coWebsite);
|
||||||
throw new Error("Error on closing co-website");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer("closeCoWebsites", async () => {
|
iframeListener.registerAnswerer("closeCoWebsites", () => {
|
||||||
return await coWebsiteManager.closeCoWebsites().catch((error) => {
|
return coWebsiteManager.closeCoWebsites();
|
||||||
throw new Error("Error on closing all co-websites");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer("getMapData", () => {
|
iframeListener.registerAnswerer("getMapData", () => {
|
||||||
@ -1387,7 +1304,7 @@ ${escapedMessage}
|
|||||||
//Create new colliders with the new GameMap
|
//Create new colliders with the new GameMap
|
||||||
this.createCollisionWithPlayer();
|
this.createCollisionWithPlayer();
|
||||||
//Create new trigger with the new GameMap
|
//Create new trigger with the new GameMap
|
||||||
this.triggerOnMapLayerPropertyChange();
|
new GameMapPropertiesListener(this, this.gameMap).register();
|
||||||
resolve(newFirstgid);
|
resolve(newFirstgid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1458,9 +1375,9 @@ ${escapedMessage}
|
|||||||
});
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer("movePlayerTo", async (message) => {
|
iframeListener.registerAnswerer("movePlayerTo", async (message) => {
|
||||||
const index = this.getGameMap().getTileIndexAt(message.x, message.y);
|
const startTileIndex = this.getGameMap().getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
||||||
const startTile = this.getGameMap().getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
const destinationTileIndex = this.getGameMap().getTileIndexAt(message.x, message.y);
|
||||||
const path = await this.getPathfindingManager().findPath(startTile, index, true, true);
|
const path = await this.getPathfindingManager().findPath(startTileIndex, destinationTileIndex, true, true);
|
||||||
path.shift();
|
path.shift();
|
||||||
if (path.length === 0) {
|
if (path.length === 0) {
|
||||||
throw new Error("no path available");
|
throw new Error("no path available");
|
||||||
@ -1500,14 +1417,15 @@ ${escapedMessage}
|
|||||||
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid());
|
||||||
this.markDirty();
|
this.markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMapDirUrl(): string {
|
public getMapDirUrl(): string {
|
||||||
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/"));
|
return this.MapUrlFile.substring(0, this.MapUrlFile.lastIndexOf("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onMapExit(roomUrl: URL) {
|
public async onMapExit(roomUrl: URL) {
|
||||||
if (this.mapTransitioning) return;
|
if (this.mapTransitioning) return;
|
||||||
this.mapTransitioning = true;
|
this.mapTransitioning = true;
|
||||||
|
|
||||||
@ -1566,14 +1484,13 @@ ${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.closeCoWebsites().catch((e) => console.error(e));
|
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) {
|
||||||
iframeListener.unregisterScript(script);
|
iframeListener.unregisterScript(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopJitsi();
|
|
||||||
audioManagerFileStore.unloadAudio();
|
audioManagerFileStore.unloadAudio();
|
||||||
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
||||||
this.connection?.closeConnection();
|
this.connection?.closeConnection();
|
||||||
@ -1624,6 +1541,36 @@ ${escapedMessage}
|
|||||||
this.MapPlayersByKey.clear();
|
this.MapPlayersByKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private tryMovePlayerWithMoveToParameter(): void {
|
||||||
|
const moveToParam = urlManager.getHashParameter("moveTo");
|
||||||
|
if (moveToParam) {
|
||||||
|
try {
|
||||||
|
let endPos;
|
||||||
|
const posFromParam = StringUtils.parsePointFromParam(moveToParam);
|
||||||
|
if (posFromParam) {
|
||||||
|
endPos = this.gameMap.getTileIndexAt(posFromParam.x, posFromParam.y);
|
||||||
|
} else {
|
||||||
|
const destinationObject = this.gameMap.getObjectWithName(moveToParam);
|
||||||
|
if (destinationObject) {
|
||||||
|
endPos = this.gameMap.getTileIndexAt(destinationObject.x, destinationObject.y);
|
||||||
|
} else {
|
||||||
|
endPos = this.gameMap.getRandomPositionFromLayer(moveToParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.pathfindingManager
|
||||||
|
.findPath(this.gameMap.getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y), endPos)
|
||||||
|
.then((path) => {
|
||||||
|
if (path && path.length > 0) {
|
||||||
|
this.CurrentPlayer.setPathToFollow(path).catch((reason) => console.warn(reason));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason) => console.warn(reason));
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private getExitUrl(layer: ITiledMapLayer): string | undefined {
|
private getExitUrl(layer: ITiledMapLayer): string | undefined {
|
||||||
return this.getProperty(layer, GameMapProperties.EXIT_URL) as string | undefined;
|
return this.getProperty(layer, GameMapProperties.EXIT_URL) as string | undefined;
|
||||||
}
|
}
|
||||||
@ -1736,26 +1683,16 @@ ${escapedMessage}
|
|||||||
emoteMenuStore.openEmoteMenu();
|
emoteMenuStore.openEmoteMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.CurrentPlayer.on(Phaser.Input.Events.POINTER_OVER, (pointer: Phaser.Input.Pointer) => {
|
||||||
|
this.CurrentPlayer.pointerOverOutline(0x00ffff);
|
||||||
|
});
|
||||||
|
this.CurrentPlayer.on(Phaser.Input.Events.POINTER_OUT, (pointer: Phaser.Input.Pointer) => {
|
||||||
|
this.CurrentPlayer.pointerOutOutline();
|
||||||
|
});
|
||||||
this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => {
|
this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => {
|
||||||
this.connection?.emitEmoteEvent(emoteKey);
|
this.connection?.emitEmoteEvent(emoteKey);
|
||||||
analyticsClient.launchEmote(emoteKey);
|
analyticsClient.launchEmote(emoteKey);
|
||||||
});
|
});
|
||||||
const moveToParam = urlManager.getHashParameter("moveTo");
|
|
||||||
if (moveToParam) {
|
|
||||||
try {
|
|
||||||
const endPos = this.gameMap.getRandomPositionFromLayer(moveToParam);
|
|
||||||
this.pathfindingManager
|
|
||||||
.findPath(this.gameMap.getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y), endPos)
|
|
||||||
.then((path) => {
|
|
||||||
if (path && path.length > 0) {
|
|
||||||
this.CurrentPlayer.setPathToFollow(path).catch((reason) => console.warn(reason));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((reason) => console.warn(reason));
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof TextureError) {
|
if (err instanceof TextureError) {
|
||||||
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
||||||
@ -2108,7 +2045,7 @@ ${escapedMessage}
|
|||||||
mediaManager.hideMyCamera();
|
mediaManager.hideMyCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
public startJitsi(roomName: string, jwt?: string): void {
|
public initialiseJitsi(coWebsite: JitsiCoWebsite, roomName: string, jwt?: string): void {
|
||||||
const allProps = this.gameMap.getCurrentProperties();
|
const allProps = this.gameMap.getCurrentProperties();
|
||||||
const jitsiConfig = this.safeParseJSONstring(
|
const jitsiConfig = this.safeParseJSONstring(
|
||||||
allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined,
|
allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined,
|
||||||
@ -2120,20 +2057,15 @@ ${escapedMessage}
|
|||||||
);
|
);
|
||||||
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||||
|
|
||||||
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl).catch(() => {
|
coWebsite.setJitsiLoadPromise(() => {
|
||||||
console.error("Cannot start a Jitsi co-website");
|
return jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl);
|
||||||
});
|
});
|
||||||
this.disableMediaBehaviors();
|
|
||||||
analyticsClient.enteredJitsi(roomName, this.room.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public stopJitsi(): void {
|
coWebsiteManager.loadCoWebsite(coWebsite).catch((err) => {
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
console.error(err);
|
||||||
if (coWebsite) {
|
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => {
|
|
||||||
console.error("Error during Jitsi co-website closing", e);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
analyticsClient.enteredJitsi(roomName, this.room.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
||||||
|
@ -3,8 +3,8 @@ export interface OutlineableInterface {
|
|||||||
removeFollowOutlineColor(): void;
|
removeFollowOutlineColor(): void;
|
||||||
setApiOutlineColor(color: number): void;
|
setApiOutlineColor(color: number): void;
|
||||||
removeApiOutlineColor(): void;
|
removeApiOutlineColor(): void;
|
||||||
pointerOverOutline(): void;
|
pointerOverOutline(color: number): void;
|
||||||
pointerOutOutline(): void;
|
pointerOutOutline(): void;
|
||||||
characterCloseByOutline(): void;
|
characterCloseByOutline(color: number): void;
|
||||||
characterFarAwayOutline(): void;
|
characterFarAwayOutline(): void;
|
||||||
}
|
}
|
||||||
|
@ -16,32 +16,6 @@ export class StartPositionCalculator {
|
|||||||
) {
|
) {
|
||||||
this.initStartXAndStartY();
|
this.initStartXAndStartY();
|
||||||
}
|
}
|
||||||
private initStartXAndStartY() {
|
|
||||||
// If there is an init position passed
|
|
||||||
if (this.initPosition !== null) {
|
|
||||||
this.startPosition = this.initPosition;
|
|
||||||
} else {
|
|
||||||
// Now, let's find the start layer
|
|
||||||
if (this.startLayerName) {
|
|
||||||
this.initPositionFromLayerName(this.startLayerName, this.startLayerName);
|
|
||||||
}
|
|
||||||
if (this.startPosition === undefined) {
|
|
||||||
// If we have no start layer specified or if the hash passed does not exist, let's go with the default start position.
|
|
||||||
this.initPositionFromLayerName(defaultStartLayerName, this.startLayerName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Still no start position? Something is wrong with the map, we need a "start" layer.
|
|
||||||
if (this.startPosition === undefined) {
|
|
||||||
console.warn(
|
|
||||||
'This map is missing a layer named "start" that contains the available default start positions.'
|
|
||||||
);
|
|
||||||
// Let's start in the middle of the map
|
|
||||||
this.startPosition = {
|
|
||||||
x: this.mapFile.width * 16,
|
|
||||||
y: this.mapFile.height * 16,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -76,6 +50,47 @@ export class StartPositionCalculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getStartPositionNames(): string[] {
|
||||||
|
const names: string[] = [];
|
||||||
|
for (const layer of this.gameMap.flatLayers) {
|
||||||
|
if (layer.name === "start") {
|
||||||
|
names.push(layer.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.isStartLayer(layer)) {
|
||||||
|
names.push(layer.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initStartXAndStartY() {
|
||||||
|
// If there is an init position passed
|
||||||
|
if (this.initPosition !== null) {
|
||||||
|
this.startPosition = this.initPosition;
|
||||||
|
} else {
|
||||||
|
// Now, let's find the start layer
|
||||||
|
if (this.startLayerName) {
|
||||||
|
this.initPositionFromLayerName(this.startLayerName, this.startLayerName);
|
||||||
|
}
|
||||||
|
if (this.startPosition === undefined) {
|
||||||
|
// If we have no start layer specified or if the hash passed does not exist, let's go with the default start position.
|
||||||
|
this.initPositionFromLayerName(defaultStartLayerName, this.startLayerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Still no start position? Something is wrong with the map, we need a "start" layer.
|
||||||
|
if (this.startPosition === undefined) {
|
||||||
|
console.warn(
|
||||||
|
'This map is missing a layer named "start" that contains the available default start positions.'
|
||||||
|
);
|
||||||
|
// Let's start in the middle of the map
|
||||||
|
this.startPosition = {
|
||||||
|
x: this.mapFile.width * 16,
|
||||||
|
y: this.mapFile.height * 16,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private isStartLayer(layer: ITiledMapLayer): boolean {
|
private isStartLayer(layer: ITiledMapLayer): boolean {
|
||||||
return this.getProperty(layer, GameMapProperties.START_LAYER) == true;
|
return this.getProperty(layer, GameMapProperties.START_LAYER) == true;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,8 @@ export interface ITiledMapTileLayer {
|
|||||||
width: number;
|
width: number;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
parallaxx?: number;
|
||||||
|
parallaxy?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw order (topdown (default), index)
|
* Draw order (topdown (default), index)
|
||||||
|
@ -25,7 +25,7 @@ export class Player extends Character {
|
|||||||
direction: PlayerAnimationDirections,
|
direction: PlayerAnimationDirections,
|
||||||
moving: boolean,
|
moving: boolean,
|
||||||
companion: string | null,
|
companion: string | null,
|
||||||
companionTexturePromise?: Promise<string>
|
companionTexturePromise?: CancelablePromise<string>
|
||||||
) {
|
) {
|
||||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise);
|
super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise);
|
||||||
|
|
||||||
|
@ -53,10 +53,20 @@ export class GameSceneUserInputHandler implements UserInputHandlerInterface {
|
|||||||
public handlePointerDownEvent(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]): void {}
|
public handlePointerDownEvent(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]): void {}
|
||||||
|
|
||||||
public handleSpaceKeyUpEvent(event: Event): Event {
|
public handleSpaceKeyUpEvent(event: Event): Event {
|
||||||
const activatable = this.gameScene.getActivatablesManager().getSelectedActivatableObject();
|
const activatableManager = this.gameScene.getActivatablesManager();
|
||||||
if (activatable && activatable.isActivatable()) {
|
const activatable = activatableManager.getSelectedActivatableObject();
|
||||||
|
if (activatable && activatable.isActivatable() && activatableManager.isSelectingByDistanceEnabled()) {
|
||||||
activatable.activate();
|
activatable.activate();
|
||||||
}
|
}
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addSpaceEventListener(callback: Function): void {
|
||||||
|
this.gameScene.input.keyboard.addListener("keyup-SPACE", callback);
|
||||||
|
this.gameScene.getActivatablesManager().disableSelectingByDistance();
|
||||||
|
}
|
||||||
|
public removeSpaceEventListner(callback: Function): void {
|
||||||
|
this.gameScene.input.keyboard.removeListener("keyup-SPACE", callback);
|
||||||
|
this.gameScene.getActivatablesManager().enableSelectingByDistance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,10 +223,10 @@ export class UserInputManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSpaceEventListner(callback: Function) {
|
addSpaceEventListner(callback: Function) {
|
||||||
this.scene.input.keyboard.addListener("keyup-SPACE", callback);
|
this.userInputHandler.addSpaceEventListener(callback);
|
||||||
}
|
}
|
||||||
removeSpaceEventListner(callback: Function) {
|
removeSpaceEventListner(callback: Function) {
|
||||||
this.scene.input.keyboard.removeListener("keyup-SPACE", callback);
|
this.userInputHandler.removeSpaceEventListner(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
@ -255,6 +255,11 @@ export class UserInputManager {
|
|||||||
(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => {
|
(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => {
|
||||||
this.joystick?.hide();
|
this.joystick?.hide();
|
||||||
this.userInputHandler.handlePointerUpEvent(pointer, gameObjects);
|
this.userInputHandler.handlePointerUpEvent(pointer, gameObjects);
|
||||||
|
|
||||||
|
// Disable focus on iframe (need by Firefox)
|
||||||
|
if (pointer.downElement.nodeName === "CANVAS" && document.activeElement instanceof HTMLIFrameElement) {
|
||||||
|
document.activeElement.blur();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { derived, get, writable } from "svelte/store";
|
import { derived, writable } from "svelte/store";
|
||||||
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
|
import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
|
||||||
|
|
||||||
function createCoWebsiteStore() {
|
function createCoWebsiteStore() {
|
||||||
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
||||||
@ -9,7 +9,7 @@ function createCoWebsiteStore() {
|
|||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
add: (coWebsite: CoWebsite, position?: number) => {
|
add: (coWebsite: CoWebsite, position?: number) => {
|
||||||
coWebsite.state.subscribe((value) => {
|
coWebsite.getStateSubscriber().subscribe((value) => {
|
||||||
update((currentArray) => currentArray);
|
update((currentArray) => currentArray);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ function createCoWebsiteStore() {
|
|||||||
},
|
},
|
||||||
remove: (coWebsite: CoWebsite) => {
|
remove: (coWebsite: CoWebsite) => {
|
||||||
update((currentArray) => [
|
update((currentArray) => [
|
||||||
...currentArray.filter((currentCoWebsite) => currentCoWebsite.iframe.id !== coWebsite.iframe.id),
|
...currentArray.filter((currentCoWebsite) => currentCoWebsite.getId() !== coWebsite.getId()),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
empty: () => {
|
empty: () => {
|
||||||
@ -43,9 +43,9 @@ function createCoWebsiteStore() {
|
|||||||
export const coWebsites = createCoWebsiteStore();
|
export const coWebsites = createCoWebsiteStore();
|
||||||
|
|
||||||
export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
|
export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
|
||||||
$coWebsites.filter((coWebsite) => get(coWebsite.state) !== "asleep")
|
$coWebsites.filter((coWebsite) => coWebsite.getState() !== "asleep")
|
||||||
);
|
);
|
||||||
|
|
||||||
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
|
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
|
||||||
$coWebsites.find((coWebsite) => get(coWebsite.state) !== "asleep")
|
$coWebsites.find((coWebsite) => coWebsite.getState() !== "asleep")
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { derived, get, writable } from "svelte/store";
|
import { derived, get, writable } from "svelte/store";
|
||||||
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
|
import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
|
||||||
import { LayoutMode } from "../WebRtc/LayoutManager";
|
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||||
import { coWebsites } from "./CoWebsiteStore";
|
import { coWebsites } from "./CoWebsiteStore";
|
||||||
import { Streamable, streamableCollectionStore } from "./StreamableCollectionStore";
|
import { Streamable, streamableCollectionStore } from "./StreamableCollectionStore";
|
||||||
@ -31,7 +31,7 @@ function createHighlightedEmbedScreenStore() {
|
|||||||
embedScreen.type !== currentEmbedScreen.type ||
|
embedScreen.type !== currentEmbedScreen.type ||
|
||||||
(embedScreen.type === "cowebsite" &&
|
(embedScreen.type === "cowebsite" &&
|
||||||
currentEmbedScreen.type === "cowebsite" &&
|
currentEmbedScreen.type === "cowebsite" &&
|
||||||
embedScreen.embed.iframe.id !== currentEmbedScreen.embed.iframe.id) ||
|
embedScreen.embed.getId() !== currentEmbedScreen.embed.getId()) ||
|
||||||
(embedScreen.type === "streamable" &&
|
(embedScreen.type === "streamable" &&
|
||||||
currentEmbedScreen.type === "streamable" &&
|
currentEmbedScreen.type === "streamable" &&
|
||||||
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)
|
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { derived, writable } from "svelte/store";
|
import { derived, writable } from "svelte/store";
|
||||||
|
import type { ActivatablesManager } from "../Phaser/Game/ActivatablesManager";
|
||||||
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
||||||
|
|
||||||
export interface LayoutManagerAction {
|
export interface LayoutManagerAction {
|
||||||
|
@ -5,38 +5,33 @@ export function createColorStore() {
|
|||||||
|
|
||||||
let followColor: number | undefined = undefined;
|
let followColor: number | undefined = undefined;
|
||||||
let apiColor: number | undefined = undefined;
|
let apiColor: number | undefined = undefined;
|
||||||
|
let pointedByPointer: number | undefined = undefined;
|
||||||
let pointedByPointer: boolean = false;
|
let pointedByCharacter: number | undefined = undefined;
|
||||||
let pointedByCharacter: boolean = false;
|
|
||||||
|
|
||||||
const updateColor = () => {
|
const updateColor = () => {
|
||||||
if (pointedByPointer || pointedByCharacter) {
|
set(pointedByPointer ?? pointedByCharacter ?? followColor ?? apiColor);
|
||||||
set(0xffff00);
|
|
||||||
} else {
|
|
||||||
set(followColor ?? apiColor);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
|
|
||||||
pointerOver() {
|
pointerOver(color: number) {
|
||||||
pointedByPointer = true;
|
pointedByPointer = color;
|
||||||
updateColor();
|
updateColor();
|
||||||
},
|
},
|
||||||
|
|
||||||
pointerOut() {
|
pointerOut() {
|
||||||
pointedByPointer = false;
|
pointedByPointer = undefined;
|
||||||
updateColor();
|
updateColor();
|
||||||
},
|
},
|
||||||
|
|
||||||
characterCloseBy() {
|
characterCloseBy(color: number) {
|
||||||
pointedByCharacter = true;
|
pointedByCharacter = color;
|
||||||
updateColor();
|
updateColor();
|
||||||
},
|
},
|
||||||
|
|
||||||
characterFarAway() {
|
characterFarAway() {
|
||||||
pointedByCharacter = false;
|
pointedByCharacter = undefined;
|
||||||
updateColor();
|
updateColor();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
6
front/src/Stores/StartLayerNamesStore.ts
Normal file
6
front/src/Stores/StartLayerNamesStore.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Readable, writable } from "svelte/store";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A store that contains the map starting layers names
|
||||||
|
*/
|
||||||
|
export const startLayerNamesStore = writable<string[]>([]);
|
@ -19,6 +19,10 @@ export class PathfindingManager {
|
|||||||
this.setEasyStarGrid(collisionsGrid);
|
this.setEasyStarGrid(collisionsGrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setCollisionGrid(collisionGrid: number[][]): void {
|
||||||
|
this.setEasyStarGrid(collisionGrid);
|
||||||
|
}
|
||||||
|
|
||||||
public async findPath(
|
public async findPath(
|
||||||
start: { x: number; y: number },
|
start: { x: number; y: number },
|
||||||
end: { x: number; y: number },
|
end: { x: number; y: number },
|
||||||
|
12
front/src/Utils/StringUtils.ts
Normal file
12
front/src/Utils/StringUtils.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export class StringUtils {
|
||||||
|
public static parsePointFromParam(param: string, separator: string = ","): { x: number; y: number } | undefined {
|
||||||
|
const values = param.split(separator).map((val) => parseInt(val));
|
||||||
|
if (values.length !== 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(values[0]) || isNaN(values[1])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return { x: values[0], y: values[1] };
|
||||||
|
}
|
||||||
|
}
|
17
front/src/WebRtc/CoWebsite/CoWesbite.ts
Normal file
17
front/src/WebRtc/CoWebsite/CoWesbite.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type CancelablePromise from "cancelable-promise";
|
||||||
|
import type { Readable, Writable } from "svelte/store";
|
||||||
|
|
||||||
|
export type CoWebsiteState = "asleep" | "loading" | "ready";
|
||||||
|
|
||||||
|
export interface CoWebsite {
|
||||||
|
getId(): string;
|
||||||
|
getUrl(): URL;
|
||||||
|
getState(): CoWebsiteState;
|
||||||
|
getStateSubscriber(): Readable<CoWebsiteState>;
|
||||||
|
getIframe(): HTMLIFrameElement | undefined;
|
||||||
|
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined;
|
||||||
|
getWidthPercent(): number | undefined;
|
||||||
|
isClosable(): boolean;
|
||||||
|
load(): CancelablePromise<HTMLIFrameElement>;
|
||||||
|
unload(): Promise<void>;
|
||||||
|
}
|
49
front/src/WebRtc/CoWebsite/JitsiCoWebsite.ts
Normal file
49
front/src/WebRtc/CoWebsite/JitsiCoWebsite.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
import { jitsiFactory } from "../JitsiFactory";
|
||||||
|
import { SimpleCoWebsite } from "./SimpleCoWebsite";
|
||||||
|
|
||||||
|
export class JitsiCoWebsite extends SimpleCoWebsite {
|
||||||
|
private jitsiLoadPromise?: () => CancelablePromise<HTMLIFrameElement>;
|
||||||
|
|
||||||
|
setJitsiLoadPromise(promise: () => CancelablePromise<HTMLIFrameElement>): void {
|
||||||
|
this.jitsiLoadPromise = promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
load(): CancelablePromise<HTMLIFrameElement> {
|
||||||
|
return new CancelablePromise((resolve, reject, cancel) => {
|
||||||
|
this.state.set("loading");
|
||||||
|
|
||||||
|
gameManager.getCurrentGameScene().disableMediaBehaviors();
|
||||||
|
|
||||||
|
if (!this.jitsiLoadPromise) {
|
||||||
|
return reject("Undefined Jitsi start callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
const jitsiLoading = this.jitsiLoadPromise()
|
||||||
|
.then((iframe) => {
|
||||||
|
this.iframe = iframe;
|
||||||
|
this.iframe.classList.add("pixel");
|
||||||
|
this.state.set("ready");
|
||||||
|
return resolve(iframe);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
return reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
cancel(() => {
|
||||||
|
jitsiLoading.cancel();
|
||||||
|
this.unload().catch((err) => {
|
||||||
|
console.error("Cannot unload Jitsi co-website while cancel loading", err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unload(): Promise<void> {
|
||||||
|
jitsiFactory.destroy();
|
||||||
|
gameManager.getCurrentGameScene().enableMediaBehaviors();
|
||||||
|
|
||||||
|
return super.unload();
|
||||||
|
}
|
||||||
|
}
|
133
front/src/WebRtc/CoWebsite/SimpleCoWebsite.ts
Normal file
133
front/src/WebRtc/CoWebsite/SimpleCoWebsite.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
import { get, Readable, writable, Writable } from "svelte/store";
|
||||||
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
|
import { coWebsiteManager } from "../CoWebsiteManager";
|
||||||
|
import type { CoWebsite, CoWebsiteState } from "./CoWesbite";
|
||||||
|
|
||||||
|
export class SimpleCoWebsite implements CoWebsite {
|
||||||
|
protected id: string;
|
||||||
|
protected url: URL;
|
||||||
|
protected state: Writable<CoWebsiteState>;
|
||||||
|
protected iframe?: HTMLIFrameElement;
|
||||||
|
protected loadIframe?: CancelablePromise<HTMLIFrameElement>;
|
||||||
|
protected allowApi?: boolean;
|
||||||
|
protected allowPolicy?: string;
|
||||||
|
protected widthPercent?: number;
|
||||||
|
protected closable: boolean;
|
||||||
|
|
||||||
|
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
|
||||||
|
this.id = coWebsiteManager.generateUniqueId();
|
||||||
|
this.url = url;
|
||||||
|
this.state = writable("asleep" as CoWebsiteState);
|
||||||
|
this.allowApi = allowApi;
|
||||||
|
this.allowPolicy = allowPolicy;
|
||||||
|
this.widthPercent = widthPercent;
|
||||||
|
this.closable = closable ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getId(): string {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
getUrl(): URL {
|
||||||
|
return this.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
getState(): CoWebsiteState {
|
||||||
|
return get(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStateSubscriber(): Readable<CoWebsiteState> {
|
||||||
|
return this.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIframe(): HTMLIFrameElement | undefined {
|
||||||
|
return this.iframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined {
|
||||||
|
return this.loadIframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
getWidthPercent(): number | undefined {
|
||||||
|
return this.widthPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
isClosable(): boolean {
|
||||||
|
return this.closable;
|
||||||
|
}
|
||||||
|
|
||||||
|
load(): CancelablePromise<HTMLIFrameElement> {
|
||||||
|
this.loadIframe = new CancelablePromise((resolve, reject, cancel) => {
|
||||||
|
this.state.set("loading");
|
||||||
|
|
||||||
|
const iframe = document.createElement("iframe");
|
||||||
|
this.iframe = iframe;
|
||||||
|
this.iframe.src = this.url.toString();
|
||||||
|
this.iframe.id = this.id;
|
||||||
|
|
||||||
|
if (this.allowPolicy) {
|
||||||
|
this.iframe.allow = this.allowPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.allowApi) {
|
||||||
|
iframeListener.registerIframe(this.iframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.iframe.classList.add("pixel");
|
||||||
|
|
||||||
|
const onloadPromise = new Promise<void>((resolve) => {
|
||||||
|
if (this.iframe) {
|
||||||
|
this.iframe.onload = () => {
|
||||||
|
this.state.set("ready");
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onTimeoutPromise = new Promise<void>((resolve) => {
|
||||||
|
setTimeout(() => resolve(), 2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
coWebsiteManager.getCoWebsiteBuffer().appendChild(this.iframe);
|
||||||
|
|
||||||
|
const race = CancelablePromise.race([onloadPromise, onTimeoutPromise])
|
||||||
|
.then(() => {
|
||||||
|
return resolve(iframe);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Error on co-website loading => ", err);
|
||||||
|
return reject();
|
||||||
|
});
|
||||||
|
|
||||||
|
cancel(() => {
|
||||||
|
race.cancel();
|
||||||
|
this.unload().catch((err) => {
|
||||||
|
console.error("Cannot unload co-website while cancel loading", err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.loadIframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
unload(): Promise<void> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (this.iframe) {
|
||||||
|
if (this.allowApi) {
|
||||||
|
iframeListener.unregisterIframe(this.iframe);
|
||||||
|
}
|
||||||
|
this.iframe.parentNode?.removeChild(this.iframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.loadIframe) {
|
||||||
|
this.loadIframe.cancel();
|
||||||
|
this.loadIframe = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.set("asleep");
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,15 @@
|
|||||||
import { HtmlUtils } from "./HtmlUtils";
|
import { HtmlUtils } from "./HtmlUtils";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { iframeListener } from "../Api/IframeListener";
|
|
||||||
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
||||||
import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
||||||
import { get, Writable, writable } from "svelte/store";
|
import { get, Readable, Writable, writable } from "svelte/store";
|
||||||
import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore";
|
import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore";
|
||||||
import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils";
|
import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils";
|
||||||
import { jitsiFactory } from "./JitsiFactory";
|
|
||||||
import { gameManager } from "../Phaser/Game/GameManager";
|
|
||||||
import { LayoutMode } from "./LayoutManager";
|
import { LayoutMode } from "./LayoutManager";
|
||||||
|
import type { CoWebsite } from "./CoWebsite/CoWesbite";
|
||||||
|
import type CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
enum iframeStates {
|
export enum iframeStates {
|
||||||
closed = 1,
|
closed = 1,
|
||||||
loading, // loading an iframe can be slow, so we show some placeholder until it is ready
|
loading, // loading an iframe can be slow, so we show some placeholder until it is ready
|
||||||
opened,
|
opened,
|
||||||
@ -21,7 +20,7 @@ const gameOverlayDomId = "game-overlay";
|
|||||||
const cowebsiteBufferDomId = "cowebsite-buffer"; // the id of the container who contains cowebsite iframes.
|
const cowebsiteBufferDomId = "cowebsite-buffer"; // the id of the container who contains cowebsite iframes.
|
||||||
const cowebsiteAsideHolderDomId = "cowebsite-aside-holder";
|
const cowebsiteAsideHolderDomId = "cowebsite-aside-holder";
|
||||||
const cowebsiteLoaderDomId = "cowebsite-loader";
|
const cowebsiteLoaderDomId = "cowebsite-loader";
|
||||||
export const cowebsiteCloseButtonId = "cowebsite-close";
|
const cowebsiteCloseButtonId = "cowebsite-close";
|
||||||
const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
|
const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
|
||||||
const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
|
const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
|
||||||
const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close";
|
const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close";
|
||||||
@ -34,29 +33,12 @@ interface TouchMoveCoordinates {
|
|||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CoWebsiteState = "asleep" | "loading" | "ready";
|
|
||||||
|
|
||||||
export type CoWebsite = {
|
|
||||||
iframe: HTMLIFrameElement;
|
|
||||||
url: URL;
|
|
||||||
state: Writable<CoWebsiteState>;
|
|
||||||
closable: boolean;
|
|
||||||
allowPolicy: string | undefined;
|
|
||||||
allowApi: boolean | undefined;
|
|
||||||
jitsi?: boolean;
|
|
||||||
altMessage?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CoWebsiteManager {
|
class CoWebsiteManager {
|
||||||
private openedMain: iframeStates = iframeStates.closed;
|
private openedMain: Writable<iframeStates> = writable(iframeStates.closed);
|
||||||
|
|
||||||
private _onResize: Subject<void> = new Subject();
|
private _onResize: Subject<void> = new Subject();
|
||||||
public onResize = this._onResize.asObservable();
|
public onResize = this._onResize.asObservable();
|
||||||
/**
|
|
||||||
* Quickly going in and out of an iframe trigger can create conflicts between the iframe states.
|
|
||||||
* So we use this promise to queue up every cowebsite state transition
|
|
||||||
*/
|
|
||||||
private currentOperationPromise: Promise<void> = Promise.resolve();
|
|
||||||
private cowebsiteDom: HTMLDivElement;
|
private cowebsiteDom: HTMLDivElement;
|
||||||
private resizing: boolean = false;
|
private resizing: boolean = false;
|
||||||
private gameOverlayDom: HTMLDivElement;
|
private gameOverlayDom: HTMLDivElement;
|
||||||
@ -74,6 +56,14 @@ class CoWebsiteManager {
|
|||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public getMainState() {
|
||||||
|
return get(this.openedMain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMainStateSubscriber(): Readable<iframeStates> {
|
||||||
|
return this.openedMain;
|
||||||
|
}
|
||||||
|
|
||||||
get width(): number {
|
get width(): number {
|
||||||
return this.cowebsiteDom.clientWidth;
|
return this.cowebsiteDom.clientWidth;
|
||||||
}
|
}
|
||||||
@ -82,8 +72,13 @@ class CoWebsiteManager {
|
|||||||
this.cowebsiteDom.style.width = width + "px";
|
this.cowebsiteDom.style.width = width + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
set widthPercent(width: number) {
|
get maxWidth(): number {
|
||||||
this.cowebsiteDom.style.width = width + "%";
|
let maxWidth = 75 * window.innerWidth;
|
||||||
|
if (maxWidth !== 0) {
|
||||||
|
maxWidth = Math.round(maxWidth / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
get height(): number {
|
get height(): number {
|
||||||
@ -94,6 +89,15 @@ class CoWebsiteManager {
|
|||||||
this.cowebsiteDom.style.height = height + "px";
|
this.cowebsiteDom.style.height = height + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get maxHeight(): number {
|
||||||
|
let maxHeight = 60 * window.innerHeight;
|
||||||
|
if (maxHeight !== 0) {
|
||||||
|
maxHeight = Math.round(maxHeight / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
get verticalMode(): boolean {
|
get verticalMode(): boolean {
|
||||||
return window.innerWidth < window.innerHeight;
|
return window.innerWidth < window.innerHeight;
|
||||||
}
|
}
|
||||||
@ -128,13 +132,11 @@ class CoWebsiteManager {
|
|||||||
throw new Error("Undefined main co-website on closing");
|
throw new Error("Undefined main co-website on closing");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coWebsite.closable) {
|
if (coWebsite.isClosable()) {
|
||||||
this.closeCoWebsite(coWebsite).catch(() => {
|
this.closeCoWebsite(coWebsite);
|
||||||
console.error("Error during closing a co-website by a button");
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.unloadCoWebsite(coWebsite).catch(() => {
|
this.unloadCoWebsite(coWebsite).catch((err) => {
|
||||||
console.error("Error during unloading a co-website by a button");
|
console.error("Cannot unload co-website on click on close button", err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -191,29 +193,21 @@ class CoWebsiteManager {
|
|||||||
|
|
||||||
if (this.verticalMode) {
|
if (this.verticalMode) {
|
||||||
const tempValue = this.height + y;
|
const tempValue = this.height + y;
|
||||||
let maxHeight = 60 * window.innerHeight;
|
|
||||||
if (maxHeight !== 0) {
|
|
||||||
maxHeight = Math.round(maxHeight / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tempValue < this.cowebsiteAsideHolderDom.offsetHeight) {
|
if (tempValue < this.cowebsiteAsideHolderDom.offsetHeight) {
|
||||||
this.height = this.cowebsiteAsideHolderDom.offsetHeight;
|
this.height = this.cowebsiteAsideHolderDom.offsetHeight;
|
||||||
} else if (tempValue > maxHeight) {
|
} else if (tempValue > this.maxHeight) {
|
||||||
this.height = maxHeight;
|
this.height = this.maxHeight;
|
||||||
} else {
|
} else {
|
||||||
this.height = tempValue;
|
this.height = tempValue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const tempValue = this.width - x;
|
const tempValue = this.width - x;
|
||||||
let maxWidth = 75 * window.innerWidth;
|
|
||||||
if (maxWidth !== 0) {
|
|
||||||
maxWidth = Math.round(maxWidth / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tempValue < this.cowebsiteAsideHolderDom.offsetWidth) {
|
if (tempValue < this.cowebsiteAsideHolderDom.offsetWidth) {
|
||||||
this.width = this.cowebsiteAsideHolderDom.offsetWidth;
|
this.width = this.cowebsiteAsideHolderDom.offsetWidth;
|
||||||
} else if (tempValue > maxWidth) {
|
} else if (tempValue > this.maxWidth) {
|
||||||
this.width = maxWidth;
|
this.width = this.maxWidth;
|
||||||
} else {
|
} else {
|
||||||
this.width = tempValue;
|
this.width = tempValue;
|
||||||
}
|
}
|
||||||
@ -230,7 +224,10 @@ class CoWebsiteManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
coWebsite.iframe.style.display = "none";
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "none";
|
||||||
|
}
|
||||||
this.resizing = true;
|
this.resizing = true;
|
||||||
document.addEventListener("mousemove", movecallback);
|
document.addEventListener("mousemove", movecallback);
|
||||||
});
|
});
|
||||||
@ -246,7 +243,10 @@ class CoWebsiteManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
coWebsite.iframe.style.display = "flex";
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "flex";
|
||||||
|
}
|
||||||
this.resizing = false;
|
this.resizing = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -259,7 +259,10 @@ class CoWebsiteManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
coWebsite.iframe.style.display = "none";
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "none";
|
||||||
|
}
|
||||||
this.resizing = true;
|
this.resizing = true;
|
||||||
const touchEvent = event.touches[0];
|
const touchEvent = event.touches[0];
|
||||||
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
|
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
|
||||||
@ -278,7 +281,10 @@ class CoWebsiteManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
coWebsite.iframe.style.display = "flex";
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "flex";
|
||||||
|
}
|
||||||
this.resizing = false;
|
this.resizing = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -299,16 +305,43 @@ class CoWebsiteManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public displayMain() {
|
||||||
|
const coWebsite = this.getMainCoWebsite();
|
||||||
|
if (coWebsite) {
|
||||||
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loadMain(coWebsite?.getWidthPercent());
|
||||||
|
this.openMain();
|
||||||
|
this.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hideMain() {
|
||||||
|
const coWebsite = this.getMainCoWebsite();
|
||||||
|
if (coWebsite) {
|
||||||
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.cowebsiteDom.classList.add("closing");
|
||||||
|
this.cowebsiteDom.classList.remove("opened");
|
||||||
|
this.openedMain.set(iframeStates.closed);
|
||||||
|
this.fire();
|
||||||
|
}
|
||||||
|
|
||||||
private closeMain(): void {
|
private closeMain(): void {
|
||||||
this.toggleFullScreenIcon(true);
|
this.toggleFullScreenIcon(true);
|
||||||
this.cowebsiteDom.classList.add("closing");
|
this.cowebsiteDom.classList.add("closing");
|
||||||
this.cowebsiteDom.classList.remove("opened");
|
this.cowebsiteDom.classList.remove("opened");
|
||||||
this.openedMain = iframeStates.closed;
|
this.openedMain.set(iframeStates.closed);
|
||||||
this.resetStyleMain();
|
this.resetStyleMain();
|
||||||
this.fire();
|
this.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadMain(): void {
|
private loadMain(openingWidth?: number): void {
|
||||||
this.loaderAnimationInterval.interval = setInterval(() => {
|
this.loaderAnimationInterval.interval = setInterval(() => {
|
||||||
if (!this.loaderAnimationInterval.trails) {
|
if (!this.loaderAnimationInterval.trails) {
|
||||||
this.loaderAnimationInterval.trails = [0, 1, 2];
|
this.loaderAnimationInterval.trails = [0, 1, 2];
|
||||||
@ -337,16 +370,34 @@ class CoWebsiteManager {
|
|||||||
trail === 3 ? 0 : trail + 1
|
trail === 3 ? 0 : trail + 1
|
||||||
);
|
);
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
|
if (!this.verticalMode && openingWidth) {
|
||||||
|
let newWidth = 50;
|
||||||
|
|
||||||
|
if (openingWidth > 100) {
|
||||||
|
newWidth = 100;
|
||||||
|
} else if (openingWidth > 1) {
|
||||||
|
newWidth = openingWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
newWidth = Math.round((newWidth * this.maxWidth) / 100);
|
||||||
|
|
||||||
|
if (newWidth < this.cowebsiteAsideHolderDom.offsetWidth) {
|
||||||
|
newWidth = this.cowebsiteAsideHolderDom.offsetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.width = newWidth;
|
||||||
|
}
|
||||||
|
|
||||||
this.cowebsiteDom.classList.add("opened");
|
this.cowebsiteDom.classList.add("opened");
|
||||||
this.openedMain = iframeStates.loading;
|
this.openedMain.set(iframeStates.loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
private openMain(): void {
|
private openMain(): void {
|
||||||
this.cowebsiteDom.addEventListener("transitionend", () => {
|
this.cowebsiteDom.addEventListener("transitionend", () => {
|
||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
});
|
});
|
||||||
this.openedMain = iframeStates.opened;
|
this.openedMain.set(iframeStates.opened);
|
||||||
this.resetStyleMain();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetStyleMain() {
|
public resetStyleMain() {
|
||||||
@ -359,7 +410,9 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined {
|
public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined {
|
||||||
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId);
|
return get(coWebsites).find((coWebsite: CoWebsite) => {
|
||||||
|
return coWebsite.getId() === coWebsiteId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCoWebsiteByPosition(position: number): CoWebsite | undefined {
|
private getCoWebsiteByPosition(position: number): CoWebsite | undefined {
|
||||||
@ -379,7 +432,9 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getPositionByCoWebsite(coWebsite: CoWebsite): number {
|
private getPositionByCoWebsite(coWebsite: CoWebsite): number {
|
||||||
return get(coWebsites).findIndex((currentCoWebsite) => currentCoWebsite.iframe.id === coWebsite.iframe.id);
|
return get(coWebsites).findIndex((currentCoWebsite) => {
|
||||||
|
return currentCoWebsite.getId() === coWebsite.getId();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSlotByCowebsite(coWebsite: CoWebsite): HTMLDivElement | undefined {
|
private getSlotByCowebsite(coWebsite: CoWebsite): HTMLDivElement | undefined {
|
||||||
@ -393,7 +448,7 @@ class CoWebsiteManager {
|
|||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
id += "main";
|
id += "main";
|
||||||
} else {
|
} else {
|
||||||
id += coWebsite.iframe.id;
|
id += coWebsite.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
const slot = HtmlUtils.getElementById<HTMLDivElement>(id);
|
const slot = HtmlUtils.getElementById<HTMLDivElement>(id);
|
||||||
@ -410,60 +465,72 @@ class CoWebsiteManager {
|
|||||||
|
|
||||||
const bounding = coWebsiteSlot.getBoundingClientRect();
|
const bounding = coWebsiteSlot.getBoundingClientRect();
|
||||||
|
|
||||||
coWebsite.iframe.style.top = bounding.top + "px";
|
const iframe = coWebsite.getIframe();
|
||||||
coWebsite.iframe.style.left = bounding.left + "px";
|
|
||||||
coWebsite.iframe.style.width = bounding.right - bounding.left + "px";
|
if (iframe) {
|
||||||
coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px";
|
iframe.style.top = bounding.top + "px";
|
||||||
|
iframe.style.left = bounding.left + "px";
|
||||||
|
iframe.style.width = bounding.right - bounding.left + "px";
|
||||||
|
iframe.style.height = bounding.bottom - bounding.top + "px";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public resizeAllIframes() {
|
public resizeAllIframes() {
|
||||||
const mainCoWebsite = this.getCoWebsiteByPosition(0);
|
const mainCoWebsite = this.getCoWebsiteByPosition(0);
|
||||||
|
const mainIframe = mainCoWebsite?.getIframe();
|
||||||
const highlightEmbed = get(highlightedEmbedScreen);
|
const highlightEmbed = get(highlightedEmbedScreen);
|
||||||
|
|
||||||
get(coWebsites).forEach((coWebsite) => {
|
get(coWebsites).forEach((coWebsite: CoWebsite) => {
|
||||||
const notMain = !mainCoWebsite || (mainCoWebsite && mainCoWebsite.iframe.id !== coWebsite.iframe.id);
|
const iframe = coWebsite.getIframe();
|
||||||
|
if (!iframe) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const notMain = !mainCoWebsite || (mainCoWebsite && mainIframe && mainIframe.id !== iframe.id);
|
||||||
const notHighlighEmbed =
|
const notHighlighEmbed =
|
||||||
!highlightEmbed ||
|
!highlightEmbed ||
|
||||||
(highlightEmbed &&
|
(highlightEmbed &&
|
||||||
(highlightEmbed.type !== "cowebsite" ||
|
(highlightEmbed.type !== "cowebsite" ||
|
||||||
(highlightEmbed.type === "cowebsite" &&
|
(highlightEmbed.type === "cowebsite" && highlightEmbed.embed.getId() !== coWebsite.getId())));
|
||||||
highlightEmbed.embed.iframe.id !== coWebsite.iframe.id)));
|
|
||||||
|
|
||||||
if (coWebsite.iframe.classList.contains("main") && notMain) {
|
if (iframe.classList.contains("main") && notMain) {
|
||||||
coWebsite.iframe.classList.remove("main");
|
iframe.classList.remove("main");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coWebsite.iframe.classList.contains("highlighted") && notHighlighEmbed) {
|
if (iframe.classList.contains("highlighted") && notHighlighEmbed) {
|
||||||
coWebsite.iframe.classList.remove("highlighted");
|
iframe.classList.remove("highlighted");
|
||||||
coWebsite.iframe.classList.add("pixel");
|
iframe.classList.add("pixel");
|
||||||
coWebsite.iframe.style.top = "-1px";
|
iframe.style.top = "-1px";
|
||||||
coWebsite.iframe.style.left = "-1px";
|
iframe.style.left = "-1px";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notMain && notHighlighEmbed) {
|
if (notMain && notHighlighEmbed) {
|
||||||
coWebsite.iframe.classList.add("pixel");
|
iframe.classList.add("pixel");
|
||||||
coWebsite.iframe.style.top = "-1px";
|
iframe.style.top = "-1px";
|
||||||
coWebsite.iframe.style.left = "-1px";
|
iframe.style.left = "-1px";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setIframeOffset(coWebsite);
|
this.setIframeOffset(coWebsite);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mainCoWebsite) {
|
if (mainIframe) {
|
||||||
mainCoWebsite.iframe.classList.add("main");
|
mainIframe.classList.add("main");
|
||||||
mainCoWebsite.iframe.classList.remove("pixel");
|
mainIframe.classList.remove("pixel");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highlightEmbed && highlightEmbed.type === "cowebsite") {
|
if (highlightEmbed && highlightEmbed.type === "cowebsite") {
|
||||||
highlightEmbed.embed.iframe.classList.add("highlighted");
|
const highlightEmbedIframe = highlightEmbed.embed.getIframe();
|
||||||
highlightEmbed.embed.iframe.classList.remove("pixel");
|
if (highlightEmbedIframe) {
|
||||||
|
highlightEmbedIframe.classList.add("highlighted");
|
||||||
|
highlightEmbedIframe.classList.remove("pixel");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeHighlightCoWebsite(coWebsite: CoWebsite) {
|
private removeHighlightCoWebsite(coWebsite: CoWebsite) {
|
||||||
const highlighted = get(highlightedEmbedScreen);
|
const highlighted = get(highlightedEmbedScreen);
|
||||||
|
|
||||||
if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.iframe.id === coWebsite.iframe.id) {
|
if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.getId() === coWebsite.getId()) {
|
||||||
highlightedEmbedScreen.removeHighlight();
|
highlightedEmbedScreen.removeHighlight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -476,7 +543,9 @@ class CoWebsiteManager {
|
|||||||
this.closeMain();
|
this.closeMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
coWebsite.iframe.remove();
|
coWebsite.unload().catch((err) => {
|
||||||
|
console.error("Cannot unload cowebsite on remove from stack");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public goToMain(coWebsite: CoWebsite) {
|
public goToMain(coWebsite: CoWebsite) {
|
||||||
@ -488,38 +557,21 @@ class CoWebsiteManager {
|
|||||||
isMediaBreakpointDown("lg") &&
|
isMediaBreakpointDown("lg") &&
|
||||||
get(embedScreenLayout) === LayoutMode.Presentation &&
|
get(embedScreenLayout) === LayoutMode.Presentation &&
|
||||||
mainCoWebsite &&
|
mainCoWebsite &&
|
||||||
mainCoWebsite.iframe.id !== coWebsite.iframe.id &&
|
mainCoWebsite.getId() !== coWebsite.getId() &&
|
||||||
get(mainCoWebsite.state) !== "asleep"
|
mainCoWebsite.getState() !== "asleep"
|
||||||
) {
|
) {
|
||||||
highlightedEmbedScreen.toggleHighlight({
|
highlightedEmbedScreen.removeHighlight();
|
||||||
type: "cowebsite",
|
|
||||||
embed: mainCoWebsite,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public searchJitsi(): CoWebsite | undefined {
|
public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
|
||||||
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.jitsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initialiseCowebsite(coWebsite: CoWebsite, position: number | undefined) {
|
|
||||||
if (coWebsite.allowPolicy) {
|
|
||||||
coWebsite.iframe.allow = coWebsite.allowPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coWebsite.allowApi) {
|
|
||||||
iframeListener.registerIframe(coWebsite.iframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
coWebsite.iframe.classList.add("pixel");
|
|
||||||
|
|
||||||
const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
|
const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
|
||||||
coWebsites.add(coWebsite, coWebsitePosition);
|
coWebsites.add(coWebsite, coWebsitePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateUniqueId() {
|
public generateUniqueId() {
|
||||||
let id = undefined;
|
let id = undefined;
|
||||||
do {
|
do {
|
||||||
id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
|
id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
|
||||||
@ -528,137 +580,46 @@ class CoWebsiteManager {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addCoWebsite(
|
public loadCoWebsite(coWebsite: CoWebsite): CancelablePromise<void> {
|
||||||
url: string,
|
|
||||||
base: string,
|
|
||||||
allowApi?: boolean,
|
|
||||||
allowPolicy?: string,
|
|
||||||
position?: number,
|
|
||||||
closable?: boolean,
|
|
||||||
altMessage?: string
|
|
||||||
): CoWebsite {
|
|
||||||
const iframe = document.createElement("iframe");
|
|
||||||
const fullUrl = new URL(url, base);
|
|
||||||
iframe.src = fullUrl.toString();
|
|
||||||
iframe.id = this.generateUniqueId();
|
|
||||||
|
|
||||||
const newCoWebsite: CoWebsite = {
|
|
||||||
iframe,
|
|
||||||
url: fullUrl,
|
|
||||||
state: writable("asleep" as CoWebsiteState),
|
|
||||||
closable: closable ?? false,
|
|
||||||
allowPolicy,
|
|
||||||
allowApi,
|
|
||||||
altMessage,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.initialiseCowebsite(newCoWebsite, position);
|
|
||||||
|
|
||||||
return newCoWebsite;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addCoWebsiteFromIframe(
|
|
||||||
iframe: HTMLIFrameElement,
|
|
||||||
allowApi?: boolean,
|
|
||||||
allowPolicy?: string,
|
|
||||||
position?: number,
|
|
||||||
closable?: boolean,
|
|
||||||
jitsi?: boolean
|
|
||||||
): CoWebsite {
|
|
||||||
if (get(coWebsitesNotAsleep).length < 1) {
|
|
||||||
this.loadMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
iframe.id = this.generateUniqueId();
|
|
||||||
|
|
||||||
const newCoWebsite: CoWebsite = {
|
|
||||||
iframe,
|
|
||||||
url: new URL(iframe.src),
|
|
||||||
state: writable("ready" as CoWebsiteState),
|
|
||||||
closable: closable ?? false,
|
|
||||||
allowPolicy,
|
|
||||||
allowApi,
|
|
||||||
jitsi,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (position === 0) {
|
|
||||||
this.openMain();
|
|
||||||
setTimeout(() => {
|
|
||||||
this.fire();
|
|
||||||
}, animationTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initialiseCowebsite(newCoWebsite, position);
|
|
||||||
|
|
||||||
return newCoWebsite;
|
|
||||||
}
|
|
||||||
|
|
||||||
public loadCoWebsite(coWebsite: CoWebsite): Promise<CoWebsite> {
|
|
||||||
if (get(coWebsitesNotAsleep).length < 1) {
|
if (get(coWebsitesNotAsleep).length < 1) {
|
||||||
coWebsites.remove(coWebsite);
|
coWebsites.remove(coWebsite);
|
||||||
coWebsites.add(coWebsite, 0);
|
coWebsites.add(coWebsite, 0);
|
||||||
this.loadMain();
|
this.loadMain(coWebsite.getWidthPercent());
|
||||||
}
|
}
|
||||||
|
|
||||||
coWebsite.state.set("loading");
|
// Check if the main is hide
|
||||||
|
if (this.getMainCoWebsite() && this.getMainState() === iframeStates.closed) {
|
||||||
const mainCoWebsite = this.getMainCoWebsite();
|
this.displayMain();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const onloadPromise = new Promise<void>((resolve) => {
|
|
||||||
coWebsite.iframe.onload = () => {
|
|
||||||
coWebsite.state.set("ready");
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const onTimeoutPromise = new Promise<void>((resolve) => {
|
|
||||||
setTimeout(() => resolve(), 2000);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.cowebsiteBufferDom.appendChild(coWebsite.iframe);
|
|
||||||
|
|
||||||
if (coWebsite.jitsi) {
|
|
||||||
const gameScene = gameManager.getCurrentGameScene();
|
|
||||||
gameScene.disableMediaBehaviors();
|
|
||||||
jitsiFactory.restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentOperationPromise = this.currentOperationPromise
|
const coWebsiteLloading = coWebsite
|
||||||
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
.load()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (mainCoWebsite && mainCoWebsite.iframe.id === coWebsite.iframe.id) {
|
const mainCoWebsite = this.getMainCoWebsite();
|
||||||
|
if (mainCoWebsite && mainCoWebsite.getId() === coWebsite.getId()) {
|
||||||
this.openMain();
|
this.openMain();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
}, animationTime);
|
}, animationTime);
|
||||||
}
|
}
|
||||||
|
this.resizeAllIframes();
|
||||||
return resolve(coWebsite);
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Error on co-website loading => ", err);
|
console.error("Error on co-website loading => ", err);
|
||||||
this.removeCoWebsiteFromStack(coWebsite);
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
return reject();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return coWebsiteLloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unloadCoWebsite(coWebsite: CoWebsite): Promise<void> {
|
public unloadCoWebsite(coWebsite: CoWebsite): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.removeHighlightCoWebsite(coWebsite);
|
this.removeHighlightCoWebsite(coWebsite);
|
||||||
|
|
||||||
coWebsite.iframe.parentNode?.removeChild(coWebsite.iframe);
|
return coWebsite
|
||||||
coWebsite.state.set("asleep");
|
.unload()
|
||||||
|
.then(() => {
|
||||||
coWebsites.remove(coWebsite);
|
coWebsites.remove(coWebsite);
|
||||||
|
|
||||||
if (coWebsite.jitsi) {
|
|
||||||
jitsiFactory.stop();
|
|
||||||
const gameScene = gameManager.getCurrentGameScene();
|
|
||||||
gameScene.enableMediaBehaviors();
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainCoWebsite = this.getMainCoWebsite();
|
const mainCoWebsite = this.getMainCoWebsite();
|
||||||
|
|
||||||
if (mainCoWebsite) {
|
if (mainCoWebsite) {
|
||||||
@ -670,29 +631,17 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
coWebsites.add(coWebsite, get(coWebsites).length);
|
coWebsites.add(coWebsite, get(coWebsites).length);
|
||||||
|
})
|
||||||
resolve();
|
.catch(() => {
|
||||||
|
console.error();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeCoWebsite(coWebsite: CoWebsite): Promise<void> {
|
public closeCoWebsite(coWebsite: CoWebsite): void {
|
||||||
this.currentOperationPromise = this.currentOperationPromise.then(
|
|
||||||
() =>
|
|
||||||
new Promise((resolve) => {
|
|
||||||
if (coWebsite.jitsi) {
|
|
||||||
jitsiFactory.destroy();
|
|
||||||
const gameScene = gameManager.getCurrentGameScene();
|
|
||||||
gameScene.enableMediaBehaviors();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get(coWebsites).length === 1) {
|
if (get(coWebsites).length === 1) {
|
||||||
this.fire();
|
this.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coWebsite.allowApi) {
|
|
||||||
iframeListener.unregisterIframe(coWebsite.iframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeCoWebsiteFromStack(coWebsite);
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
|
|
||||||
const mainCoWebsite = this.getMainCoWebsite();
|
const mainCoWebsite = this.getMainCoWebsite();
|
||||||
@ -704,25 +653,16 @@ class CoWebsiteManager {
|
|||||||
} else {
|
} else {
|
||||||
this.closeMain();
|
this.closeMain();
|
||||||
}
|
}
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return this.currentOperationPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeCoWebsites(): Promise<void> {
|
public closeCoWebsites(): void {
|
||||||
return (this.currentOperationPromise = this.currentOperationPromise.then(() => {
|
|
||||||
get(coWebsites).forEach((coWebsite: CoWebsite) => {
|
get(coWebsites).forEach((coWebsite: CoWebsite) => {
|
||||||
this.closeCoWebsite(coWebsite).catch(() => {
|
this.closeCoWebsite(coWebsite);
|
||||||
console.error("Error during closing a co-website");
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}));
|
|
||||||
return this.currentOperationPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getGameSize(): { width: number; height: number } {
|
public getGameSize(): { width: number; height: number } {
|
||||||
if (this.openedMain === iframeStates.closed) {
|
if (this.getMainState() === iframeStates.closed) {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
||||||
import { CoWebsite, coWebsiteManager } from "./CoWebsiteManager";
|
import { coWebsiteManager } from "./CoWebsiteManager";
|
||||||
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
interface jitsiConfigInterface {
|
interface jitsiConfigInterface {
|
||||||
startWithAudioMuted: boolean;
|
startWithAudioMuted: boolean;
|
||||||
@ -134,20 +135,15 @@ class JitsiFactory {
|
|||||||
return slugify(instance.replace("/", "-") + "-" + roomName);
|
return slugify(instance.replace("/", "-") + "-" + roomName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start(
|
public start(
|
||||||
roomName: string,
|
roomName: string,
|
||||||
playerName: string,
|
playerName: string,
|
||||||
jwt?: string,
|
jwt?: string,
|
||||||
config?: object,
|
config?: object,
|
||||||
interfaceConfig?: object,
|
interfaceConfig?: object,
|
||||||
jitsiUrl?: string
|
jitsiUrl?: string
|
||||||
) {
|
): CancelablePromise<HTMLIFrameElement> {
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
return new CancelablePromise((resolve, reject, cancel) => {
|
||||||
|
|
||||||
if (coWebsite) {
|
|
||||||
await coWebsiteManager.closeCoWebsite(coWebsite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
@ -160,8 +156,8 @@ class JitsiFactory {
|
|||||||
if (domain === undefined) {
|
if (domain === undefined) {
|
||||||
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
||||||
}
|
}
|
||||||
await this.loadJitsiScript(domain);
|
|
||||||
|
|
||||||
|
const loadScript = this.loadJitsiScript(domain).then(() => {
|
||||||
const options: JitsiOptions = {
|
const options: JitsiOptions = {
|
||||||
roomName: roomName,
|
roomName: roomName,
|
||||||
jwt: jwt,
|
jwt: jwt,
|
||||||
@ -176,72 +172,59 @@ class JitsiFactory {
|
|||||||
delete options.jwt;
|
delete options.jwt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const doResolve = (): void => {
|
const timemout = setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
||||||
const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
|
||||||
if (iframe && this.jitsiApi) {
|
|
||||||
const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true);
|
|
||||||
|
|
||||||
|
const doResolve = (): void => {
|
||||||
|
clearTimeout(timemout);
|
||||||
|
const iframe = coWebsiteManager
|
||||||
|
.getCoWebsiteBuffer()
|
||||||
|
.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
||||||
|
|
||||||
|
if (iframe && this.jitsiApi) {
|
||||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
||||||
this.closeOrUnload(coWebsite);
|
this.closeOrUnload(iframe);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.jitsiApi.addListener("readyToClose", () => {
|
this.jitsiApi.addListener("readyToClose", () => {
|
||||||
this.closeOrUnload(coWebsite);
|
this.closeOrUnload(iframe);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
coWebsiteManager.resizeAllIframes();
|
return resolve(iframe);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.jitsiApi = undefined;
|
this.jitsiApi = undefined;
|
||||||
|
|
||||||
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
cancel(() => {
|
||||||
|
loadScript.cancel();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private closeOrUnload = function (coWebsite: CoWebsite) {
|
private closeOrUnload = function (iframe: HTMLIFrameElement) {
|
||||||
if (coWebsite.closable) {
|
const coWebsite = coWebsiteManager.getCoWebsites().find((coWebsite) => coWebsite.getIframe() === iframe);
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
|
||||||
console.error("Error during closing a Jitsi Meet");
|
if (!coWebsite) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coWebsite.isClosable()) {
|
||||||
|
coWebsiteManager.closeCoWebsite(coWebsite);
|
||||||
} else {
|
} else {
|
||||||
coWebsiteManager.unloadCoWebsite(coWebsite).catch(() => {
|
coWebsiteManager.unloadCoWebsite(coWebsite).catch((err) => {
|
||||||
console.error("Error during unloading a Jitsi Meet");
|
console.error("Cannot unload co-website from the Jitsi factory", err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public restart() {
|
|
||||||
if (!this.jitsiApi) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
|
||||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
|
||||||
|
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
|
||||||
console.log("jitsi api ", this.jitsiApi);
|
|
||||||
console.log("iframe cowebsite", coWebsite?.iframe);
|
|
||||||
|
|
||||||
if (!coWebsite) {
|
|
||||||
this.destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
|
||||||
this.closeOrUnload(coWebsite);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("readyToClose", () => {
|
|
||||||
this.closeOrUnload(coWebsite);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public stop() {
|
public stop() {
|
||||||
if (!this.jitsiApi) {
|
if (!this.jitsiApi) {
|
||||||
return;
|
return;
|
||||||
@ -276,8 +259,8 @@ class JitsiFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadJitsiScript(domain: string): Promise<void> {
|
private loadJitsiScript(domain: string): CancelablePromise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new CancelablePromise<void>((resolve, reject, cancel) => {
|
||||||
if (this.jitsiScriptLoaded) {
|
if (this.jitsiScriptLoaded) {
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
@ -296,6 +279,10 @@ class JitsiFactory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.head.appendChild(jitsiScript);
|
document.head.appendChild(jitsiScript);
|
||||||
|
|
||||||
|
cancel(() => {
|
||||||
|
jitsiScript.remove();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,6 @@ export enum DivImportance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ON_ACTION_TRIGGER_BUTTON = "onaction";
|
export const ON_ACTION_TRIGGER_BUTTON = "onaction";
|
||||||
|
export const ON_ICON_TRIGGER_BUTTON = "onicon";
|
||||||
|
|
||||||
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };
|
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };
|
||||||
|
@ -14,7 +14,7 @@ import warning from "./warning";
|
|||||||
import woka from "./woka";
|
import woka from "./woka";
|
||||||
|
|
||||||
const de_DE: Translation = {
|
const de_DE: Translation = {
|
||||||
...en_US,
|
...(en_US as Translation),
|
||||||
language: "Deutsch",
|
language: "Deutsch",
|
||||||
country: "Deutschland",
|
country: "Deutschland",
|
||||||
audio,
|
audio,
|
||||||
|
@ -70,6 +70,7 @@ const menu: NonNullable<Translation["menu"]> = {
|
|||||||
description: "Link zu diesem Raum teilen!",
|
description: "Link zu diesem Raum teilen!",
|
||||||
copy: "Kopieren",
|
copy: "Kopieren",
|
||||||
share: "Teilen",
|
share: "Teilen",
|
||||||
|
walk_automatically_to_position: "Walk automatically to my position",
|
||||||
},
|
},
|
||||||
globalMessage: {
|
globalMessage: {
|
||||||
text: "Text",
|
text: "Text",
|
||||||
|
@ -11,6 +11,7 @@ import menu from "./menu";
|
|||||||
import report from "./report";
|
import report from "./report";
|
||||||
import warning from "./warning";
|
import warning from "./warning";
|
||||||
import emoji from "./emoji";
|
import emoji from "./emoji";
|
||||||
|
import trigger from "./trigger";
|
||||||
|
|
||||||
const en_US: BaseTranslation = {
|
const en_US: BaseTranslation = {
|
||||||
language: "English",
|
language: "English",
|
||||||
@ -27,6 +28,7 @@ const en_US: BaseTranslation = {
|
|||||||
report,
|
report,
|
||||||
warning,
|
warning,
|
||||||
emoji,
|
emoji,
|
||||||
|
trigger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en_US;
|
export default en_US;
|
||||||
|
@ -70,6 +70,7 @@ const menu: BaseTranslation = {
|
|||||||
description: "Share the link of the room!",
|
description: "Share the link of the room!",
|
||||||
copy: "Copy",
|
copy: "Copy",
|
||||||
share: "Share",
|
share: "Share",
|
||||||
|
walk_automatically_to_position: "Walk automatically to my position",
|
||||||
},
|
},
|
||||||
globalMessage: {
|
globalMessage: {
|
||||||
text: "Text",
|
text: "Text",
|
||||||
|
9
front/src/i18n/en-US/trigger.ts
Normal file
9
front/src/i18n/en-US/trigger.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { BaseTranslation } from "../i18n-types";
|
||||||
|
|
||||||
|
const trigger: BaseTranslation = {
|
||||||
|
cowebsite: "Press SPACE or touch here to open web site",
|
||||||
|
jitsiRoom: "Press SPACE or touch here to enter Jitsi Meet room",
|
||||||
|
newTab: "Press SPACE or touch here to open web site in new tab",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default trigger;
|
@ -12,9 +12,10 @@ import menu from "./menu";
|
|||||||
import report from "./report";
|
import report from "./report";
|
||||||
import warning from "./warning";
|
import warning from "./warning";
|
||||||
import woka from "./woka";
|
import woka from "./woka";
|
||||||
|
import trigger from "./trigger";
|
||||||
|
|
||||||
const fr_FR: Translation = {
|
const fr_FR: Translation = {
|
||||||
...en_US,
|
...(en_US as Translation),
|
||||||
language: "Français",
|
language: "Français",
|
||||||
country: "France",
|
country: "France",
|
||||||
audio,
|
audio,
|
||||||
@ -29,6 +30,7 @@ const fr_FR: Translation = {
|
|||||||
report,
|
report,
|
||||||
warning,
|
warning,
|
||||||
emoji,
|
emoji,
|
||||||
|
trigger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr_FR;
|
export default fr_FR;
|
||||||
|
@ -63,13 +63,14 @@ const menu: NonNullable<Translation["menu"]> = {
|
|||||||
},
|
},
|
||||||
fullscreen: "Plein écran",
|
fullscreen: "Plein écran",
|
||||||
notifications: "Notifications",
|
notifications: "Notifications",
|
||||||
cowebsiteTrigger: "Demander toujours avant d'ouvrir des sites web et des salles de réunion Jitsi",
|
cowebsiteTrigger: "Demander toujours avant d'ouvrir des sites web et des salles de conférence Jitsi",
|
||||||
ignoreFollowRequest: "Ignorer les demandes de suivi des autres utilisateurs",
|
ignoreFollowRequest: "Ignorer les demandes de suivi des autres utilisateurs",
|
||||||
},
|
},
|
||||||
invite: {
|
invite: {
|
||||||
description: "Partager le lien de la salle!",
|
description: "Partager le lien de la salle!",
|
||||||
copy: "Copier",
|
copy: "Copier",
|
||||||
share: "Partager",
|
share: "Partager",
|
||||||
|
walk_automatically_to_position: "Marcher automatiquement jusqu'à ma position",
|
||||||
},
|
},
|
||||||
globalMessage: {
|
globalMessage: {
|
||||||
text: "Texte",
|
text: "Texte",
|
||||||
|
9
front/src/i18n/fr-FR/trigger.ts
Normal file
9
front/src/i18n/fr-FR/trigger.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { Translation } from "../i18n-types";
|
||||||
|
|
||||||
|
const trigger: NonNullable<Translation["trigger"]> = {
|
||||||
|
cowebsite: "Appuyez sur ESPACE ou ici pour ouvrir le site Web",
|
||||||
|
jitsiRoom: "Appuyez sur ESPACE ou ici pour entrer dans la salle conférence Jitsi",
|
||||||
|
newTab: "Appuyez sur ESPACE ou ici pour ouvrir le site Web dans un nouvel onglet",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default trigger;
|
@ -47,6 +47,11 @@
|
|||||||
"name":"openWebsiteTrigger",
|
"name":"openWebsiteTrigger",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"value":"onaction"
|
"value":"onaction"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"openWebsiteWidth",
|
||||||
|
"type":"int",
|
||||||
|
"value":100
|
||||||
}],
|
}],
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
|
197
maps/tests/DoorTest/map.json
Normal file
197
maps/tests/DoorTest/map.json
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":30,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":30,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"script.php"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"openWebsiteAllowApi",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":30,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 6, 6, 6, 6, 6, 0, 0, 6, 6, 6, 6, 6, 6, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28, 28, 0, 0, 28, 28, 28, 28, 28, 28, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":30,
|
||||||
|
"id":6,
|
||||||
|
"name":"furnitures",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":30,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":30,
|
||||||
|
"id":8,
|
||||||
|
"name":"closedPath",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":30,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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":30,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":30,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":101.5,
|
||||||
|
"id":11,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"text":"You should be able to get here only if the path isn't blocked",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":383,
|
||||||
|
"x":81.226595249185,
|
||||||
|
"y":297.048206800186
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":101.5,
|
||||||
|
"id":12,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"text":"Try to move to the next room by using right-click \/ tap movement. Click \"Toggle Door\" button to block \/ make access.",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":383,
|
||||||
|
"x":81,
|
||||||
|
"y":99.75
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":9,
|
||||||
|
"nextobjectid":13,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"script.php"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"openWebsiteAllowApi",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"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":16,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":17,
|
||||||
|
"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":72,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":73,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":30
|
||||||
|
}
|
26
maps/tests/DoorTest/script.php
Normal file
26
maps/tests/DoorTest/script.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script src="<?php echo $_SERVER["FRONT_URL"] ?>/iframe_api.js"></script>
|
||||||
|
<script>
|
||||||
|
let closed = true;
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
//@ts-ignore
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('After WA init');
|
||||||
|
const toogleDoorButton = document.getElementById('toogleDoorButton');
|
||||||
|
|
||||||
|
toogleDoorButton.addEventListener('click', async () => {
|
||||||
|
closed ? WA.room.hideLayer('closedPath') : WA.room.showLayer('closedPath');
|
||||||
|
closed = !closed;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="toogleDoorButton">Toggle Door</button>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -32,6 +32,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="jitsi_custom_url.json" target="_blank">Testing jitsiUrl property</a>
|
<a href="#" class="testLink" data-testmap="jitsi_custom_url.json" target="_blank">Testing jitsiUrl property</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-parallax-effect"> Success <input type="radio" name="test-parallax-effect"> Failure <input type="radio" name="test-parallax-effect" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="parallax.json" target="_blank">Test parallax effect</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio" name="test-animated-tiles"> Success <input type="radio" name="test-animated-tiles"> Failure <input type="radio" name="test-animated-tiles" checked> Pending
|
<input type="radio" name="test-animated-tiles"> Success <input type="radio" name="test-animated-tiles"> Failure <input type="radio" name="test-animated-tiles" checked> Pending
|
||||||
@ -40,6 +48,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="animated_tiles.json" target="_blank">Test animated tiles</a>
|
<a href="#" class="testLink" data-testmap="animated_tiles.json" target="_blank">Test animated tiles</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-door-map"> Success <input type="radio" name="test-door-map"> Failure <input type="radio" name="test-door-map" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="DoorTest/map.json" target="_blank">Test Doors</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio" name="test-start-tile-S1"> Success <input type="radio" name="test-start-tile-S1"> Failure <input type="radio" name="test-start-tile-S1" checked> Pending
|
<input type="radio" name="test-start-tile-S1"> Success <input type="radio" name="test-start-tile-S1"> Failure <input type="radio" name="test-start-tile-S1" checked> Pending
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"infinite":false,
|
"infinite":false,
|
||||||
"layers":[
|
"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],
|
"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, 12, 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,
|
"height":10,
|
||||||
"id":1,
|
"id":1,
|
||||||
"name":"floor",
|
"name":"floor",
|
||||||
@ -204,6 +204,71 @@
|
|||||||
"width":92.7120717279925,
|
"width":92.7120717279925,
|
||||||
"x":233.848901257569,
|
"x":233.848901257569,
|
||||||
"y":135.845612785282
|
"y":135.845612785282
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":0,
|
||||||
|
"id":9,
|
||||||
|
"name":"destination",
|
||||||
|
"point":true,
|
||||||
|
"rotation":0,
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":0,
|
||||||
|
"x":207.918025151374,
|
||||||
|
"y":243.31625523987
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":45.0829063809967,
|
||||||
|
"id":10,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"halign":"center",
|
||||||
|
"text":"destination object",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":83,
|
||||||
|
"x":167.26,
|
||||||
|
"y":254.682580344667
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":19.6921,
|
||||||
|
"id":11,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"...#start&moveTo=destination",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":202.260327899394,
|
||||||
|
"x":32.2652715416861,
|
||||||
|
"y":148.51445302748
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":19.6921,
|
||||||
|
"id":12,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"...#start2&moveTo=200,100",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":202.26,
|
||||||
|
"x":32.2654354913834,
|
||||||
|
"y":169.008165183978
|
||||||
}],
|
}],
|
||||||
"opacity":1,
|
"opacity":1,
|
||||||
"type":"objectgroup",
|
"type":"objectgroup",
|
||||||
@ -212,7 +277,7 @@
|
|||||||
"y":0
|
"y":0
|
||||||
}],
|
}],
|
||||||
"nextlayerid":11,
|
"nextlayerid":11,
|
||||||
"nextobjectid":9,
|
"nextobjectid":13,
|
||||||
"orientation":"orthogonal",
|
"orientation":"orthogonal",
|
||||||
"renderorder":"right-down",
|
"renderorder":"right-down",
|
||||||
"tiledversion":"1.7.2",
|
"tiledversion":"1.7.2",
|
||||||
|
150
maps/tests/parallax.json
Normal file
150
maps/tests/parallax.json
Normal file
File diff suppressed because one or more lines are too long
@ -2,6 +2,7 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"husky@^6.0.0":
|
husky@^7.0.1:
|
||||||
"resolved" "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz"
|
version "7.0.4"
|
||||||
"version" "6.0.0"
|
resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535"
|
||||||
|
integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==
|
||||||
|
Loading…
Reference in New Issue
Block a user