Merge branch 'develop' of ssh://git.bstly.de:222/_Bastler/partey_workadventure
This commit is contained in:
commit
667e3c0944
5
.github/workflows/build-and-deploy.yml
vendored
5
.github/workflows/build-and-deploy.yml
vendored
@ -149,6 +149,10 @@ jobs:
|
|||||||
# Create a slugified value of the branch
|
# Create a slugified value of the branch
|
||||||
- uses: rlespinasse/github-slug-action@3.1.0
|
- uses: rlespinasse/github-slug-action@3.1.0
|
||||||
|
|
||||||
|
- name: Set ADMIN_URL if "deploy-connect-to-admin" label is set
|
||||||
|
run: echo "ADMIN_API_URL=https://${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }}.test.workadventu.re" >> $GITHUB_ENV
|
||||||
|
if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy-connect-to-admin') }}
|
||||||
|
|
||||||
- name: Write certificate
|
- name: Write certificate
|
||||||
run: echo "${CERTS_PRIVATE_KEY}" > secret.key && chmod 0600 secret.key
|
run: echo "${CERTS_PRIVATE_KEY}" > secret.key && chmod 0600 secret.key
|
||||||
env:
|
env:
|
||||||
@ -185,6 +189,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
KUBE_CONFIG_FILE: ${{ secrets.KUBE_CONFIG_FILE }}
|
KUBE_CONFIG_FILE: ${{ secrets.KUBE_CONFIG_FILE }}
|
||||||
ADMIN_API_TOKEN: ${{ secrets.ADMIN_API_TOKEN }}
|
ADMIN_API_TOKEN: ${{ secrets.ADMIN_API_TOKEN }}
|
||||||
|
ADMIN_SOCKETS_TOKEN: ${{ secrets.ADMIN_SOCKETS_TOKEN }}
|
||||||
JITSI_ISS: ${{ secrets.JITSI_ISS }}
|
JITSI_ISS: ${{ secrets.JITSI_ISS }}
|
||||||
JITSI_URL: ${{ secrets.JITSI_URL }}
|
JITSI_URL: ${{ secrets.JITSI_URL }}
|
||||||
SECRET_JITSI_KEY: ${{ secrets.SECRET_JITSI_KEY }}
|
SECRET_JITSI_KEY: ${{ secrets.SECRET_JITSI_KEY }}
|
||||||
|
@ -935,9 +935,9 @@ flatted@^3.1.0:
|
|||||||
integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
|
integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
|
||||||
|
|
||||||
follow-redirects@^1.14.0:
|
follow-redirects@^1.14.0:
|
||||||
version "1.14.7"
|
version "1.14.8"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
|
||||||
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
|
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
|
||||||
|
|
||||||
fs-minipass@^2.0.0:
|
fs-minipass@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
|
@ -13,7 +13,7 @@ DOMAIN=workadventure.localhost
|
|||||||
|
|
||||||
# Subdomains
|
# Subdomains
|
||||||
# MUST match the DOMAIN variable above
|
# MUST match the DOMAIN variable above
|
||||||
FRONT_HOST=front.workadventure.localhost
|
FRONT_HOST=play.workadventure.localhost
|
||||||
PUSHER_HOST=pusher.workadventure.localhost
|
PUSHER_HOST=pusher.workadventure.localhost
|
||||||
BACK_HOST=api.workadventure.localhost
|
BACK_HOST=api.workadventure.localhost
|
||||||
MAPS_HOST=maps.workadventure.localhost
|
MAPS_HOST=maps.workadventure.localhost
|
||||||
|
@ -27,10 +27,7 @@ services:
|
|||||||
|
|
||||||
|
|
||||||
front:
|
front:
|
||||||
build:
|
image: thecodingmachine/workadventure-front:${VERSION}
|
||||||
context: ../..
|
|
||||||
dockerfile: front/Dockerfile
|
|
||||||
#image: thecodingmachine/workadventure-front:${VERSION}
|
|
||||||
environment:
|
environment:
|
||||||
- DEBUG_MODE
|
- DEBUG_MODE
|
||||||
- JITSI_URL
|
- JITSI_URL
|
||||||
@ -60,10 +57,7 @@ services:
|
|||||||
restart: ${RESTART_POLICY}
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
pusher:
|
pusher:
|
||||||
build:
|
image: thecodingmachine/workadventure-pusher:${VERSION}
|
||||||
context: ../..
|
|
||||||
dockerfile: pusher/Dockerfile
|
|
||||||
#image: thecodingmachine/workadventure-pusher:${VERSION}
|
|
||||||
command: yarn run runprod
|
command: yarn run runprod
|
||||||
environment:
|
environment:
|
||||||
- SECRET_JITSI_KEY
|
- SECRET_JITSI_KEY
|
||||||
@ -77,7 +71,7 @@ services:
|
|||||||
- "traefik.http.routers.pusher.rule=Host(`${PUSHER_HOST}`)"
|
- "traefik.http.routers.pusher.rule=Host(`${PUSHER_HOST}`)"
|
||||||
- "traefik.http.routers.pusher.entryPoints=web"
|
- "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_HOST}`)"
|
- "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.service=pusher"
|
- "traefik.http.routers.pusher-ssl.service=pusher"
|
||||||
- "traefik.http.routers.pusher-ssl.tls=true"
|
- "traefik.http.routers.pusher-ssl.tls=true"
|
||||||
@ -85,10 +79,7 @@ services:
|
|||||||
restart: ${RESTART_POLICY}
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
back:
|
back:
|
||||||
build:
|
image: thecodingmachine/workadventure-back:${VERSION}
|
||||||
context: ../..
|
|
||||||
dockerfile: back/Dockerfile
|
|
||||||
#image: thecodingmachine/workadventure-back:${VERSION}
|
|
||||||
command: yarn run runprod
|
command: yarn run runprod
|
||||||
environment:
|
environment:
|
||||||
- SECRET_JITSI_KEY
|
- SECRET_JITSI_KEY
|
||||||
@ -119,7 +110,7 @@ services:
|
|||||||
image: matthiasluedtke/iconserver:v3.13.0
|
image: matthiasluedtke/iconserver:v3.13.0
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.icon.rule=Host(`${ICON_HOST}`)"
|
- "traefik.http.routers.icon.rule=Host(`${ICON_HOST}`)"
|
||||||
- "traefik.http.routers.icon.entryPoints=web,traefik"
|
- "traefik.http.routers.icon.entryPoints=web"
|
||||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.icon-ssl.rule=Host(`${ICON_HOST}`)"
|
- "traefik.http.routers.icon-ssl.rule=Host(`${ICON_HOST}`)"
|
||||||
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
local tag = namespace,
|
local tag = namespace,
|
||||||
local url = namespace+".test.workadventu.re",
|
local url = namespace+".test.workadventu.re",
|
||||||
// develop branch does not use admin because of issue with SSL certificate of admin as of now.
|
// develop branch does not use admin because of issue with SSL certificate of admin as of now.
|
||||||
local adminUrl = if std.startsWith(namespace, "admin") then "https://"+url else null,
|
local adminUrl = if std.objectHas(env, 'ADMIN_API_URL') then env.ADMIN_API_URL else null,
|
||||||
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"containers": {
|
"containers": {
|
||||||
|
@ -4,6 +4,7 @@ WORKDIR /usr/src
|
|||||||
COPY messages .
|
COPY messages .
|
||||||
RUN yarn install && yarn ts-proto
|
RUN yarn install && yarn ts-proto
|
||||||
|
|
||||||
|
|
||||||
# webpack build
|
# webpack build
|
||||||
FROM node:14.18.2-buster-slim@sha256:20bedf0c09de887379e59a41c04284974f5fb529cf0e13aab613473ce298da3d as builder
|
FROM node:14.18.2-buster-slim@sha256:20bedf0c09de887379e59a41c04284974f5fb529cf0e13aab613473ce298da3d as builder
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
@ -16,6 +17,15 @@ COPY --from=messages /usr/src/ts-proto-generated/protos src/Messages/ts-proto-ge
|
|||||||
RUN sed -i 's/import { Observable } from "rxjs";/import type { Observable } from "rxjs";/g' src/Messages/ts-proto-generated/messages.ts
|
RUN sed -i 's/import { Observable } from "rxjs";/import type { Observable } from "rxjs";/g' src/Messages/ts-proto-generated/messages.ts
|
||||||
COPY --from=messages /usr/src/JsonMessages src/Messages/JsonMessages
|
COPY --from=messages /usr/src/JsonMessages src/Messages/JsonMessages
|
||||||
|
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update \
|
||||||
|
&& apt-get install -y \
|
||||||
|
gettext-base
|
||||||
|
|
||||||
|
RUN rm dist/iframe.html
|
||||||
|
RUN yarn run typesafe-i18n
|
||||||
|
RUN yarn run build
|
||||||
|
RUN ./templater.sh
|
||||||
|
|
||||||
# passing arguments as environment
|
# passing arguments as environment
|
||||||
ARG DEBUG_MODE
|
ARG DEBUG_MODE
|
||||||
ARG JITSI_URL
|
ARG JITSI_URL
|
||||||
@ -35,33 +45,28 @@ ARG DISABLE_NOTIFICATIONS
|
|||||||
ARG SKIP_RENDER_OPTIMIZATIONS
|
ARG SKIP_RENDER_OPTIMIZATIONS
|
||||||
ARG OPID_LOGIN_SCREEN_PROVIDER
|
ARG OPID_LOGIN_SCREEN_PROVIDER
|
||||||
|
|
||||||
# Removing the iframe.html file from the final image as this adds a XSS attack.
|
ENV DEBUG_MODE=$DEBUG_MODE
|
||||||
# iframe.html is only in dev mode to circumvent a limitation
|
ENV JITSI_URL=$JITSI_URL
|
||||||
RUN rm dist/iframe.html
|
ENV JITSI_PRIVATE_MODE=$JITSI_PRIVATE_MODE
|
||||||
ENV NODE_ENV=production
|
ENV PUSHER_URL=$PUSHER_URL
|
||||||
RUN ./templater.sh
|
ENV ICON_URL=$ICON_URL
|
||||||
RUN yarn run typesafe-i18n
|
ENV ADMIN_URL=$ADMIN_URL
|
||||||
RUN \
|
ENV STUN_SERVER=$STUN_SERVER
|
||||||
DEBUG_MODE=$DEBUG_MODE \
|
ENV TURN_SERVER=$TURN_SERVER
|
||||||
JITSI_URL=$JITSI_URL \
|
ENV TURN_USER=$TURN_USER
|
||||||
JITSI_PRIVATE_MODE=$JITSI_PRIVATE_MODE \
|
ENV TURN_PASSWORD=$TURN_PASSWORD
|
||||||
PUSHER_URL=$PUSHER_URL \
|
ENV MAX_PER_GROUP=$MAX_PER_GROUP
|
||||||
ICON_URL=$ICON_URL \
|
ENV MAX_USERNAME_LENGTH=$MAX_USERNAME_LENGTH
|
||||||
ADMIN_URL=$ADMIN_URL \
|
ENV PROFILE_URL=$PROFILE_URL
|
||||||
STUN_SERVER=$STUN_SERVER \
|
ENV START_ROOM_URL=$START_ROOM_URL
|
||||||
TURN_SERVER=$TURN_SERVER \
|
ENV DISABLE_NOTIFICATIONS=$DISABLE_NOTIFICATIONS
|
||||||
TURN_USER=$TURN_USER \
|
ENV SKIP_RENDER_OPTIMIZATIONS=$SKIP_RENDER_OPTIMIZATIONS
|
||||||
TURN_PASSWORD=$TURN_PASSWORD \
|
ENV OPID_LOGIN_SCREEN_PROVIDER=$OPID_LOGIN_SCREEN_PROVIDER
|
||||||
MAX_PER_GROUP=$MAX_PER_GROUP \
|
|
||||||
MAX_USERNAME_LENGTH=$MAX_USERNAME_LENGTH \
|
RUN envsubst < dist/env-config.template.js > dist/env-config.js
|
||||||
PROFILE_URL=$PROFILE_URL \
|
|
||||||
START_ROOM_URL=$START_ROOM_URL \
|
|
||||||
DISABLE_NOTIFICATIONS=$DISABLE_NOTIFICATIONS \
|
|
||||||
SKIP_RENDER_OPTIMIZATIONS=$SKIP_RENDER_OPTIMIZATIONS \
|
|
||||||
OPID_LOGIN_SCREEN_PROVIDER=$OPID_LOGIN_SCREEN_PROVIDER \
|
|
||||||
yarn run build
|
|
||||||
|
|
||||||
# final production image
|
# final production image
|
||||||
FROM nginx:mainline-alpine
|
FROM nginx:mainline-alpine
|
||||||
COPY front/nginx-vhost.conf /etc/nginx/conf.d/default.conf
|
COPY front/nginx-vhost.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY --from=builder /usr/src/dist /usr/share/nginx/html
|
COPY --from=builder /usr/src/dist /usr/share/nginx/html
|
||||||
|
RUN cat /usr/share/nginx/html/env-config.js
|
||||||
|
1
front/dist/.gitignore
vendored
1
front/dist/.gitignore
vendored
@ -4,3 +4,4 @@ index.html
|
|||||||
style.*.css
|
style.*.css
|
||||||
!env-config.template.js
|
!env-config.template.js
|
||||||
*.png
|
*.png
|
||||||
|
!/resources/**
|
||||||
|
3
front/dist/index.ejs
vendored
3
front/dist/index.ejs
vendored
@ -29,9 +29,8 @@
|
|||||||
|
|
||||||
<script src="/env-config.js"></script>
|
<script src="/env-config.js"></script>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<link href="https://unpkg.com/nes.css@2.3.0/css/nes.min.css" rel="stylesheet" />
|
|
||||||
|
|
||||||
<title>WorkAdventure</title>
|
<title>Partey</title>
|
||||||
</head>
|
</head>
|
||||||
<body id="body" style="margin: 0; background-color: #000">
|
<body id="body" style="margin: 0; background-color: #000">
|
||||||
<div class="main-container" id="main-container">
|
<div class="main-container" id="main-container">
|
||||||
|
BIN
front/dist/resources/icons/icon_talking.png
vendored
Normal file
BIN
front/dist/resources/icons/icon_talking.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -42,6 +42,7 @@
|
|||||||
"webpack-dev-server": "^3.11.2"
|
"webpack-dev-server": "^3.11.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@16bits/nes.css": "^2.3.2",
|
||||||
"@fontsource/press-start-2p": "^4.3.0",
|
"@fontsource/press-start-2p": "^4.3.0",
|
||||||
"@joeattardi/emoji-button": "^4.6.2",
|
"@joeattardi/emoji-button": "^4.6.2",
|
||||||
"@types/simple-peer": "^9.11.1",
|
"@types/simple-peer": "^9.11.1",
|
||||||
|
@ -9,6 +9,7 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface()
|
|||||||
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),
|
||||||
|
hint: tg.isOptional(tg.isString),
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
@ -48,7 +48,8 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
widthPercent?: number,
|
widthPercent?: number,
|
||||||
position?: number,
|
position?: number,
|
||||||
closable?: boolean,
|
closable?: boolean,
|
||||||
lazy?: boolean
|
lazy?: boolean,
|
||||||
|
hint?: string
|
||||||
): Promise<CoWebsite> {
|
): Promise<CoWebsite> {
|
||||||
const result = await queryWorkadventure({
|
const result = await queryWorkadventure({
|
||||||
type: "openCoWebsite",
|
type: "openCoWebsite",
|
||||||
@ -60,6 +61,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
position,
|
position,
|
||||||
closable,
|
closable,
|
||||||
lazy,
|
lazy,
|
||||||
|
hint,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return new CoWebsite(result.id);
|
return new CoWebsite(result.id);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
|
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
|
||||||
import MediaBox from "../Video/MediaBox.svelte";
|
import MediaBox from "../Video/MediaBox.svelte";
|
||||||
|
|
||||||
export let highlightedEmbedScreen: EmbedScreen | null;
|
export let highlightedEmbedScreen: EmbedScreen | undefined;
|
||||||
export let full = false;
|
export let full = false;
|
||||||
$: clickable = !full;
|
$: clickable = !full;
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
|
import { i18nJson } from "../../i18n/locales";
|
||||||
|
|
||||||
export let index: number;
|
export let index: number;
|
||||||
export let coWebsite: CoWebsite;
|
export let coWebsite: CoWebsite;
|
||||||
@ -65,6 +67,17 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function i18n(text: string | undefined): string {
|
||||||
|
if (typeof text === "string") {
|
||||||
|
return i18nJson(text);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitize(html : string | undefined): string {
|
||||||
|
return HtmlUtils.sanitize(html);
|
||||||
|
}
|
||||||
|
|
||||||
let isHighlight: boolean = false;
|
let isHighlight: boolean = false;
|
||||||
let isMain: boolean = false;
|
let isMain: boolean = false;
|
||||||
$: {
|
$: {
|
||||||
@ -73,9 +86,9 @@
|
|||||||
$mainCoWebsite !== undefined &&
|
$mainCoWebsite !== undefined &&
|
||||||
$mainCoWebsite.getId() === coWebsite.getId();
|
$mainCoWebsite.getId() === coWebsite.getId();
|
||||||
isHighlight =
|
isHighlight =
|
||||||
$highlightedEmbedScreen !== null &&
|
$highlightedEmbedScreen !== undefined &&
|
||||||
$highlightedEmbedScreen.type === "cowebsite" &&
|
$highlightedEmbedScreen?.type === "cowebsite" &&
|
||||||
$highlightedEmbedScreen.embed.getId() === coWebsite.getId();
|
$highlightedEmbedScreen?.embed.getId() === coWebsite.getId();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -188,6 +201,12 @@
|
|||||||
/>
|
/>
|
||||||
</rect>
|
</rect>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
{#if coWebsite.getHint() && !isMain && !isHighlight }
|
||||||
|
<div class="cowebsite-thumbnail-hint nes-balloon from-left">
|
||||||
|
<p>{@html sanitize(i18n(coWebsite.getHint()))}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -320,5 +339,19 @@
|
|||||||
padding: 7px;
|
padding: 7px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cowebsite-thumbnail-hint {
|
||||||
|
display: none;
|
||||||
|
position:absolute;
|
||||||
|
padding: 8px 4px;
|
||||||
|
text-align: center;
|
||||||
|
bottom: 50px;
|
||||||
|
width: clamp(150px, 15vw, 15vw);
|
||||||
|
left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .cowebsite-thumbnail-hint {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
left: 2%;
|
left: 2%;
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
audioConstraintStore,
|
audioConstraintStore,
|
||||||
cameraListStore,
|
cameraListStore,
|
||||||
localStreamStore,
|
localStreamStore,
|
||||||
|
localVolumeStore,
|
||||||
microphoneListStore,
|
microphoneListStore,
|
||||||
videoConstraintStore,
|
videoConstraintStore,
|
||||||
} from "../../Stores/MediaStore";
|
} from "../../Stores/MediaStore";
|
||||||
@ -38,7 +39,7 @@
|
|||||||
|
|
||||||
let stream: MediaStream | null;
|
let stream: MediaStream | null;
|
||||||
|
|
||||||
const unsubscribe = localStreamStore.subscribe((value) => {
|
const unsubscribeLocalStreamStore = localStreamStore.subscribe((value) => {
|
||||||
if (value.type === "success") {
|
if (value.type === "success") {
|
||||||
stream = value.stream;
|
stream = value.stream;
|
||||||
|
|
||||||
@ -59,7 +60,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(unsubscribe);
|
onDestroy(() => {
|
||||||
|
unsubscribeLocalStreamStore();
|
||||||
|
});
|
||||||
|
|
||||||
function normalizeDeviceName(label: string): string {
|
function normalizeDeviceName(label: string): string {
|
||||||
// remove IDs (that can appear in Chrome, like: "HD Pro Webcam (4df7:4eda)"
|
// remove IDs (that can appear in Chrome, like: "HD Pro Webcam (4df7:4eda)"
|
||||||
@ -86,7 +89,7 @@
|
|||||||
<img class="background-img" src={cinemaCloseImg} alt="" />
|
<img class="background-img" src={cinemaCloseImg} alt="" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<HorizontalSoundMeterWidget {stream} />
|
<HorizontalSoundMeterWidget volume={$localVolumeStore} />
|
||||||
|
|
||||||
<section class="selectWebcamForm">
|
<section class="selectWebcamForm">
|
||||||
{#if $cameraListStore.length > 1}
|
{#if $cameraListStore.length > 1}
|
||||||
|
@ -1,50 +1,8 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { AudioContext } from "standardized-audio-context";
|
export let volume = 0;
|
||||||
import { SoundMeter } from "../../Phaser/Components/SoundMeter";
|
|
||||||
import { onDestroy } from "svelte";
|
|
||||||
|
|
||||||
export let stream: MediaStream | null;
|
|
||||||
let volume = 0;
|
|
||||||
|
|
||||||
const NB_BARS = 20;
|
const NB_BARS = 20;
|
||||||
|
|
||||||
let timeout: ReturnType<typeof setTimeout>;
|
|
||||||
const soundMeter = new SoundMeter();
|
|
||||||
let display = false;
|
|
||||||
let error = false;
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if (stream && stream.getAudioTracks().length > 0) {
|
|
||||||
display = true;
|
|
||||||
soundMeter.connectToSource(stream, new AudioContext());
|
|
||||||
|
|
||||||
if (timeout) {
|
|
||||||
clearInterval(timeout);
|
|
||||||
error = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = setInterval(() => {
|
|
||||||
try {
|
|
||||||
volume = parseInt(((soundMeter.getVolume() / 100) * NB_BARS).toFixed(0));
|
|
||||||
} catch (err) {
|
|
||||||
if (!error) {
|
|
||||||
console.error(err);
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
display = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
soundMeter.stop();
|
|
||||||
if (timeout) {
|
|
||||||
clearInterval(timeout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function color(i: number, volume: number) {
|
function color(i: number, volume: number) {
|
||||||
const red = (255 * i) / NB_BARS;
|
const red = (255 * i) / NB_BARS;
|
||||||
const green = 255 * (1 - i / NB_BARS);
|
const green = 255 * (1 - i / NB_BARS);
|
||||||
@ -58,7 +16,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="horizontal-sound-meter" class:active={display}>
|
<div class="horizontal-sound-meter" class:active={volume !== undefined}>
|
||||||
{#each [...Array(NB_BARS).keys()] as i (i)}
|
{#each [...Array(NB_BARS).keys()] as i (i)}
|
||||||
<div style={color(i, volume)} />
|
<div style={color(i, volume)} />
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { obtainedMediaConstraintStore } from "../Stores/MediaStore";
|
import { localVolumeStore, obtainedMediaConstraintStore } from "../Stores/MediaStore";
|
||||||
import { localStreamStore, isSilentStore } from "../Stores/MediaStore";
|
import { localStreamStore, isSilentStore } from "../Stores/MediaStore";
|
||||||
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
||||||
import { onDestroy, onMount } from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
let stream: MediaStream | null;
|
let stream: MediaStream | null;
|
||||||
|
|
||||||
const unsubscribe = localStreamStore.subscribe((value) => {
|
const unsubscribeLocalStreamStore = localStreamStore.subscribe((value) => {
|
||||||
if (value.type === "success") {
|
if (value.type === "success") {
|
||||||
stream = value.stream;
|
stream = value.stream;
|
||||||
} else {
|
} else {
|
||||||
@ -16,7 +16,9 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(unsubscribe);
|
onDestroy(() => {
|
||||||
|
unsubscribeLocalStreamStore();
|
||||||
|
});
|
||||||
|
|
||||||
let isSilent: boolean;
|
let isSilent: boolean;
|
||||||
const unsubscribeIsSilent = isSilentStore.subscribe((value) => {
|
const unsubscribeIsSilent = isSilentStore.subscribe((value) => {
|
||||||
@ -51,7 +53,7 @@
|
|||||||
<div class="is-silent">{$LL.camera.my.silentZone()}</div>
|
<div class="is-silent">{$LL.camera.my.silentZone()}</div>
|
||||||
{:else if $localStreamStore.type === "success" && $localStreamStore.stream}
|
{:else if $localStreamStore.type === "success" && $localStreamStore.stream}
|
||||||
<video class="my-cam-video" use:srcObject={stream} autoplay muted playsinline />
|
<video class="my-cam-video" use:srcObject={stream} autoplay muted playsinline />
|
||||||
<SoundMeterWidget {stream} />
|
<SoundMeterWidget volume={$localVolumeStore} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,47 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { AudioContext } from "standardized-audio-context";
|
export let volume = 0;
|
||||||
import { SoundMeter } from "../Phaser/Components/SoundMeter";
|
let display = true;
|
||||||
import { onDestroy } from "svelte";
|
|
||||||
|
|
||||||
export let stream: MediaStream | null;
|
|
||||||
let volume = 0;
|
|
||||||
|
|
||||||
let timeout: ReturnType<typeof setTimeout>;
|
|
||||||
const soundMeter = new SoundMeter();
|
|
||||||
let display = false;
|
|
||||||
let error = false;
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if (stream && stream.getAudioTracks().length > 0) {
|
|
||||||
display = true;
|
|
||||||
soundMeter.connectToSource(stream, new AudioContext());
|
|
||||||
|
|
||||||
if (timeout) {
|
|
||||||
clearInterval(timeout);
|
|
||||||
error = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = setInterval(() => {
|
|
||||||
try {
|
|
||||||
volume = soundMeter.getVolume();
|
|
||||||
} catch (err) {
|
|
||||||
if (!error) {
|
|
||||||
console.error(err);
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
display = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
soundMeter.stop();
|
|
||||||
if (timeout) {
|
|
||||||
clearInterval(timeout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="sound-progress" class:active={display}>
|
<div class="sound-progress" class:active={display}>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
export let peer: VideoPeer;
|
export let peer: VideoPeer;
|
||||||
let streamStore = peer.streamStore;
|
let streamStore = peer.streamStore;
|
||||||
|
let volumeStore = peer.volumeStore;
|
||||||
let name = peer.userName;
|
let name = peer.userName;
|
||||||
let statusStore = peer.statusStore;
|
let statusStore = peer.statusStore;
|
||||||
let constraintStore = peer.constraintsStore;
|
let constraintStore = peer.constraintsStore;
|
||||||
@ -93,7 +94,7 @@
|
|||||||
/>
|
/>
|
||||||
<img src={blockSignImg} draggable="false" on:dragstart|preventDefault={noDrag} class="block-logo" alt="Block" />
|
<img src={blockSignImg} draggable="false" on:dragstart|preventDefault={noDrag} class="block-logo" alt="Block" />
|
||||||
{#if $constraintStore && $constraintStore.audio !== false}
|
{#if $constraintStore && $constraintStore.audio !== false}
|
||||||
<SoundMeterWidget stream={$streamStore} />
|
<SoundMeterWidget volume={$volumeStore} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -378,9 +378,8 @@ class ConnectionManager {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("Could not set locale", err);
|
console.warn("Could not set locale", err);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
console.log("no locale", locale);
|
|
||||||
}
|
|
||||||
//user connected, set connected store for menu at true
|
//user connected, set connected store for menu at true
|
||||||
userIsConnected.set(true);
|
userIsConnected.set(true);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { IAnalyserNode, IAudioContext, IMediaStreamAudioSourceNode } from "standardized-audio-context";
|
import { AudioContext, IAnalyserNode, IAudioContext, IMediaStreamAudioSourceNode } from "standardized-audio-context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to measure the sound volume of a media stream
|
* Class to measure the sound volume of a media stream
|
||||||
@ -6,41 +6,15 @@ import type { IAnalyserNode, IAudioContext, IMediaStreamAudioSourceNode } from "
|
|||||||
export class SoundMeter {
|
export class SoundMeter {
|
||||||
private instant: number;
|
private instant: number;
|
||||||
private clip: number;
|
private clip: number;
|
||||||
//private script: ScriptProcessorNode;
|
|
||||||
private analyser: IAnalyserNode<IAudioContext> | undefined;
|
private analyser: IAnalyserNode<IAudioContext> | undefined;
|
||||||
private dataArray: Uint8Array | undefined;
|
private dataArray: Uint8Array | undefined;
|
||||||
private context: IAudioContext | undefined;
|
private context: IAudioContext | undefined;
|
||||||
private source: IMediaStreamAudioSourceNode<IAudioContext> | undefined;
|
private source: IMediaStreamAudioSourceNode<IAudioContext> | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor(mediaStream: MediaStream) {
|
||||||
this.instant = 0.0;
|
this.instant = 0.0;
|
||||||
this.clip = 0.0;
|
this.clip = 0.0;
|
||||||
//this.script = context.createScriptProcessor(2048, 1, 1);
|
this.connectToSource(mediaStream, new AudioContext());
|
||||||
}
|
|
||||||
|
|
||||||
private init(context: IAudioContext) {
|
|
||||||
this.context = context;
|
|
||||||
this.analyser = this.context.createAnalyser();
|
|
||||||
|
|
||||||
this.analyser.fftSize = 2048;
|
|
||||||
const bufferLength = this.analyser.fftSize;
|
|
||||||
this.dataArray = new Uint8Array(bufferLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
public connectToSource(stream: MediaStream, context: IAudioContext): void {
|
|
||||||
if (this.source !== undefined) {
|
|
||||||
this.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.init(context);
|
|
||||||
|
|
||||||
this.source = this.context?.createMediaStreamSource(stream);
|
|
||||||
if (this.analyser !== undefined) {
|
|
||||||
this.source?.connect(this.analyser);
|
|
||||||
}
|
|
||||||
//analyser.connect(distortion);
|
|
||||||
//distortion.connect(this.context.destination);
|
|
||||||
//this.analyser.connect(this.context.destination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getVolume(): number {
|
public getVolume(): number {
|
||||||
@ -78,4 +52,29 @@ export class SoundMeter {
|
|||||||
this.dataArray = undefined;
|
this.dataArray = undefined;
|
||||||
this.source = undefined;
|
this.source = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private init(context: IAudioContext) {
|
||||||
|
this.context = context;
|
||||||
|
this.analyser = this.context.createAnalyser();
|
||||||
|
|
||||||
|
this.analyser.fftSize = 2048;
|
||||||
|
const bufferLength = this.analyser.fftSize;
|
||||||
|
this.dataArray = new Uint8Array(bufferLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private connectToSource(stream: MediaStream, context: IAudioContext): void {
|
||||||
|
if (this.source !== undefined) {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init(context);
|
||||||
|
|
||||||
|
this.source = this.context?.createMediaStreamSource(stream);
|
||||||
|
if (this.analyser !== undefined) {
|
||||||
|
this.source?.connect(this.analyser);
|
||||||
|
}
|
||||||
|
//analyser.connect(distortion);
|
||||||
|
//distortion.connect(this.context.destination);
|
||||||
|
//this.analyser.connect(this.context.destination);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
58
front/src/Phaser/Components/TalkIcon.ts
Normal file
58
front/src/Phaser/Components/TalkIcon.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { Easing } from "../../types";
|
||||||
|
|
||||||
|
export class TalkIcon extends Phaser.GameObjects.Image {
|
||||||
|
private shown: boolean;
|
||||||
|
private showAnimationTween?: Phaser.Tweens.Tween;
|
||||||
|
|
||||||
|
private defaultPosition: { x: number; y: number };
|
||||||
|
private defaultScale: number;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number) {
|
||||||
|
super(scene, x, y, "iconTalk");
|
||||||
|
|
||||||
|
this.defaultPosition = { x, y };
|
||||||
|
this.defaultScale = 0.3;
|
||||||
|
|
||||||
|
this.shown = false;
|
||||||
|
this.setAlpha(0);
|
||||||
|
this.setScale(this.defaultScale);
|
||||||
|
|
||||||
|
this.scene.add.existing(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show(show: boolean = true, forceClose: boolean = false): void {
|
||||||
|
if (this.shown === show && !forceClose) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showAnimation(show, forceClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
private showAnimation(show: boolean = true, forceClose: boolean = false) {
|
||||||
|
if (forceClose && !show) {
|
||||||
|
this.showAnimationTween?.stop();
|
||||||
|
} else if (this.showAnimationTween?.isPlaying()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.shown = show;
|
||||||
|
if (show) {
|
||||||
|
this.y += 50;
|
||||||
|
this.scale = 0.05;
|
||||||
|
this.alpha = 0;
|
||||||
|
}
|
||||||
|
this.showAnimationTween = this.scene.tweens.add({
|
||||||
|
targets: [this],
|
||||||
|
duration: 350,
|
||||||
|
alpha: show ? 1 : 0,
|
||||||
|
y: this.defaultPosition.y,
|
||||||
|
scale: this.defaultScale,
|
||||||
|
ease: Easing.BackEaseOut,
|
||||||
|
onComplete: () => {
|
||||||
|
this.showAnimationTween = undefined;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public isShown(): boolean {
|
||||||
|
return this.shown;
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ import { Unsubscriber, Writable, writable } from "svelte/store";
|
|||||||
import { createColorStore } from "../../Stores/OutlineColorStore";
|
import { createColorStore } from "../../Stores/OutlineColorStore";
|
||||||
import type { OutlineableInterface } from "../Game/OutlineableInterface";
|
import type { OutlineableInterface } from "../Game/OutlineableInterface";
|
||||||
import type CancelablePromise from "cancelable-promise";
|
import type CancelablePromise from "cancelable-promise";
|
||||||
|
import { TalkIcon } from "../Components/TalkIcon";
|
||||||
|
|
||||||
const playerNameY = -25;
|
const playerNameY = -25;
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ const interactiveRadius = 35;
|
|||||||
export abstract class Character extends Container implements OutlineableInterface {
|
export abstract class Character extends Container implements OutlineableInterface {
|
||||||
private bubble: SpeechBubble | null = null;
|
private bubble: SpeechBubble | null = null;
|
||||||
private readonly playerNameText: Text;
|
private readonly playerNameText: Text;
|
||||||
|
private readonly talkIcon: TalkIcon;
|
||||||
public playerName: string;
|
public playerName: string;
|
||||||
public sprites: Map<string, Sprite>;
|
public sprites: Map<string, Sprite>;
|
||||||
protected lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
protected lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
||||||
@ -102,6 +104,17 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
fontSize: 35,
|
fontSize: 35,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.talkIcon = new TalkIcon(scene, 0, -45);
|
||||||
|
this.add(this.talkIcon);
|
||||||
|
|
||||||
|
if (isClickable) {
|
||||||
|
this.setInteractive({
|
||||||
|
hitArea: new Phaser.Geom.Circle(0, 0, interactiveRadius),
|
||||||
|
hitAreaCallback: Phaser.Geom.Circle.Contains, //eslint-disable-line @typescript-eslint/unbound-method
|
||||||
|
useHandCursor: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
this.playerNameText.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
this.playerNameText.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
||||||
this.add(this.playerNameText);
|
this.add(this.playerNameText);
|
||||||
|
|
||||||
@ -200,6 +213,10 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public showTalkIcon(show: boolean = true, forceClose: boolean = false): void {
|
||||||
|
this.talkIcon.show(show, forceClose);
|
||||||
|
}
|
||||||
|
|
||||||
public addCompanion(name: string, texturePromise?: CancelablePromise<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);
|
||||||
|
@ -7,6 +7,7 @@ import type { PlayerAnimationDirections } from "../Player/Animation";
|
|||||||
import type { Unsubscriber } from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import type { ActivatableInterface } from "../Game/ActivatableInterface";
|
import type { ActivatableInterface } from "../Game/ActivatableInterface";
|
||||||
import type CancelablePromise from "cancelable-promise";
|
import type CancelablePromise from "cancelable-promise";
|
||||||
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||||
@ -107,7 +108,7 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
|||||||
private registerDefaultActionsMenuActions(): void {
|
private registerDefaultActionsMenuActions(): void {
|
||||||
if (this.visitCardUrl) {
|
if (this.visitCardUrl) {
|
||||||
this.registeredActions.push({
|
this.registeredActions.push({
|
||||||
actionName: "Visiting Card",
|
actionName: LL.woka.menu.businessCard(),
|
||||||
callback: () => {
|
callback: () => {
|
||||||
requestVisitCardsStore.set(this.visitCardUrl);
|
requestVisitCardsStore.set(this.visitCardUrl);
|
||||||
actionsMenuStore.clear();
|
actionsMenuStore.clear();
|
||||||
|
@ -133,6 +133,18 @@ export class GameMap {
|
|||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getWalkingCostGrid(): number[][] {
|
||||||
|
const grid: number[][] = [];
|
||||||
|
for (let y = 0; y < this.map.height; y += 1) {
|
||||||
|
const row: number[] = [];
|
||||||
|
for (let x = 0; x < this.map.width; x += 1) {
|
||||||
|
row.push(this.getWalkingCostAt(x, y));
|
||||||
|
}
|
||||||
|
grid.push(row);
|
||||||
|
}
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
public getTileDimensions(): { width: number; height: number } {
|
public getTileDimensions(): { width: number; height: number } {
|
||||||
return { width: this.map.tilewidth, height: this.map.tileheight };
|
return { width: this.map.tilewidth, height: this.map.tileheight };
|
||||||
}
|
}
|
||||||
@ -356,6 +368,32 @@ export class GameMap {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getWalkingCostAt(x: number, y: number): number {
|
||||||
|
const bigCost = 100;
|
||||||
|
for (const layer of this.phaserLayers) {
|
||||||
|
if (!layer.visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const tile = layer.getTileAt(x, y);
|
||||||
|
if (!tile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
tile &&
|
||||||
|
(tile.properties[GameMapProperties.EXIT_URL] || tile.properties[GameMapProperties.EXIT_SCENE_URL])
|
||||||
|
) {
|
||||||
|
return bigCost;
|
||||||
|
}
|
||||||
|
for (const property of layer.layer.properties) {
|
||||||
|
//@ts-ignore
|
||||||
|
if (property.name && property.name === "exitUrl") {
|
||||||
|
return bigCost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private triggerAllProperties(): void {
|
private triggerAllProperties(): void {
|
||||||
const newProps = this.getProperties(this.key ?? 0);
|
const newProps = this.getProperties(this.key ?? 0);
|
||||||
const oldProps = this.lastProperties;
|
const oldProps = this.lastProperties;
|
||||||
|
@ -24,6 +24,7 @@ export enum GameMapProperties {
|
|||||||
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",
|
||||||
|
OPEN_WEBSITE_HINT = "openWebsiteHint",
|
||||||
PLAY_AUDIO = "playAudio",
|
PLAY_AUDIO = "playAudio",
|
||||||
PLAY_AUDIO_LOOP = "playAudioLoop",
|
PLAY_AUDIO_LOOP = "playAudioLoop",
|
||||||
READABLE_BY = "readableBy",
|
READABLE_BY = "readableBy",
|
||||||
|
@ -194,6 +194,7 @@ export class GameMapPropertiesListener {
|
|||||||
let websitePositionProperty: number | undefined;
|
let websitePositionProperty: number | undefined;
|
||||||
let websiteTriggerProperty: string | undefined;
|
let websiteTriggerProperty: string | undefined;
|
||||||
let websiteTriggerMessageProperty: string | undefined;
|
let websiteTriggerMessageProperty: string | undefined;
|
||||||
|
let websiteHintProperty: string | undefined;
|
||||||
|
|
||||||
layer.properties.forEach((property) => {
|
layer.properties.forEach((property) => {
|
||||||
switch (property.name) {
|
switch (property.name) {
|
||||||
@ -218,6 +219,9 @@ export class GameMapPropertiesListener {
|
|||||||
case GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE:
|
case GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE:
|
||||||
websiteTriggerMessageProperty = property.value as string | undefined;
|
websiteTriggerMessageProperty = property.value as string | undefined;
|
||||||
break;
|
break;
|
||||||
|
case GameMapProperties.OPEN_WEBSITE_HINT:
|
||||||
|
websiteHintProperty = property.value as string | undefined;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -251,7 +255,8 @@ export class GameMapPropertiesListener {
|
|||||||
allowApiProperty,
|
allowApiProperty,
|
||||||
websitePolicyProperty,
|
websitePolicyProperty,
|
||||||
websiteWidthProperty,
|
websiteWidthProperty,
|
||||||
false
|
false,
|
||||||
|
websiteHintProperty
|
||||||
);
|
);
|
||||||
|
|
||||||
coWebsiteOpen.coWebsite = coWebsite;
|
coWebsiteOpen.coWebsite = coWebsite;
|
||||||
@ -284,7 +289,8 @@ export class GameMapPropertiesListener {
|
|||||||
allowApiProperty,
|
allowApiProperty,
|
||||||
websitePolicyProperty,
|
websitePolicyProperty,
|
||||||
websiteWidthProperty,
|
websiteWidthProperty,
|
||||||
false
|
false,
|
||||||
|
websiteHintProperty
|
||||||
);
|
);
|
||||||
|
|
||||||
coWebsiteOpen.coWebsite = coWebsite;
|
coWebsiteOpen.coWebsite = coWebsite;
|
||||||
|
@ -92,6 +92,7 @@ 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 { i18nJson } from "../../i18n/locales";
|
import { i18nJson } from "../../i18n/locales";
|
||||||
|
import { localVolumeStore } from "../../Stores/MediaStore";
|
||||||
import { StringUtils } from "../../Utils/StringUtils";
|
import { StringUtils } from "../../Utils/StringUtils";
|
||||||
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
@ -173,6 +174,9 @@ export class GameScene extends DirtyScene {
|
|||||||
private peerStoreUnsubscribe!: Unsubscriber;
|
private peerStoreUnsubscribe!: Unsubscriber;
|
||||||
private emoteUnsubscribe!: Unsubscriber;
|
private emoteUnsubscribe!: Unsubscriber;
|
||||||
private emoteMenuUnsubscribe!: Unsubscriber;
|
private emoteMenuUnsubscribe!: Unsubscriber;
|
||||||
|
|
||||||
|
private volumeStoreUnsubscribers: Map<number, Unsubscriber> = new Map<number, Unsubscriber>();
|
||||||
|
private localVolumeStoreUnsubscriber: Unsubscriber | undefined;
|
||||||
private followUsersColorStoreUnsubscribe!: Unsubscriber;
|
private followUsersColorStoreUnsubscribe!: Unsubscriber;
|
||||||
|
|
||||||
private biggestAvailableAreaStoreUnsubscribe!: () => void;
|
private biggestAvailableAreaStoreUnsubscribe!: () => void;
|
||||||
@ -250,6 +254,7 @@ export class GameScene extends DirtyScene {
|
|||||||
loadCustomTexture(this.load, texture).catch((e) => console.error(e));
|
loadCustomTexture(this.load, texture).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.load.image("iconTalk", "/resources/icons/icon_talking.png");
|
||||||
|
|
||||||
if (touchScreenManager.supportTouchScreen) {
|
if (touchScreenManager.supportTouchScreen) {
|
||||||
this.load.image(joystickBaseKey, joystickBaseImg);
|
this.load.image(joystickBaseKey, joystickBaseImg);
|
||||||
@ -585,6 +590,7 @@ export class GameScene extends DirtyScene {
|
|||||||
this.pathfindingManager = new PathfindingManager(
|
this.pathfindingManager = new PathfindingManager(
|
||||||
this,
|
this,
|
||||||
this.gameMap.getCollisionGrid(),
|
this.gameMap.getCollisionGrid(),
|
||||||
|
this.gameMap.getWalkingCostGrid(),
|
||||||
this.gameMap.getTileDimensions()
|
this.gameMap.getTileDimensions()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -600,12 +606,6 @@ export class GameScene extends DirtyScene {
|
|||||||
waScaleManager
|
waScaleManager
|
||||||
);
|
);
|
||||||
|
|
||||||
this.pathfindingManager = new PathfindingManager(
|
|
||||||
this,
|
|
||||||
this.gameMap.getCollisionGrid(),
|
|
||||||
this.gameMap.getTileDimensions()
|
|
||||||
);
|
|
||||||
|
|
||||||
this.activatablesManager = new ActivatablesManager(this.CurrentPlayer);
|
this.activatablesManager = new ActivatablesManager(this.CurrentPlayer);
|
||||||
|
|
||||||
biggestAvailableAreaStore.recompute();
|
biggestAvailableAreaStore.recompute();
|
||||||
@ -659,14 +659,45 @@ export class GameScene extends DirtyScene {
|
|||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const talkIconVolumeTreshold = 10;
|
||||||
let oldPeerNumber = 0;
|
let oldPeerNumber = 0;
|
||||||
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||||
|
this.volumeStoreUnsubscribers.forEach((unsubscribe) => unsubscribe());
|
||||||
|
this.volumeStoreUnsubscribers.clear();
|
||||||
|
|
||||||
|
for (const [key, videoStream] of peers) {
|
||||||
|
this.volumeStoreUnsubscribers.set(
|
||||||
|
key,
|
||||||
|
videoStream.volumeStore.subscribe((volume) => {
|
||||||
|
if (volume) {
|
||||||
|
this.MapPlayersByKey.get(key)?.showTalkIcon(volume > talkIconVolumeTreshold);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const newPeerNumber = peers.size;
|
const newPeerNumber = peers.size;
|
||||||
if (newPeerNumber > oldPeerNumber) {
|
if (newPeerNumber > oldPeerNumber) {
|
||||||
this.playSound("audio-webrtc-in");
|
this.playSound("audio-webrtc-in");
|
||||||
} else if (newPeerNumber < oldPeerNumber) {
|
} else if (newPeerNumber < oldPeerNumber) {
|
||||||
this.playSound("audio-webrtc-out");
|
this.playSound("audio-webrtc-out");
|
||||||
}
|
}
|
||||||
|
if (newPeerNumber > 0) {
|
||||||
|
if (!this.localVolumeStoreUnsubscriber) {
|
||||||
|
this.localVolumeStoreUnsubscriber = localVolumeStore.subscribe((volume) => {
|
||||||
|
if (volume) {
|
||||||
|
this.CurrentPlayer.showTalkIcon(volume > talkIconVolumeTreshold);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.CurrentPlayer.showTalkIcon(false, true);
|
||||||
|
this.MapPlayersByKey.forEach((remotePlayer) => remotePlayer.showTalkIcon(false, true));
|
||||||
|
if (this.localVolumeStoreUnsubscriber) {
|
||||||
|
this.localVolumeStoreUnsubscriber();
|
||||||
|
this.localVolumeStoreUnsubscriber = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
oldPeerNumber = newPeerNumber;
|
oldPeerNumber = newPeerNumber;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1218,7 +1249,8 @@ export class GameScene extends DirtyScene {
|
|||||||
openCoWebsite.allowApi,
|
openCoWebsite.allowApi,
|
||||||
openCoWebsite.allowPolicy,
|
openCoWebsite.allowPolicy,
|
||||||
openCoWebsite.widthPercent,
|
openCoWebsite.widthPercent,
|
||||||
openCoWebsite.closable ?? true
|
openCoWebsite.closable ?? true,
|
||||||
|
openCoWebsite.hint
|
||||||
);
|
);
|
||||||
|
|
||||||
if (openCoWebsite.lazy === undefined || !openCoWebsite.lazy) {
|
if (openCoWebsite.lazy === undefined || !openCoWebsite.lazy) {
|
||||||
@ -1450,7 +1482,7 @@ export class GameScene extends DirtyScene {
|
|||||||
phaserLayer.setCollisionByProperty({ collides: true }, visible);
|
phaserLayer.setCollisionByProperty({ collides: true }, visible);
|
||||||
} else {
|
} else {
|
||||||
const phaserLayers = this.gameMap.findPhaserLayers(layerName + "/");
|
const phaserLayers = this.gameMap.findPhaserLayers(layerName + "/");
|
||||||
if (phaserLayers === []) {
|
if (phaserLayers.length === 0) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'Could not find layer with name that contains "' +
|
'Could not find layer with name that contains "' +
|
||||||
layerName +
|
layerName +
|
||||||
@ -1463,7 +1495,7 @@ export class GameScene extends DirtyScene {
|
|||||||
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid());
|
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid(), this.gameMap.getWalkingCostGrid());
|
||||||
this.markDirty();
|
this.markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export type EmbedScreen =
|
|||||||
};
|
};
|
||||||
|
|
||||||
function createHighlightedEmbedScreenStore() {
|
function createHighlightedEmbedScreenStore() {
|
||||||
const { subscribe, set, update } = writable<EmbedScreen | null>(null);
|
const { subscribe, set, update } = writable<EmbedScreen | undefined>(undefined);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
@ -23,7 +23,7 @@ function createHighlightedEmbedScreenStore() {
|
|||||||
set(embedScreen);
|
set(embedScreen);
|
||||||
},
|
},
|
||||||
removeHighlight: () => {
|
removeHighlight: () => {
|
||||||
set(null);
|
set(undefined);
|
||||||
},
|
},
|
||||||
toggleHighlight: (embedScreen: EmbedScreen) => {
|
toggleHighlight: (embedScreen: EmbedScreen) => {
|
||||||
update((currentEmbedScreen) =>
|
update((currentEmbedScreen) =>
|
||||||
@ -36,7 +36,7 @@ function createHighlightedEmbedScreenStore() {
|
|||||||
currentEmbedScreen.type === "streamable" &&
|
currentEmbedScreen.type === "streamable" &&
|
||||||
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)
|
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)
|
||||||
? embedScreen
|
? embedScreen
|
||||||
: null
|
: undefined
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,8 @@ import { myCameraVisibilityStore } from "./MyCameraStoreVisibility";
|
|||||||
import { peerStore } from "./PeerStore";
|
import { peerStore } from "./PeerStore";
|
||||||
import { privacyShutdownStore } from "./PrivacyShutdownStore";
|
import { privacyShutdownStore } from "./PrivacyShutdownStore";
|
||||||
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
|
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
|
||||||
|
import { SoundMeter } from "../Phaser/Components/SoundMeter";
|
||||||
|
import { AudioContext } from "standardized-audio-context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store that contains the camera state requested by the user (on or off).
|
* A store that contains the camera state requested by the user (on or off).
|
||||||
@ -541,6 +543,41 @@ export const obtainedMediaConstraintStore = derived<Readable<MediaStreamConstrai
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const localVolumeStore = readable<number | undefined>(undefined, (set) => {
|
||||||
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
|
const unsubscribe = localStreamStore.subscribe((localStreamStoreValue) => {
|
||||||
|
clearInterval(timeout);
|
||||||
|
if (localStreamStoreValue.type === "error") {
|
||||||
|
set(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const mediaStream = localStreamStoreValue.stream;
|
||||||
|
|
||||||
|
if (mediaStream === null || mediaStream.getAudioTracks().length <= 0) {
|
||||||
|
set(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const soundMeter = new SoundMeter(mediaStream);
|
||||||
|
let error = false;
|
||||||
|
|
||||||
|
timeout = setInterval(() => {
|
||||||
|
try {
|
||||||
|
set(soundMeter.getVolume());
|
||||||
|
} catch (err) {
|
||||||
|
if (!error) {
|
||||||
|
console.error(err);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
clearInterval(timeout);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device list
|
* Device list
|
||||||
*/
|
*/
|
||||||
|
@ -8,19 +8,27 @@ export class PathfindingManager {
|
|||||||
private grid: number[][];
|
private grid: number[][];
|
||||||
private tileDimensions: { width: number; height: number };
|
private tileDimensions: { width: number; height: number };
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, collisionsGrid: number[][], tileDimensions: { width: number; height: number }) {
|
constructor(
|
||||||
|
scene: Phaser.Scene,
|
||||||
|
collisionsGrid: number[][],
|
||||||
|
walkingCostGrid: number[][],
|
||||||
|
tileDimensions: { width: number; height: number }
|
||||||
|
) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
||||||
this.easyStar = new EasyStar.js();
|
this.easyStar = new EasyStar.js();
|
||||||
this.easyStar.enableDiagonals();
|
this.easyStar.enableDiagonals();
|
||||||
|
this.easyStar.disableCornerCutting();
|
||||||
|
|
||||||
this.grid = collisionsGrid;
|
this.grid = collisionsGrid;
|
||||||
this.tileDimensions = tileDimensions;
|
this.tileDimensions = tileDimensions;
|
||||||
this.setEasyStarGrid(collisionsGrid);
|
this.setEasyStarGrid(collisionsGrid);
|
||||||
|
this.setWalkingCostGrid(walkingCostGrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCollisionGrid(collisionGrid: number[][]): void {
|
public setCollisionGrid(collisionGrid: number[][], walkingCostGrid: number[][]): void {
|
||||||
this.setEasyStarGrid(collisionGrid);
|
this.setEasyStarGrid(collisionGrid);
|
||||||
|
this.setWalkingCostGrid(walkingCostGrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findPath(
|
public async findPath(
|
||||||
@ -115,6 +123,14 @@ export class PathfindingManager {
|
|||||||
this.easyStar.setAcceptableTiles([0]); // zeroes are walkable
|
this.easyStar.setAcceptableTiles([0]); // zeroes are walkable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setWalkingCostGrid(grid: number[][]): void {
|
||||||
|
for (let y = 0; y < grid.length; y += 1) {
|
||||||
|
for (let x = 0; x < grid[y].length; x += 1) {
|
||||||
|
this.easyStar.setAdditionalPointCost(x, y, grid[y][x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private logGridToTheConsole(grid: number[][]): void {
|
private logGridToTheConsole(grid: number[][]): void {
|
||||||
let rowNumber = 0;
|
let rowNumber = 0;
|
||||||
for (const row of grid) {
|
for (const row of grid) {
|
||||||
|
@ -12,6 +12,7 @@ export interface CoWebsite {
|
|||||||
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined;
|
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined;
|
||||||
getWidthPercent(): number | undefined;
|
getWidthPercent(): number | undefined;
|
||||||
isClosable(): boolean;
|
isClosable(): boolean;
|
||||||
|
getHint(): string;
|
||||||
load(): CancelablePromise<HTMLIFrameElement>;
|
load(): CancelablePromise<HTMLIFrameElement>;
|
||||||
unload(): Promise<void>;
|
unload(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@ export class SimpleCoWebsite implements CoWebsite {
|
|||||||
protected allowPolicy?: string;
|
protected allowPolicy?: string;
|
||||||
protected widthPercent?: number;
|
protected widthPercent?: number;
|
||||||
protected closable: boolean;
|
protected closable: boolean;
|
||||||
|
protected hint: string;
|
||||||
|
|
||||||
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
|
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean, hint?: string) {
|
||||||
this.id = coWebsiteManager.generateUniqueId();
|
this.id = coWebsiteManager.generateUniqueId();
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.state = writable("asleep" as CoWebsiteState);
|
this.state = writable("asleep" as CoWebsiteState);
|
||||||
@ -23,6 +24,7 @@ export class SimpleCoWebsite implements CoWebsite {
|
|||||||
this.allowPolicy = allowPolicy;
|
this.allowPolicy = allowPolicy;
|
||||||
this.widthPercent = widthPercent;
|
this.widthPercent = widthPercent;
|
||||||
this.closable = closable ?? false;
|
this.closable = closable ?? false;
|
||||||
|
this.hint = hint ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
getId(): string {
|
getId(): string {
|
||||||
@ -57,6 +59,10 @@ export class SimpleCoWebsite implements CoWebsite {
|
|||||||
return this.closable;
|
return this.closable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getHint(): string {
|
||||||
|
return this.hint;
|
||||||
|
}
|
||||||
|
|
||||||
load(): CancelablePromise<HTMLIFrameElement> {
|
load(): CancelablePromise<HTMLIFrameElement> {
|
||||||
this.loadIframe = new CancelablePromise((resolve, reject, cancel) => {
|
this.loadIframe = new CancelablePromise((resolve, reject, cancel) => {
|
||||||
this.state.set("loading");
|
this.state.set("loading");
|
||||||
|
@ -159,9 +159,17 @@ class CoWebsiteManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
buttonSwipe.addEventListener("click", () => {
|
buttonSwipe.addEventListener("click", () => {
|
||||||
|
const mainCoWebsite = this.getMainCoWebsite();
|
||||||
const highlightedEmbed = get(highlightedEmbedScreen);
|
const highlightedEmbed = get(highlightedEmbedScreen);
|
||||||
if (highlightedEmbed?.type === "cowebsite") {
|
if (highlightedEmbed?.type === "cowebsite") {
|
||||||
this.goToMain(highlightedEmbed.embed);
|
this.goToMain(highlightedEmbed.embed);
|
||||||
|
|
||||||
|
if (mainCoWebsite) {
|
||||||
|
highlightedEmbedScreen.toggleHighlight({
|
||||||
|
type: "cowebsite",
|
||||||
|
embed: mainCoWebsite,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -553,6 +561,13 @@ class CoWebsiteManager {
|
|||||||
coWebsites.remove(coWebsite);
|
coWebsites.remove(coWebsite);
|
||||||
coWebsites.add(coWebsite, 0);
|
coWebsites.add(coWebsite, 0);
|
||||||
|
|
||||||
|
if (mainCoWebsite) {
|
||||||
|
const iframe = mainCoWebsite.getIframe();
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.display = "block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isMediaBreakpointDown("lg") &&
|
isMediaBreakpointDown("lg") &&
|
||||||
get(embedScreenLayout) === LayoutMode.Presentation &&
|
get(embedScreenLayout) === LayoutMode.Presentation &&
|
||||||
@ -596,12 +611,20 @@ class CoWebsiteManager {
|
|||||||
.load()
|
.load()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const mainCoWebsite = this.getMainCoWebsite();
|
const mainCoWebsite = this.getMainCoWebsite();
|
||||||
if (mainCoWebsite && mainCoWebsite.getId() === coWebsite.getId()) {
|
const highlightedEmbed = get(highlightedEmbedScreen);
|
||||||
this.openMain();
|
if (mainCoWebsite) {
|
||||||
|
if (mainCoWebsite.getId() === coWebsite.getId()) {
|
||||||
|
this.openMain();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
}, animationTime);
|
}, animationTime);
|
||||||
|
} else if (!highlightedEmbed) {
|
||||||
|
highlightedEmbedScreen.toggleHighlight({
|
||||||
|
type: "cowebsite",
|
||||||
|
embed: coWebsite,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
})
|
})
|
||||||
|
@ -10,6 +10,9 @@ import { playersStore } from "../Stores/PlayersStore";
|
|||||||
import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore";
|
import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore";
|
||||||
import { getIceServersConfig } from "../Components/Video/utils";
|
import { getIceServersConfig } from "../Components/Video/utils";
|
||||||
import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
|
import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
|
||||||
|
import { SoundMeter } from "../Phaser/Components/SoundMeter";
|
||||||
|
import { AudioContext } from "standardized-audio-context";
|
||||||
|
import { Console } from "console";
|
||||||
|
|
||||||
const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
|
const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
|
||||||
|
|
||||||
@ -33,6 +36,7 @@ export class VideoPeer extends Peer {
|
|||||||
private onBlockSubscribe: Subscription;
|
private onBlockSubscribe: Subscription;
|
||||||
private onUnBlockSubscribe: Subscription;
|
private onUnBlockSubscribe: Subscription;
|
||||||
public readonly streamStore: Readable<MediaStream | null>;
|
public readonly streamStore: Readable<MediaStream | null>;
|
||||||
|
public readonly volumeStore: Readable<number | undefined>;
|
||||||
public readonly statusStore: Readable<PeerStatus>;
|
public readonly statusStore: Readable<PeerStatus>;
|
||||||
public readonly constraintsStore: Readable<ObtainedMediaStreamConstraints | null>;
|
public readonly constraintsStore: Readable<ObtainedMediaStreamConstraints | null>;
|
||||||
private newMessageSubscribtion: Subscription | undefined;
|
private newMessageSubscribtion: Subscription | undefined;
|
||||||
@ -69,6 +73,34 @@ export class VideoPeer extends Peer {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.volumeStore = readable<number | undefined>(undefined, (set) => {
|
||||||
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
|
const unsubscribe = this.streamStore.subscribe((mediaStream) => {
|
||||||
|
if (mediaStream === null || mediaStream.getAudioTracks().length <= 0) {
|
||||||
|
set(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const soundMeter = new SoundMeter(mediaStream);
|
||||||
|
let error = false;
|
||||||
|
|
||||||
|
timeout = setInterval(() => {
|
||||||
|
try {
|
||||||
|
set(soundMeter.getVolume());
|
||||||
|
} catch (err) {
|
||||||
|
if (!error) {
|
||||||
|
console.error(err);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
clearInterval(timeout);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
this.constraintsStore = readable<ObtainedMediaStreamConstraints | null>(null, (set) => {
|
this.constraintsStore = readable<ObtainedMediaStreamConstraints | null>(null, (set) => {
|
||||||
const onData = (chunk: Buffer) => {
|
const onData = (chunk: Buffer) => {
|
||||||
const message = JSON.parse(chunk.toString("utf8"));
|
const message = JSON.parse(chunk.toString("utf8"));
|
||||||
|
@ -15,6 +15,9 @@ const woka: NonNullable<Translation["woka"]> = {
|
|||||||
continue: "Auswählen",
|
continue: "Auswählen",
|
||||||
customize: "Bearbeite dein Avatar",
|
customize: "Bearbeite dein Avatar",
|
||||||
},
|
},
|
||||||
|
menu: {
|
||||||
|
businessCard: "Visitenkarte",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default woka;
|
export default woka;
|
||||||
|
@ -15,6 +15,9 @@ const woka: BaseTranslation = {
|
|||||||
continue: "Continue",
|
continue: "Continue",
|
||||||
customize: "Customize your WOKA",
|
customize: "Customize your WOKA",
|
||||||
},
|
},
|
||||||
|
menu: {
|
||||||
|
businessCard: "Business Card",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default woka;
|
export default woka;
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
//TextGlobalMessage
|
//TextGlobalMessage
|
||||||
|
|
||||||
|
// TODO: load on demand with TextGlobalMessage component
|
||||||
|
@import "quill/dist/quill.snow.css";
|
||||||
|
|
||||||
section.section-input-send-text {
|
section.section-input-send-text {
|
||||||
--height-toolbar: 20%;
|
--height-toolbar: 20%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -43,6 +43,10 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
|
|
||||||
|
.nes-btn {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
#cowebsite-swipe {
|
#cowebsite-swipe {
|
||||||
display: none;
|
display: none;
|
||||||
img {
|
img {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@import "~@fontsource/press-start-2p/index.css";
|
@import "~@fontsource/press-start-2p/index.css";
|
||||||
|
@import "~@16bits/nes.css/css/nes.min.css";
|
||||||
|
|
||||||
*{
|
*{
|
||||||
font-family: "Press Start 2P",monospace;
|
font-family: "Press Start 2P",monospace;
|
||||||
|
@ -2,7 +2,6 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body button:focus,
|
body button:focus,
|
||||||
body img:focus,
|
body img:focus,
|
||||||
body input:focus {
|
body input:focus {
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@16bits/nes.css@^2.3.2":
|
||||||
|
version "2.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@16bits/nes.css/-/nes.css-2.3.2.tgz#e69db834119b33ae8d3cb044f106a07a17cadd6f"
|
||||||
|
integrity sha512-nEM5PIth+Bab5JSOa4uUR+PMNUsNTYxA55oVlG3gXI/4LoYtWS767Uv9Pu/KCbHXVvnIjt4ZXt13kZw3083qTw==
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
|
||||||
version "7.12.13"
|
version "7.12.13"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
|
||||||
@ -2795,9 +2800,9 @@ focus-trap@^5.1.0:
|
|||||||
xtend "^4.0.1"
|
xtend "^4.0.1"
|
||||||
|
|
||||||
follow-redirects@^1.0.0, follow-redirects@^1.14.0:
|
follow-redirects@^1.0.0, follow-redirects@^1.14.0:
|
||||||
version "1.14.7"
|
version "1.14.8"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
|
||||||
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
|
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
|
||||||
|
|
||||||
for-in@^1.0.2:
|
for-in@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
|
177
maps/tests/PathfinderAvoidExits/map1.json
Normal file
177
maps/tests/PathfinderAvoidExits/map1.json
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":0.9,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"walls",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":8,
|
||||||
|
"name":"exit",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"exitUrl",
|
||||||
|
"type":"string",
|
||||||
|
"value":"map2.json"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":9,
|
||||||
|
"name":"from_exit2",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"startLayer",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":10,
|
||||||
|
"name":"funritures",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":58.0929629319722,
|
||||||
|
"id":2,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"text":"DO NOT fall into the water or you will drown! Use right-click to move",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":207.776169358213,
|
||||||
|
"x":78.9920090369007,
|
||||||
|
"y":34.4126432934483
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":11,
|
||||||
|
"nextobjectid":3,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.2",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"..\/tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"id":16,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":17,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":18,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":19,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
184
maps/tests/PathfinderAvoidExits/map2.json
Normal file
184
maps/tests/PathfinderAvoidExits/map2.json
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"walls",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":8,
|
||||||
|
"name":"exit",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"exitUrl",
|
||||||
|
"type":"string",
|
||||||
|
"value":"map1.json#from_exit2"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":19,
|
||||||
|
"id":2,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"text":"YOU ",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":33.1966362647477,
|
||||||
|
"x":143.254413856581,
|
||||||
|
"y":65.4728056229604
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":39.3497615262321,
|
||||||
|
"id":3,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"MS Shell Dlg 2",
|
||||||
|
"pixelsize":32,
|
||||||
|
"text":"ARE",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":81.3934036147603,
|
||||||
|
"x":130.134191004937,
|
||||||
|
"y":102.423688394277
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":124.497486386076,
|
||||||
|
"id":4,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"color":"#ff0000",
|
||||||
|
"fontfamily":"MS Shell Dlg 2",
|
||||||
|
"pixelsize":96,
|
||||||
|
"text":"DEAD",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":246.869092410677,
|
||||||
|
"x":41.7733861852564,
|
||||||
|
"y":157.582233294285
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":9,
|
||||||
|
"nextobjectid":5,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.2",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"..\/tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"id":16,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":17,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":18,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":19,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
@ -88,6 +88,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="exit1.json" target="_blank">Test exits</a>
|
<a href="#" class="testLink" data-testmap="exit1.json" target="_blank">Test exits</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-pathfinder-avoid-exits"> Success <input type="radio" name="test-pathfinder-avoid-exits"> Failure <input type="radio" name="test-pathfinder-avoid-exits" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="PathfinderAvoidExits/map1.json" target="_blank">Test Pathfinder Avoid Exits</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio" name="test-exitSceneUrl"> Success <input type="radio" name="test-exitSceneUrl"> Failure <input type="radio" name="test-exitSceneUrl" checked> Pending
|
<input type="radio" name="test-exitSceneUrl"> Success <input type="radio" name="test-exitSceneUrl"> Failure <input type="radio" name="test-exitSceneUrl" checked> Pending
|
||||||
|
@ -79,6 +79,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
if (!code && !nonce) {
|
if (!code && !nonce) {
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
return res.end(JSON.stringify({ ...resUserData, authToken: token }));
|
return res.end(JSON.stringify({ ...resUserData, authToken: token }));
|
||||||
}
|
}
|
||||||
console.error("Token cannot to be check on OpenId provider");
|
console.error("Token cannot to be check on OpenId provider");
|
||||||
@ -91,6 +92,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
return res.end(JSON.stringify({ ...resCheckTokenAuth, ...resUserData, username: authTokenData.username, locale: authTokenData.locale, authToken: token }));
|
return res.end(JSON.stringify({ ...resCheckTokenAuth, ...resUserData, username: authTokenData.username, locale: authTokenData.locale, authToken: token }));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.info("User was not connected", err);
|
console.info("User was not connected", err);
|
||||||
@ -113,7 +115,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
if (!sub) {
|
if (!sub) {
|
||||||
throw new Error("No sub in the response");
|
throw new Error("No sub in the response");
|
||||||
}
|
}
|
||||||
const authToken = jwtTokenManager.createAuthToken(sub, userInfo?.access_token, userInfo?.username, userInfo.locale);
|
const authToken = jwtTokenManager.createAuthToken(sub, userInfo?.access_token, userInfo?.username, userInfo?.locale);
|
||||||
|
|
||||||
//Get user data from Admin Back Office
|
//Get user data from Admin Back Office
|
||||||
//This is very important to create User Local in LocalStorage in WorkAdventure
|
//This is very important to create User Local in LocalStorage in WorkAdventure
|
||||||
@ -121,6 +123,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
|
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
return res.end(JSON.stringify({ ...data, authToken, username: userInfo.username, locale: userInfo.locale, userUuid : sub }));
|
return res.end(JSON.stringify({ ...data, authToken, username: userInfo.username, locale: userInfo.locale, userUuid : sub }));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("openIDCallback => ERROR", e);
|
console.error("openIDCallback => ERROR", e);
|
||||||
@ -183,6 +186,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
const authToken = jwtTokenManager.createAuthToken(email || userUuid);
|
const authToken = jwtTokenManager.createAuthToken(email || userUuid);
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
res.end(
|
res.end(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
authToken,
|
authToken,
|
||||||
@ -222,6 +226,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
const authToken = jwtTokenManager.createAuthToken(userUuid);
|
const authToken = jwtTokenManager.createAuthToken(userUuid);
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
res.end(
|
res.end(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
authToken,
|
authToken,
|
||||||
|
@ -48,6 +48,7 @@ export class MapController extends BaseController {
|
|||||||
if (!match) {
|
if (!match) {
|
||||||
res.writeStatus("404 Not Found");
|
res.writeStatus("404 Not Found");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
res.end(JSON.stringify({}));
|
res.end(JSON.stringify({}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -56,6 +57,7 @@ export class MapController extends BaseController {
|
|||||||
|
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
res.end(
|
res.end(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
mapUrl,
|
mapUrl,
|
||||||
@ -107,6 +109,7 @@ export class MapController extends BaseController {
|
|||||||
|
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
|
res.writeHeader("Content-Type", "application/json");
|
||||||
res.end(JSON.stringify(mapDetails));
|
res.end(JSON.stringify(mapDetails));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errorToResponse(e, res);
|
this.errorToResponse(e, res);
|
||||||
|
@ -19,6 +19,9 @@ export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || "";
|
|||||||
export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || "";
|
export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || "";
|
||||||
export const OPID_CLIENT_REDIRECT_URL = process.env.OPID_CLIENT_REDIRECT_URL || FRONT_URL + "/jwt";
|
export const OPID_CLIENT_REDIRECT_URL = process.env.OPID_CLIENT_REDIRECT_URL || FRONT_URL + "/jwt";
|
||||||
export const OPID_PROFILE_SCREEN_PROVIDER = process.env.OPID_PROFILE_SCREEN_PROVIDER || ADMIN_URL + "/profile";
|
export const OPID_PROFILE_SCREEN_PROVIDER = process.env.OPID_PROFILE_SCREEN_PROVIDER || ADMIN_URL + "/profile";
|
||||||
|
export const OPID_ADDITIONAL_SCOPES = process.env.OPID_ADDITIONAL_SCOPES || "";
|
||||||
|
export const OPID_USERNAME_CLAIM = process.env.OPID_USERNAME_CLAIM || "username";
|
||||||
|
export const OPID_LOCALE_CLAIM = process.env.OPID_LOCALE_CLAIM || "locale";
|
||||||
export const DISABLE_ANONYMOUS: boolean = process.env.DISABLE_ANONYMOUS === "true";
|
export const DISABLE_ANONYMOUS: boolean = process.env.DISABLE_ANONYMOUS === "true";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -4,6 +4,9 @@ import {
|
|||||||
OPID_CLIENT_SECRET,
|
OPID_CLIENT_SECRET,
|
||||||
OPID_CLIENT_ISSUER,
|
OPID_CLIENT_ISSUER,
|
||||||
OPID_CLIENT_REDIRECT_URL,
|
OPID_CLIENT_REDIRECT_URL,
|
||||||
|
OPID_ADDITIONAL_SCOPES,
|
||||||
|
OPID_USERNAME_CLAIM,
|
||||||
|
OPID_LOCALE_CLAIM,
|
||||||
} from "../Enum/EnvironmentVariable";
|
} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
class OpenIDClient {
|
class OpenIDClient {
|
||||||
@ -26,7 +29,7 @@ class OpenIDClient {
|
|||||||
public authorizationUrl(state: string, nonce: string, playUri?: string, redirect?: string) {
|
public authorizationUrl(state: string, nonce: string, playUri?: string, redirect?: string) {
|
||||||
return this.initClient().then((client) => {
|
return this.initClient().then((client) => {
|
||||||
return client.authorizationUrl({
|
return client.authorizationUrl({
|
||||||
scope: "openid profile email",
|
scope: "openid email " + OPID_ADDITIONAL_SCOPES,
|
||||||
prompt: "login",
|
prompt: "login",
|
||||||
state: state,
|
state: state,
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
@ -36,7 +39,7 @@ class OpenIDClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string; username: string, locale: string }> {
|
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string; username: string; locale: string }> {
|
||||||
return this.initClient().then((client) => {
|
return this.initClient().then((client) => {
|
||||||
return client.callback(OPID_CLIENT_REDIRECT_URL, { code }, { nonce }).then((tokenSet) => {
|
return client.callback(OPID_CLIENT_REDIRECT_URL, { code }, { nonce }).then((tokenSet) => {
|
||||||
return client.userinfo(tokenSet).then((res) => {
|
return client.userinfo(tokenSet).then((res) => {
|
||||||
@ -45,8 +48,8 @@ class OpenIDClient {
|
|||||||
email: res.email as string,
|
email: res.email as string,
|
||||||
sub: res.sub,
|
sub: res.sub,
|
||||||
access_token: tokenSet.access_token as string,
|
access_token: tokenSet.access_token as string,
|
||||||
username: (res.preferred_username || res.username || res.nickname || res.name || res.email) as string,
|
username: (res[OPID_USERNAME_CLAIM]) as string,
|
||||||
locale: res.locale as string,
|
locale: (res[OPID_LOCALE_CLAIM]) as string,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -950,9 +950,9 @@ flatted@^2.0.0:
|
|||||||
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
|
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
|
||||||
|
|
||||||
follow-redirects@^1.14.0:
|
follow-redirects@^1.14.0:
|
||||||
version "1.14.7"
|
version "1.14.8"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
|
||||||
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
|
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
|
||||||
|
|
||||||
fs-minipass@^2.0.0:
|
fs-minipass@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
|
12
tests/package-lock.json
generated
12
tests/package-lock.json
generated
@ -3182,9 +3182,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.14.7",
|
"version": "1.14.8",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@ -8177,9 +8177,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.14.7",
|
"version": "1.14.8",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
|
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
|
||||||
},
|
},
|
||||||
"fp-ts": {
|
"fp-ts": {
|
||||||
"version": "2.11.8",
|
"version": "2.11.8",
|
||||||
|
Loading…
Reference in New Issue
Block a user