merged develop

This commit is contained in:
Hanusiak Piotr 2022-01-13 10:44:06 +01:00
commit a1c96b0524
178 changed files with 6744 additions and 3541 deletions

View file

@ -34,14 +34,15 @@ module.exports = {
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "error",
"no-throw-literal": "error",
// TODO: remove those ignored rules and write a stronger code!
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/restrict-template-expressions": "off"
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/no-unsafe-argument": "off",
},
"settings": {
"svelte3/typescript": true,

View file

@ -1 +1,2 @@
src/Messages/generated
src/Messages/JsonMessages

View file

@ -1,13 +1,15 @@
FROM node:14.15.4-buster-slim@sha256:cbae886186467bbfd274b82a234a1cdfbbd31201c2a6ee63a6893eefcf3c6e76 as builder
WORKDIR /usr/src
COPY messages .
RUN yarn install && yarn proto
RUN yarn install && yarn ts-proto
# we are rebuilding on each deploy to cope with the PUSHER_URL environment URL
FROM thecodingmachine/nodejs:14-apache
COPY --chown=docker:docker front .
COPY --from=builder --chown=docker:docker /usr/src/generated /var/www/html/src/Messages/generated
COPY --from=builder --chown=docker:docker /usr/src/ts-proto-generated/protos /var/www/html/src/Messages/ts-proto-generated
RUN sed -i 's/import { Observable } from "rxjs";/import type { Observable } from "rxjs";/g' /var/www/html/src/Messages/ts-proto-generated/messages.ts
COPY --from=builder --chown=docker:docker /usr/src/JsonMessages /var/www/html/src/Messages/JsonMessages
# Removing the iframe.html file from the final image as this adds a XSS attack.
# iframe.html is only in dev mode to circumvent a limitation

View file

@ -20,7 +20,7 @@ RewriteBase /
# We only want to let Apache serve files and not directories.
# Rewrite all other queries starting with _ to index.ts.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule "^[_@]/" "/index.html" [L]
RewriteRule "^[_@*]/" "/index.html" [L]
RewriteRule "^register/" "/index.html" [L]
RewriteRule "^login" "/index.html" [L]
RewriteRule "^jwt" "/index.html" [L]

View file

@ -12,12 +12,12 @@
"@types/quill": "^1.3.7",
"@types/uuidv4": "^5.0.0",
"@types/webpack-dev-server": "^3.11.4",
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.23.0",
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0",
"css-loader": "^5.2.4",
"eslint": "^7.26.0",
"eslint": "^8.4.1",
"eslint-plugin-svelte3": "^3.2.1",
"fork-ts-checker-webpack-plugin": "^6.2.9",
"fork-ts-checker-webpack-plugin": "^6.5.0",
"html-webpack-plugin": "^5.3.1",
"jasmine": "^3.5.0",
"lint-staged": "^11.0.0",
@ -32,10 +32,10 @@
"svelte-check": "^2.1.0",
"svelte-loader": "^3.1.1",
"svelte-preprocess": "^4.7.3",
"ts-loader": "^9.1.2",
"ts-node": "^9.1.1",
"ts-loader": "^9.2.6",
"ts-node": "^10.4.0",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.4",
"typescript": "^4.5.3",
"webpack": "^5.37.0",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2"
@ -47,6 +47,7 @@
"@types/socket.io-client": "^1.4.32",
"axios": "^0.21.2",
"cross-env": "^7.0.3",
"deep-copy-ts": "^0.5.0",
"generic-type-guard": "^3.2.0",
"google-protobuf": "^3.13.0",
"phaser": "^3.54.0",
@ -61,6 +62,7 @@
"simple-peer": "^9.11.0",
"socket.io-client": "^2.3.0",
"standardized-audio-context": "^25.2.4",
"ts-proto": "^1.96.0",
"uuidv4": "^6.2.10"
},
"scripts": {

View file

@ -18,64 +18,84 @@ class AnalyticsClient {
}
identifyUser(uuid: string, email: string | null) {
this.posthogPromise?.then((posthog) => {
posthog.identify(uuid, { uuid, email, wa: true });
});
this.posthogPromise
?.then((posthog) => {
posthog.identify(uuid, { uuid, email, wa: true });
})
.catch((e) => console.error(e));
}
loggedWithSso() {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-logged-sso");
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-logged-sso");
})
.catch((e) => console.error(e));
}
loggedWithToken() {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-logged-token");
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-logged-token");
})
.catch((e) => console.error(e));
}
enteredRoom(roomId: string, roomGroup: string | null) {
this.posthogPromise?.then((posthog) => {
posthog.capture("$pageView", { roomId, roomGroup });
posthog.capture("enteredRoom");
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("$pageView", { roomId, roomGroup });
posthog.capture("enteredRoom");
})
.catch((e) => console.error(e));
}
openedMenu() {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-opened-menu");
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-opened-menu");
})
.catch((e) => console.error(e));
}
launchEmote(emote: string) {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-emote-launch", { emote });
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-emote-launch", { emote });
})
.catch((e) => console.error(e));
}
enteredJitsi(roomName: string, roomId: string) {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-entered-jitsi", { roomName, roomId });
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-entered-jitsi", { roomName, roomId });
})
.catch((e) => console.error(e));
}
validationName() {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-name-validation");
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-name-validation");
})
.catch((e) => console.error(e));
}
validationWoka(scene: string) {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-woka-validation", { scene });
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-woka-validation", { scene });
})
.catch((e) => console.error(e));
}
validationVideo() {
this.posthogPromise?.then((posthog) => {
posthog.capture("wa-video-validation");
});
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-video-validation");
})
.catch((e) => console.error(e));
}
}
export const analyticsClient = new AnalyticsClient();

View file

@ -1,27 +1,22 @@
import { AdminMessageEventTypes, adminMessagesService } from "../Connexion/AdminMessagesService";
import { textMessageContentStore, textMessageVisibleStore } from "../Stores/TypeMessageStore/TextMessageStore";
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
import { UPLOADER_URL } from "../Enum/EnvironmentVariable";
import { banMessageContentStore, banMessageVisibleStore } from "../Stores/TypeMessageStore/BanMessageStore";
import { banMessageStore } from "../Stores/TypeMessageStore/BanMessageStore";
class UserMessageManager {
receiveBannedMessageListener!: Function;
constructor() {
adminMessagesService.messageStream.subscribe((event) => {
textMessageVisibleStore.set(false);
banMessageVisibleStore.set(false);
if (event.type === AdminMessageEventTypes.admin) {
textMessageContentStore.set(event.text);
textMessageVisibleStore.set(true);
textMessageStore.addMessage(event.text);
} else if (event.type === AdminMessageEventTypes.audio) {
soundPlayingStore.playSound(UPLOADER_URL + event.text);
} else if (event.type === AdminMessageEventTypes.ban) {
banMessageContentStore.set(event.text);
banMessageVisibleStore.set(true);
banMessageStore.addMessage(event.text);
} else if (event.type === AdminMessageEventTypes.banned) {
banMessageContentStore.set(event.text);
banMessageVisibleStore.set(true);
banMessageStore.addMessage(event.text);
this.receiveBannedMessageListener();
}
});

View file

@ -0,0 +1,13 @@
import * as tg from "generic-type-guard";
export const isColorEvent = new tg.IsInterface()
.withProperties({
red: tg.isNumber,
green: tg.isNumber,
blue: tg.isNumber,
})
.get();
/**
* A message sent from the iFrame to the game to dynamically set the outline of the player.
*/
export type ColorEvent = tg.GuardedType<typeof isColorEvent>;

View file

@ -34,6 +34,7 @@ import type { ChangeZoneEvent } from "./ChangeZoneEvent";
import type { CameraSetPositionEvent } from "./CameraSetPositionEvent";
import type { CameraFocusOnEvent } from "./CameraFocusOnEvent";
import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
import { isColorEvent } from "./ColorEvent";
export interface TypedMessageEvent<T> extends MessageEvent {
data: T;
@ -162,6 +163,14 @@ export const iframeQueryMapTypeGuards = {
query: isCreateEmbeddedWebsiteEvent,
answer: tg.isUndefined,
},
setPlayerOutline: {
query: isColorEvent,
answer: tg.isUndefined,
},
removePlayerOutline: {
query: tg.isUndefined,
answer: tg.isUndefined,
},
getPlayerPosition: {
query: tg.isUndefined,
answer: isPlayerPosition,

View file

@ -26,7 +26,7 @@ export class ActionMessage {
this.message = actionMessageOptions.message;
this.type = actionMessageOptions.type ?? "message";
this.callback = actionMessageOptions.callback;
this.create();
this.create().catch((e) => console.error(e));
}
private async create() {

View file

@ -1,6 +1,6 @@
import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution";
import { Subject } from "rxjs";
import type { WasCameraUpdatedEvent, WasCameraUpdatedEventCallback } from "../Events/WasCameraUpdatedEvent";
import type { WasCameraUpdatedEvent } from "../Events/WasCameraUpdatedEvent";
import { apiCallback } from "./registeredCallbacks";
import { isWasCameraUpdatedEvent } from "../Events/WasCameraUpdatedEvent";
@ -38,12 +38,12 @@ export class WorkAdventureCameraCommands extends IframeApiContribution<WorkAdven
});
}
onCameraUpdate(callback: WasCameraUpdatedEventCallback): void {
moveStream.subscribe(callback);
onCameraUpdate(): Subject<WasCameraUpdatedEvent> {
sendToWorkadventure({
type: "onCameraUpdate",
data: null,
});
return moveStream;
}
}

View file

@ -92,6 +92,24 @@ export class WorkadventurePlayerCommands extends IframeApiContribution<Workadven
}
return userRoomToken;
}
public setOutlineColor(red: number, green: number, blue: number): Promise<void> {
return queryWorkadventure({
type: "setPlayerOutline",
data: {
red,
green,
blue,
},
});
}
public removeOutlineColor(): Promise<void> {
return queryWorkadventure({
type: "removePlayerOutline",
data: undefined,
});
}
}
export type Position = {

View file

@ -95,7 +95,7 @@ export function createState(target: "global" | "player"): WorkadventureStateComm
set(target: WorkadventureStateCommands, p: PropertyKey, value: unknown, receiver: unknown): boolean {
// Note: when using "set", there is no way to wait, so we ignore the return of the promise.
// User must use WA.state.saveVariable to have error message.
target.saveVariable(p.toString(), value);
target.saveVariable(p.toString(), value).catch((e) => console.error(e));
return true;
},
has(target: WorkadventureStateCommands, p: PropertyKey): boolean {

View file

@ -23,6 +23,9 @@
import { chatVisibilityStore } from "../Stores/ChatStore";
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore";
import LimitRoomModal from "./Modal/LimitRoomModal.svelte";
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
import AudioPlaying from "./UI/AudioPlaying.svelte";
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
import ErrorDialog from "./UI/ErrorDialog.svelte";
@ -30,10 +33,10 @@
import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte";
import VideoOverlay from "./Video/VideoOverlay.svelte";
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
import AdminMessage from "./TypeMessage/BanMessage.svelte";
import TextMessage from "./TypeMessage/TextMessage.svelte";
import { banMessageVisibleStore } from "../Stores/TypeMessageStore/BanMessageStore";
import { textMessageVisibleStore } from "../Stores/TypeMessageStore/TextMessageStore";
import BanMessageContainer from "./TypeMessage/BanMessageContainer.svelte";
import TextMessageContainer from "./TypeMessage/TextMessageContainer.svelte";
import { banMessageStore } from "../Stores/TypeMessageStore/BanMessageStore";
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
import { warningContainerStore } from "../Stores/MenuStore";
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
import { layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
@ -42,6 +45,9 @@
import AudioManager from "./AudioManager/AudioManager.svelte";
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
import { followStateStore } from "../Stores/FollowStore";
import { peerStore } from "../Stores/PeerStore";
import FollowMenu from "./FollowMenu/FollowMenu.svelte";
export let game: Game;
</script>
@ -72,14 +78,13 @@
<EnableCameraScene {game} />
</div>
{/if}
{#if $banMessageVisibleStore}
{#if $banMessageStore.length > 0}
<div>
<AdminMessage />
<BanMessageContainer />
</div>
{/if}
{#if $textMessageVisibleStore}
{:else if $textMessageStore.length > 0}
<div>
<TextMessage />
<TextMessageContainer />
</div>
{/if}
{#if $soundPlayingStore}
@ -102,6 +107,11 @@
<ReportMenu />
</div>
{/if}
{#if $followStateStore !== "off" || $peerStore.size > 0}
<div>
<FollowMenu />
</div>
{/if}
{#if $menuIconVisiblilityStore}
<div>
<MenuIcon />
@ -129,6 +139,16 @@
<HelpCameraSettingsPopup />
</div>
{/if}
{#if $showLimitRoomModalStore}
<div>
<LimitRoomModal />
</div>
{/if}
{#if $showShareLinkMapModalStore}
<div>
<ShareLinkMapModal />
</div>
{/if}
{#if $requestVisitCardsStore}
<VisitCard visitCardUrl={$requestVisitCardsStore} />
{/if}

View file

@ -19,12 +19,13 @@
audioManagerVolumeStore.setVolume(volume);
audioManagerVolumeStore.setMuted(localUserStore.getAudioPlayerMuted());
unsubscriberFileStore = audioManagerFileStore.subscribe(() => {
unsubscriberFileStore = audioManagerFileStore.subscribe((src) => {
HTMLAudioPlayer.pause();
HTMLAudioPlayer.src = src;
HTMLAudioPlayer.loop = get(audioManagerVolumeStore).loop;
HTMLAudioPlayer.volume = get(audioManagerVolumeStore).volume;
HTMLAudioPlayer.muted = get(audioManagerVolumeStore).muted;
HTMLAudioPlayer.play();
void HTMLAudioPlayer.play();
});
unsubscriberVolumeStore = audioManagerVolumeStore.subscribe((audioManager: audioManagerVolume) => {
const reduceVolume = audioManager.talking && audioManager.decreaseWhileTalking;
@ -148,9 +149,7 @@
</label>
<section class="audio-manager-file">
<!-- svelte-ignore a11y-media-has-caption -->
<audio class="audio-manager-audioplayer" bind:this={HTMLAudioPlayer}>
<source src={$audioManagerFileStore} />
</audio>
<audio class="audio-manager-audioplayer" bind:this={HTMLAudioPlayer} />
</section>
</div>
</div>

View file

@ -67,6 +67,7 @@
.messagePart {
flex-grow: 1;
max-width: 100%;
user-select: text;
span.date {
font-size: 80%;

View file

@ -0,0 +1,197 @@
<!--
vim: ft=typescript
-->
<script lang="ts">
import { gameManager } from "../../Phaser/Game/GameManager";
import followImg from "../images/follow.svg";
import { followStateStore, followRoleStore, followUsersStore } from "../../Stores/FollowStore";
const gameScene = gameManager.getCurrentGameScene();
function name(userId: number): string | undefined {
return gameScene.MapPlayersByKey.get(userId)?.PlayerValue;
}
function sendFollowRequest() {
gameScene.CurrentPlayer.sendFollowRequest();
}
function acceptFollowRequest() {
gameScene.CurrentPlayer.startFollowing();
}
function abortEnding() {
followStateStore.set("active");
}
function reset() {
gameScene.connection?.emitFollowAbort();
followUsersStore.stopFollowing();
}
function onKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") {
reset();
}
}
</script>
<svelte:window on:keydown={onKeyDown} />
{#if $followStateStore === "requesting" && $followRoleStore === "follower"}
<div class="interact-menu nes-container is-rounded">
<section class="interact-menu-title">
<h2>Do you want to follow {name($followUsersStore[0])}?</h2>
</section>
<section class="interact-menu-action">
<button type="button" class="nes-btn is-success" on:click|preventDefault={acceptFollowRequest}>Yes</button>
<button type="button" class="nes-btn is-error" on:click|preventDefault={reset}>No</button>
</section>
</div>
{/if}
{#if $followStateStore === "ending"}
<div class="interact-menu nes-container is-rounded">
<section class="interact-menu-title">
<h2>Interaction</h2>
</section>
{#if $followRoleStore === "follower"}
<section class="interact-menu-question">
<p>Do you want to stop following {name($followUsersStore[0])}?</p>
</section>
{:else if $followRoleStore === "leader"}
<section class="interact-menu-question">
<p>Do you want to stop leading the way?</p>
</section>
{/if}
<section class="interact-menu-action">
<button type="button" class="nes-btn is-success" on:click|preventDefault={reset}>Yes</button>
<button type="button" class="nes-btn is-error" on:click|preventDefault={abortEnding}>No</button>
</section>
</div>
{/if}
{#if $followStateStore === "active" || $followStateStore === "ending"}
<div class="interact-status nes-container is-rounded">
<section class="interact-status">
{#if $followRoleStore === "follower"}
<p>Following {name($followUsersStore[0])}</p>
{:else if $followUsersStore.length === 0}
<p>Waiting for followers' confirmation</p>
{:else if $followUsersStore.length === 1}
<p>{name($followUsersStore[0])} is following you</p>
{:else if $followUsersStore.length === 2}
<p>{name($followUsersStore[0])} and {name($followUsersStore[1])} are following you</p>
{:else}
<p>
{$followUsersStore.slice(0, -1).map(name).join(", ")} and {name(
$followUsersStore[$followUsersStore.length - 1]
)} are following you
</p>
{/if}
</section>
</div>
{/if}
{#if $followStateStore === "off"}
<button
type="button"
class="nes-btn is-primary follow-menu-button"
on:click|preventDefault={sendFollowRequest}
title="Ask others to follow"><img class="background-img" src={followImg} alt="" /></button
>
{/if}
{#if $followStateStore === "active" || $followStateStore === "ending"}
{#if $followRoleStore === "follower"}
<button
type="button"
class="nes-btn is-error follow-menu-button"
on:click|preventDefault={reset}
title="Stop following"><img class="background-img" src={followImg} alt="" /></button
>
{:else}
<button
type="button"
class="nes-btn is-error follow-menu-button"
on:click|preventDefault={reset}
title="Stop leading the way"><img class="background-img" src={followImg} alt="" /></button
>
{/if}
{/if}
<style lang="scss">
.nes-container {
padding: 5px;
}
div.interact-status {
background-color: #333333;
color: whitesmoke;
position: relative;
height: 2.7em;
width: 40vw;
top: 87vh;
margin: auto;
text-align: center;
}
div.interact-menu {
pointer-events: auto;
background-color: #333333;
color: whitesmoke;
position: relative;
width: 60vw;
top: 60vh;
margin: auto;
section.interact-menu-title {
margin-bottom: 20px;
display: flex;
justify-content: center;
}
section.interact-menu-question {
margin: 4px;
margin-bottom: 20px;
p {
font-size: 1.05em;
font-weight: bold;
}
}
section.interact-menu-action {
display: grid;
grid-gap: 10%;
grid-template-columns: 45% 45%;
margin-bottom: 20px;
margin-left: 5%;
margin-right: 5%;
}
}
.follow-menu-button {
position: absolute;
bottom: 10px;
left: 10px;
pointer-events: all;
}
@media only screen and (max-width: 800px) {
div.interact-status {
width: 100vw;
top: 78vh;
font-size: 0.75em;
}
div.interact-menu {
height: 21vh;
width: 100vw;
font-size: 0.75em;
}
}
</style>

View file

@ -6,11 +6,14 @@
let expandedMapCopyright = false;
let expandedTilesetCopyright = false;
let expandedAudioCopyright = false;
let mapName: string = "";
let mapLink: string = "";
let mapDescription: string = "";
let mapCopyright: string = "The map creator did not declare a copyright for the map.";
let tilesetCopyright: string[] = [];
let audioCopyright: string[] = [];
onMount(() => {
if (gameScene.mapFile.properties !== undefined) {
@ -18,6 +21,10 @@
if (propertyName !== undefined && typeof propertyName.value === "string") {
mapName = propertyName.value;
}
const propertyLink = gameScene.mapFile.properties.find((property) => property.name === "mapLink");
if (propertyLink !== undefined && typeof propertyLink.value === "string") {
mapLink = propertyLink.value;
}
const propertyDescription = gameScene.mapFile.properties.find(
(property) => property.name === "mapDescription"
);
@ -36,7 +43,18 @@
(property) => property.name === "tilesetCopyright"
);
if (propertyTilesetCopyright !== undefined && typeof propertyTilesetCopyright.value === "string") {
tilesetCopyright = [...tilesetCopyright, propertyTilesetCopyright.value]; //Assignment needed to trigger Svelte's reactivity
// Assignment needed to trigger Svelte's reactivity
tilesetCopyright = [...tilesetCopyright, propertyTilesetCopyright.value];
}
}
}
for (const layer of gameScene.mapFile.layers) {
if (layer.type && layer.type === "tilelayer" && layer.properties) {
const propertyAudioCopyright = layer.properties.find((property) => property.name === "audioCopyright");
if (propertyAudioCopyright !== undefined && typeof propertyAudioCopyright.value === "string") {
// Assignment needed to trigger Svelte's reactivity
audioCopyright = [...audioCopyright, propertyAudioCopyright.value];
}
}
}
@ -48,6 +66,9 @@
<section class="container-overflow">
<h3>{mapName}</h3>
<p class="string-HTML">{mapDescription}</p>
{#if mapLink}
<p class="string-HTML">&gt; <a href={mapLink} target="_blank">link to this map</a> &lt;</p>
{/if}
<h3 class="nes-pointer hoverable" on:click={() => (expandedMapCopyright = !expandedMapCopyright)}>
Copyrights of the map
</h3>
@ -60,8 +81,21 @@
<p class="string-HTML">{copyright}</p>
{:else}
<p>
The map creator did not declare a copyright for the tilesets. Warning, This doesn't mean that those
tilesets have no license.
The map creator did not declare a copyright for the tilesets. This doesn't mean that those tilesets
have no license.
</p>
{/each}
</section>
<h3 class="nes-pointer hoverable" on:click={() => (expandedAudioCopyright = !expandedAudioCopyright)}>
Copyrights of audio files
</h3>
<section hidden={!expandedAudioCopyright}>
{#each audioCopyright as copyright}
<p class="string-HTML">{copyright}</p>
{:else}
<p>
The map creator did not declare a copyright for audio files. This doesn't mean that those tilesets
have no license.
</p>
{/each}
</section>

View file

@ -26,7 +26,7 @@
const selectedFile = inputAudio.files ? inputAudio.files[0] : null;
if (!selectedFile) {
errorFile = true;
throw "no file selected";
throw new Error("no file selected");
}
const fd = new FormData();

View file

@ -19,12 +19,12 @@
uploadAudioActive = true;
}
function send() {
async function send(): Promise<void> {
if (inputSendTextActive) {
handleSendText.sendTextMessage(broadcastToWorld);
return handleSendText.sendTextMessage(broadcastToWorld);
}
if (uploadAudioActive) {
handleSendAudio.sendAudioMessage(broadcastToWorld);
return handleSendAudio.sendAudioMessage(broadcastToWorld);
}
}
</script>

View file

@ -21,12 +21,12 @@
<div class="guest-main">
<section class="container-overflow">
<section class="share-url not-mobile">
<h3>Share the link of the room !</h3>
<h3>Share the link of the room!</h3>
<input type="text" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
</section>
<section class="is-mobile">
<h3>Share the link of the room !</h3>
<h3>Share the link of the room!</h3>
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
</section>

View file

@ -76,7 +76,7 @@
break;
}
}
} else throw "There is no menu called " + menu;
} else throw new Error("There is no menu called " + menu);
}
function closeMenu() {

View file

@ -1,9 +1,14 @@
<script lang="typescript">
import logoTalk from "../images/logo-message-pixel.png";
import logoWA from "../images/logo-WA-pixel.png";
import logoInvite from "../images/logo-invite-pixel.png";
import logoRegister from "../images/logo-register-pixel.png";
import { menuVisiblilityStore } from "../../Stores/MenuStore";
import { chatVisibilityStore } from "../../Stores/ChatStore";
import { limitMapStore } from "../../Stores/GameStore";
import { get } from "svelte/store";
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
import { showShareLinkMapModalStore } from "../../Stores/ModalStore";
function showMenu() {
menuVisiblilityStore.set(!get(menuVisiblilityStore));
@ -11,13 +16,25 @@
function showChat() {
chatVisibilityStore.set(true);
}
function register() {
window.open(`${ADMIN_URL}/second-step-register`, "_self");
}
function showInvite() {
showShareLinkMapModalStore.set(true);
}
</script>
<svelte:window />
<main class="menuIcon">
<img src={logoWA} alt="open menu" class="nes-pointer" on:click|preventDefault={showMenu} />
<img src={logoTalk} alt="open menu" class="nes-pointer" on:click|preventDefault={showChat} />
{#if $limitMapStore}
<img src={logoInvite} alt="open menu" class="nes-pointer" on:click|preventDefault={showInvite} />
<img src={logoRegister} alt="open menu" class="nes-pointer" on:click|preventDefault={register} />
{:else}
<img src={logoWA} alt="open menu" class="nes-pointer" on:click|preventDefault={showMenu} />
<img src={logoTalk} alt="open menu" class="nes-pointer" on:click|preventDefault={showChat} />
{/if}
</main>
<style lang="scss">

View file

@ -41,10 +41,10 @@
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
}
function logOut() {
async function logOut() {
disableMenuStores();
loginSceneVisibleStore.set(true);
connectionManager.logout();
return connectionManager.logout();
}
function getProfileUrl() {

View file

@ -8,6 +8,7 @@
let fullscreen: boolean = localUserStore.getFullscreen();
let notification: boolean = localUserStore.getNotification() === "granted";
let forceCowebsiteTrigger: boolean = localUserStore.getForceCowebsiteTrigger();
let ignoreFollowRequests: boolean = localUserStore.getIgnoreFollowRequests();
let valueGame: number = localUserStore.getGameQualityValue();
let valueVideo: number = localUserStore.getVideoQualityValue();
let previewValueGame = valueGame;
@ -32,9 +33,9 @@
const body = HtmlUtils.querySelectorOrFail("body");
if (body) {
if (document.fullscreenElement !== null && !fullscreen) {
document.exitFullscreen();
document.exitFullscreen().catch((e) => console.error(e));
} else {
body.requestFullscreen();
body.requestFullscreen().catch((e) => console.error(e));
}
localUserStore.setFullscreen(fullscreen);
}
@ -44,14 +45,16 @@
if (Notification.permission === "granted") {
localUserStore.setNotification(notification ? "granted" : "denied");
} else {
Notification.requestPermission().then((response) => {
if (response === "granted") {
localUserStore.setNotification(notification ? "granted" : "denied");
} else {
localUserStore.setNotification("denied");
notification = false;
}
});
Notification.requestPermission()
.then((response) => {
if (response === "granted") {
localUserStore.setNotification(notification ? "granted" : "denied");
} else {
localUserStore.setNotification("denied");
notification = false;
}
})
.catch((e) => console.error(e));
}
}
@ -59,6 +62,10 @@
localUserStore.setForceCowebsiteTrigger(forceCowebsiteTrigger);
}
function changeIgnoreFollowRequests() {
localUserStore.setIgnoreFollowRequests(ignoreFollowRequests);
}
function closeMenu() {
menuVisiblilityStore.set(false);
}
@ -123,6 +130,15 @@
/>
<span>Always ask before opening websites and Jitsi Meet rooms</span>
</label>
<label>
<input
type="checkbox"
class="nes-checkbox is-dark"
bind:checked={ignoreFollowRequests}
on:change={changeIgnoreFollowRequests}
/>
<span>Ignore requests to follow other users</span>
</label>
</section>
</div>

View file

@ -0,0 +1,47 @@
<script lang="typescript">
import { fly } from "svelte/transition";
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
function register() {
window.open(`${ADMIN_URL}/second-step-register`, "_self");
}
</script>
<div class="limit-map nes-container" transition:fly={{ y: -900, duration: 500 }}>
<section>
<h2>Limit of your room</h2>
<p>Register your account!</p>
<p>
This map is limited in the time and to continue to use WorkAdventure, you must register your account in our
back office.
</p>
</section>
<section>
<button class="nes-btn is-primary" on:click|preventDefault={register}>Register</button>
</section>
</div>
<style lang="scss">
.limit-map {
pointer-events: auto;
background: #eceeee;
margin-left: auto;
margin-right: auto;
margin-top: 10vh;
max-height: 80vh;
max-width: 80vw;
overflow: auto;
text-align: center;
h2 {
font-family: "Press Start 2P";
}
section {
p {
margin: 15px;
font-family: "Press Start 2P";
}
}
}
</style>

View file

@ -0,0 +1,90 @@
<script lang="typescript">
import { fly } from "svelte/transition";
import { showShareLinkMapModalStore } from "../../Stores/ModalStore";
interface ExtNavigator extends Navigator {
canShare?(data?: ShareData): Promise<boolean>;
}
const myNavigator: ExtNavigator = window.navigator;
const haveNavigatorSharingFeature: boolean =
myNavigator && myNavigator.canShare != null && myNavigator.share != null;
let copied: boolean = false;
function copyLink() {
try {
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
input.focus();
input.select();
document.execCommand("copy");
copied = true;
} catch (e) {
console.error(e);
copied = false;
}
}
async function shareLink() {
const shareData = { url: location.toString() };
try {
await myNavigator.share(shareData);
} catch (err) {
console.error("Error: " + err);
copyLink();
}
}
function close() {
showShareLinkMapModalStore.set(false);
copied = false;
}
</script>
<div class="share-link-map nes-container" transition:fly={{ y: -900, duration: 500 }}>
<section>
<h2>Invite your friends or colleagues</h2>
<p>Share the link of the room!</p>
</section>
<section>
{#if haveNavigatorSharingFeature}
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
{:else}
<input type="text" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
{/if}
{#if copied}
<p>Copied!</p>
{/if}
</section>
<section>
<button class="nes-btn" on:click|preventDefault={close}>Close</button>
</section>
</div>
<style lang="scss">
div.share-link-map {
pointer-events: auto;
background: #eceeee;
margin-left: auto;
margin-right: auto;
margin-top: 10vh;
max-height: 80vh;
max-width: 80vw;
overflow: auto;
text-align: center;
h2 {
font-family: "Press Start 2P";
}
section {
p {
margin: 15px;
font-family: "Press Start 2P";
}
}
}
</style>

View file

@ -6,12 +6,11 @@
import type { Unsubscriber } from "svelte/store";
import { playersStore } from "../../Stores/PlayersStore";
import { connectionManager } from "../../Connexion/ConnectionManager";
import { GameConnexionTypes } from "../../Url/UrlManager";
import { get } from "svelte/store";
let blockActive = true;
let reportActive = !blockActive;
let anonymous: boolean = false;
let disableReport: boolean = false;
let userUUID: string | undefined = playersStore.getPlayerById(get(showReportScreenStore).userId)?.userUuid;
let userName = "No name";
let unsubscriber: Unsubscriber;
@ -26,7 +25,7 @@
}
}
});
anonymous = connectionManager.getConnexionType === GameConnexionTypes.anonymous;
disableReport = !connectionManager.currentRoom?.canReport ?? true;
});
onDestroy(() => {
@ -65,7 +64,7 @@
<button type="button" class="nes-btn" on:click|preventDefault={close}>X</button>
</section>
</section>
<section class="report-menu-action {anonymous ? 'hidden' : ''}">
<section class="report-menu-action {disableReport ? 'hidden' : ''}">
<section class="justify-center">
<button
type="button"

View file

@ -1,9 +1,11 @@
<script lang="ts">
import { fly } from "svelte/transition";
import { banMessageVisibleStore, banMessageContentStore } from "../../Stores/TypeMessageStore/BanMessageStore";
import { fly, fade } from "svelte/transition";
import { onMount } from "svelte";
import type { Message } from "../../Stores/TypeMessageStore/MessageStore";
import { banMessageStore } from "../../Stores/TypeMessageStore/BanMessageStore";
export let message: Message;
const text = $banMessageContentStore;
const NAME_BUTTON = "Ok";
let nbSeconds = 10;
let nameButton = "";
@ -25,17 +27,21 @@
}
function closeBanMessage() {
banMessageVisibleStore.set(false);
banMessageStore.clearMessageById(message.id);
}
</script>
<div class="main-ban-message nes-container is-rounded" transition:fly={{ y: -1000, duration: 500 }}>
<div
class="main-ban-message nes-container is-rounded"
in:fly={{ y: -1000, duration: 500, delay: 250 }}
out:fade={{ duration: 200 }}
>
<h2 class="title-ban-message">
<img src="resources/logos/report.svg" alt="***" /> Important message
<img src="resources/logos/report.svg" alt="***" />
</h2>
<div class="content-ban-message">
<p>{text}</p>
<p>{message.text}</p>
</div>
<div class="footer-ban-message">
<button

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { flip } from "svelte/animate";
import { banMessageStore } from "../../Stores/TypeMessageStore/BanMessageStore";
import BanMessage from "./BanMessage.svelte";
</script>
<div class="main-ban-message-container">
{#each $banMessageStore.slice(0, 1) as message (message.id)}
<div animate:flip={{ duration: 250 }}>
<BanMessage {message} />
</div>
{/each}
</div>

View file

@ -1,14 +1,17 @@
<script lang="ts">
import { fly } from "svelte/transition";
import { textMessageContentStore, textMessageVisibleStore } from "../../Stores/TypeMessageStore/TextMessageStore";
import { fly, fade } from "svelte/transition";
import { QuillDeltaToHtmlConverter } from "quill-delta-to-html";
import type { Message } from "../../Stores/TypeMessageStore/MessageStore";
import { textMessageStore } from "../../Stores/TypeMessageStore/TextMessageStore";
const content = JSON.parse($textMessageContentStore);
export let message: Message;
const content = JSON.parse(message.text);
const converter = new QuillDeltaToHtmlConverter(content.ops, { inlineStyles: true });
const NAME_BUTTON = "Ok";
function closeTextMessage() {
textMessageVisibleStore.set(false);
textMessageStore.clearMessageById(message.id);
}
function onKeyDown(e: KeyboardEvent) {
@ -20,7 +23,11 @@
<svelte:window on:keydown={onKeyDown} />
<div class="main-text-message nes-container is-rounded" transition:fly={{ x: -1000, duration: 500 }}>
<div
class="main-text-message nes-container is-rounded"
in:fly={{ x: -1000, duration: 500, delay: 250 }}
out:fade={{ duration: 250 }}
>
<div class="content-text-message">
{@html converter.convert()}
</div>
@ -40,6 +47,8 @@
width: 80vw;
margin-right: auto;
margin-left: auto;
margin-bottom: 16px;
margin-top: 0;
padding-bottom: 0;
pointer-events: auto;

View file

@ -0,0 +1,21 @@
<script lang="ts">
import { flip } from "svelte/animate";
import TextMessage from "./TextMessage.svelte";
import { textMessageStore } from "../../Stores/TypeMessageStore/TextMessageStore";
const MAX_MESSAGES = 3;
</script>
<div class="main-text-message-container">
{#each $textMessageStore.slice(0, MAX_MESSAGES) as message (message.id)}
<div animate:flip={{ duration: 250 }}>
<TextMessage {message} />
</div>
{/each}
</div>
<style lang="scss">
div.main-text-message-container {
padding-top: 16px;
}
</style>

View file

@ -12,7 +12,7 @@
}
afterUpdate(() => {
audio.play();
audio.play().catch((e) => console.error(e));
});
</script>

View file

@ -1,20 +1,26 @@
<script lang="typescript">
import { fly } from "svelte/transition";
import { userIsAdminStore } from "../../Stores/GameStore";
import { userIsAdminStore, limitMapStore } from "../../Stores/GameStore";
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
const upgradeLink = ADMIN_URL + "/pricing";
const registerLink = ADMIN_URL + "/second-step-register";
</script>
<main class="warningMain" transition:fly={{ y: -200, duration: 500 }}>
<h2>Warning!</h2>
{#if $userIsAdminStore}
<h2>Warning!</h2>
<p>
This world is close to its limit!. You can upgrade its capacity <a href={upgradeLink} target="_blank"
>here</a
>
</p>
{:else if $limitMapStore}
<p>
This map is available for 2 days. You can register your domain <a href={registerLink}>here</a>!
</p>
{:else}
<h2>Warning!</h2>
<p>This world is close to its limit!</p>
{/if}
</main>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><rect fill="none" height="24" width="24"/><path d="M9.5,5.5c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S8.4,5.5,9.5,5.5z M5.75,8.9L3,23h2.1l1.75-8L9,17v6h2v-7.55L8.95,13.4 l0.6-3C10.85,12,12.8,13,15,13v-2c-1.85,0-3.45-1-4.35-2.45L9.7,6.95C9.35,6.35,8.7,6,8,6C7.75,6,7.5,6.05,7.25,6.15L2,8.3V13h2 V9.65L5.75,8.9 M13,2v7h3.75v14h1.5V9H22V2H13z M18.01,8V6.25H14.5v-1.5h3.51V3l2.49,2.5L18.01,8z"/></svg>

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 B

View file

@ -1,5 +1,5 @@
import { Subject } from "rxjs";
import type { BanUserMessage, SendUserMessage } from "../Messages/generated/messages_pb";
import type { BanUserMessage, SendUserMessage } from "../Messages/ts-proto-generated/messages";
export enum AdminMessageEventTypes {
admin = "message",
@ -26,8 +26,8 @@ class AdminMessagesService {
onSendusermessage(message: SendUserMessage | BanUserMessage) {
this._messageStream.next({
type: message.getType() as unknown as AdminMessageEventTypes,
text: message.getMessage(),
type: message.type as unknown as AdminMessageEventTypes,
text: message.message,
});
}
}

View file

@ -1,5 +1,5 @@
import Axios from "axios";
import { PUSHER_URL, START_ROOM_URL } from "../Enum/EnvironmentVariable";
import { PUSHER_URL } from "../Enum/EnvironmentVariable";
import { RoomConnection } from "./RoomConnection";
import type { OnConnectInterface, PositionInterface, ViewportInterface } from "./ConnexionModels";
import { GameConnexionTypes, urlManager } from "../Url/UrlManager";
@ -8,9 +8,14 @@ import { CharacterTexture, LocalUser } from "./LocalUser";
import { Room } from "./Room";
import { _ServiceWorker } from "../Network/ServiceWorker";
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
import { userIsConnected } from "../Stores/MenuStore";
import { userIsConnected, warningContainerStore } from "../Stores/MenuStore";
import { analyticsClient } from "../Administration/AnalyticsClient";
import { axiosWithRetry } from "./AxiosUtils";
import axios from "axios";
import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
import { limitMapStore } from "../Stores/GameStore";
import { showLimitRoomModalStore } from "../Stores/ModalStore";
class ConnectionManager {
private localUser!: LocalUser;
@ -101,10 +106,10 @@ class ConnectionManager {
const code = urlParams.get("code");
const state = urlParams.get("state");
if (!state || !localUserStore.verifyState(state)) {
throw "Could not validate state!";
throw new Error("Could not validate state!");
}
if (!code) {
throw "No Auth code provided";
throw new Error("No Auth code provided");
}
localUserStore.setCode(code);
}
@ -125,6 +130,10 @@ class ConnectionManager {
const data = await Axios.post(`${PUSHER_URL}/register`, { organizationMemberToken }).then(
(res) => res.data
);
if (!isRegisterData(data)) {
console.error("Invalid data received from /register route. Data: ", data);
throw new Error("Invalid data received from /register route.");
}
this.localUser = new LocalUser(data.userUuid, data.textures, data.email);
this.authToken = data.authToken;
localUserStore.saveUser(this.localUser);
@ -145,11 +154,7 @@ class ConnectionManager {
)
);
urlManager.pushRoomIdToUrl(this._currentRoom);
} else if (
connexionType === GameConnexionTypes.organization ||
connexionType === GameConnexionTypes.anonymous ||
connexionType === GameConnexionTypes.empty
) {
} else if (connexionType === GameConnexionTypes.room || connexionType === GameConnexionTypes.empty) {
this.authToken = localUserStore.getAuthToken();
let roomPath: string;
@ -163,6 +168,9 @@ class ConnectionManager {
}
} catch (err) {
console.error(err);
if (err instanceof Error) {
console.error(err.stack);
}
}
} else {
const query = urlParams.toString();
@ -181,7 +189,7 @@ class ConnectionManager {
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
//use href to keep # value
localUserStore.setLastRoomUrl(this._currentRoom.href);
await localUserStore.setLastRoomUrl(this._currentRoom.href);
//todo: add here some kind of warning if authToken has expired.
if (!this.authToken && !this._currentRoom.authenticationMandatory) {
@ -192,11 +200,13 @@ class ConnectionManager {
analyticsClient.loggedWithSso();
} catch (err) {
console.error(err);
//if user must to be connect in current room or pusher error is not openid provier access error
//try to connected with function loadOpenIDScreen
// if the user must be connected in the current room or if the pusher error is not openid provider access error
// try to connect with function loadOpenIDScreen
if (
this._currentRoom.authenticationMandatory ||
(err.response?.data && err.response.data !== "User cannot to be connected on openid provier")
(axios.isAxiosError(err) &&
err.response?.data &&
err.response.data !== "User cannot to be connected on openid provider")
) {
this.loadOpenIDScreen();
return Promise.reject(new Error("You will be redirect on login page"));
@ -228,6 +238,17 @@ class ConnectionManager {
analyticsClient.identifyUser(this.localUser.uuid, this.localUser.email);
}
//if limit room active test headband
if (this._currentRoom.expireOn !== undefined) {
warningContainerStore.activateWarningContainer();
limitMapStore.set(true);
//check time of map
if (new Date() > this._currentRoom.expireOn) {
showLimitRoomModalStore.set(true);
}
}
this.serviceWorker = new _ServiceWorker();
return Promise.resolve(this._currentRoom);
}
@ -271,7 +292,7 @@ class ConnectionManager {
reject(error);
});
connection.onConnectingError((event: CloseEvent) => {
connection.connectionErrorStream.subscribe((event: CloseEvent) => {
console.log("An error occurred while connecting to socket server. Retrying");
reject(
new Error(
@ -283,7 +304,7 @@ class ConnectionManager {
);
});
connection.onConnect((connect: OnConnectInterface) => {
connection.roomJoinedMessageStream.subscribe((connect: OnConnectInterface) => {
resolve(connect);
});
}).catch((err) => {
@ -292,7 +313,7 @@ class ConnectionManager {
this.reconnectingTimeout = setTimeout(() => {
//todo: allow a way to break recursion?
//todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely.
this.connectToRoomSocket(roomUrl, name, characterLayers, position, viewport, companion).then(
void this.connectToRoomSocket(roomUrl, name, characterLayers, position, viewport, companion).then(
(connection) => resolve(connection)
);
}, 4000 + Math.floor(Math.random() * 2000));
@ -315,15 +336,17 @@ class ConnectionManager {
if (!token) {
if (!state || !localUserStore.verifyState(state)) {
throw "Could not validate state!";
throw new Error("Could not validate state!");
}
if (!code) {
throw "No Auth code provided";
throw new Error("No Auth code provided");
}
}
const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, {
params: { code, nonce, token, playUri: this.currentRoom?.key },
}).then((res) => res.data);
}).then((res) => {
return res.data;
});
localUserStore.setAuthToken(authToken);
this.localUser = new LocalUser(userUuid, textures, email);
localUserStore.saveUser(this.localUser);

View file

@ -1,43 +1,12 @@
import type { SignalData } from "simple-peer";
import type { RoomConnection } from "./RoomConnection";
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
export enum EventMessage {
CONNECT = "connect",
WEBRTC_SIGNAL = "webrtc-signal",
WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal",
WEBRTC_START = "webrtc-start",
//START_ROOM = "start-room", // From server to client: list of all room users/groups/items
JOIN_ROOM = "join-room", // bi-directional
USER_POSITION = "user-position", // From client to server
USER_MOVED = "user-moved", // From server to client
USER_LEFT = "user-left", // From server to client
MESSAGE_ERROR = "message-error",
WEBRTC_DISCONNECT = "webrtc-disconect",
GROUP_CREATE_UPDATE = "group-create-update",
GROUP_DELETE = "group-delete",
SET_PLAYER_DETAILS = "set-player-details", // Send the name and character to the server (on connect), receive back the id.
ITEM_EVENT = "item-event",
CONNECT_ERROR = "connect_error",
CONNECTING_ERROR = "connecting_error",
SET_SILENT = "set_silent", // Set or unset the silent mode for this user.
SET_VIEWPORT = "set-viewport",
BATCH = "batch",
PLAY_GLOBAL_MESSAGE = "play-global-message",
STOP_GLOBAL_MESSAGE = "stop-global-message",
TELEPORT = "teleport",
USER_MESSAGE = "user-message",
START_JITSI_ROOM = "start-jitsi-room",
SET_VARIABLE = "set-variable",
}
import { PositionMessage_Direction } from "../Messages/ts-proto-generated/messages";
export interface PointInterface {
x: number;
y: number;
direction: string;
direction: string; // TODO: modify this to the enum from ts-proto
moving: boolean;
}
@ -64,6 +33,7 @@ export interface MessageUserJoined {
visitCardUrl: string | null;
companion: string | null;
userUuid: string;
outlineColor: number | undefined;
}
export interface PositionInterface {
@ -102,6 +72,12 @@ export interface ItemEventMessageInterface {
parameters: unknown;
}
export interface PlayerDetailsUpdatedMessageInterface {
userId: number;
outlineColor: number;
removeOutlineColor: boolean;
}
export interface RoomJoinedMessageInterface {
//users: MessageUserPositionInterface[],
//groups: GroupCreatedUpdatedMessageInterface[],

View file

@ -1,17 +0,0 @@
import { Subject } from "rxjs";
interface EmoteEvent {
userId: number;
emote: string;
}
class EmoteEventStream {
private _stream: Subject<EmoteEvent> = new Subject();
public stream = this._stream.asObservable();
fire(userId: number, emote: string) {
this._stream.next({ userId, emote });
}
}
export const emoteEventStream = new EmoteEventStream();

View file

@ -14,6 +14,7 @@ const audioPlayerMuteKey = "audioMute";
const helpCameraSettingsShown = "helpCameraSettingsShown";
const fullscreenKey = "fullscreen";
const forceCowebsiteTriggerKey = "forceCowebsiteTrigger";
const ignoreFollowRequests = "ignoreFollowRequests";
const lastRoomUrl = "lastRoomUrl";
const authToken = "authToken";
const state = "state";
@ -128,13 +129,23 @@ class LocalUserStore {
return localStorage.getItem(forceCowebsiteTriggerKey) === "true";
}
setLastRoomUrl(roomUrl: string): void {
setIgnoreFollowRequests(value: boolean): void {
localStorage.setItem(ignoreFollowRequests, value.toString());
}
getIgnoreFollowRequests(): boolean {
return localStorage.getItem(ignoreFollowRequests) === "true";
}
async setLastRoomUrl(roomUrl: string): Promise<void> {
localStorage.setItem(lastRoomUrl, roomUrl.toString());
if ("caches" in window) {
caches.open(cacheAPIIndex).then((cache) => {
try {
const cache = await caches.open(cacheAPIIndex);
const stringResponse = new Response(JSON.stringify({ roomUrl }));
cache.put(`/${lastRoomUrl}`, stringResponse);
});
await cache.put(`/${lastRoomUrl}`, stringResponse);
} catch (e) {
console.error("Could not store last room url in Browser cache. Are you using private browser mode?", e);
}
}
}
getLastRoomUrl(): string {

View file

@ -5,6 +5,8 @@ import type { CharacterTexture } from "./LocalUser";
import { localUserStore } from "./LocalUserStore";
import axios from "axios";
import { axiosWithRetry } from "./AxiosUtils";
import { isMapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
export class MapDetail {
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
@ -16,7 +18,10 @@ export interface RoomRedirect {
export class Room {
public readonly id: string;
public readonly isPublic: boolean;
/**
* @deprecated
*/
private readonly isPublic: boolean;
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS;
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
private _mapUrl: string | undefined;
@ -25,6 +30,8 @@ export class Room {
private readonly _search: URLSearchParams;
private _contactPage: string | undefined;
private _group: string | null = null;
private _expireOn: Date | undefined;
private _canReport: boolean = false;
private constructor(private roomUrl: URL) {
this.id = roomUrl.pathname;
@ -32,7 +39,7 @@ export class Room {
if (this.id.startsWith("/")) {
this.id = this.id.substr(1);
}
if (this.id.startsWith("_/")) {
if (this.id.startsWith("_/") || this.id.startsWith("*/")) {
this.isPublic = true;
} else if (this.id.startsWith("@/")) {
this.isPublic = false;
@ -80,13 +87,11 @@ export class Room {
const currentRoom = new Room(baseUrl);
let instance: string = "global";
if (currentRoom.isPublic) {
instance = currentRoom.instance as string;
instance = currentRoom.getInstance();
}
baseUrl.pathname = "/_/" + instance + "/" + absoluteExitSceneUrl.host + absoluteExitSceneUrl.pathname;
if (absoluteExitSceneUrl.hash) {
baseUrl.hash = absoluteExitSceneUrl.hash;
}
baseUrl.hash = absoluteExitSceneUrl.hash;
return baseUrl;
}
@ -101,27 +106,41 @@ export class Room {
});
const data = result.data;
if (data.redirectUrl) {
return {
redirectUrl: data.redirectUrl as string,
};
if (data.authenticationMandatory !== undefined) {
data.authenticationMandatory = Boolean(data.authenticationMandatory);
}
if (isRoomRedirect(data)) {
return {
redirectUrl: data.redirectUrl,
};
} else if (isMapDetailsData(data)) {
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
this._mapUrl = data.mapUrl;
this._textures = data.textures;
this._group = data.group;
this._authenticationMandatory =
data.authenticationMandatory != null ? data.authenticationMandatory : DISABLE_ANONYMOUS;
this._iframeAuthentication = data.iframeAuthentication || OPID_LOGIN_SCREEN_PROVIDER;
this._contactPage = data.contactPage || CONTACT_URL;
if (data.expireOn) {
this._expireOn = new Date(data.expireOn);
}
this._canReport = data.canReport ?? false;
return new MapDetail(data.mapUrl, data.textures);
} else {
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
}
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
this._mapUrl = data.mapUrl;
this._textures = data.textures;
this._group = data.group;
this._authenticationMandatory =
data.authenticationMandatory != null ? data.authenticationMandatory : DISABLE_ANONYMOUS;
this._iframeAuthentication = data.iframeAuthentication || OPID_LOGIN_SCREEN_PROVIDER;
this._contactPage = data.contactPage || CONTACT_URL;
return new MapDetail(data.mapUrl, data.textures);
} catch (e) {
if (axios.isAxiosError(e) && e.response?.status == 401 && e.response?.data === "Token decrypted error") {
console.warn("JWT token sent could not be decrypted. Maybe it expired?");
localUserStore.setAuthToken(null);
window.location.assign("/login");
} else {
} else if (axios.isAxiosError(e)) {
console.error("Error => getMapDetail", e, e.response);
} else {
console.error("Error => getMapDetail", e);
}
throw e;
}
@ -131,6 +150,8 @@ export class Room {
* Instance name is:
* - In a public URL: the second part of the URL ( _/[instance]/map.json)
* - In a private URL: [organizationId/worldId]
*
* @deprecated
*/
public getInstance(): string {
if (this.instance !== undefined) {
@ -138,7 +159,7 @@ export class Room {
}
if (this.isPublic) {
const match = /_\/([^/]+)\/.+/.exec(this.id);
const match = /[_*]\/([^/]+)\/.+/.exec(this.id);
if (!match) throw new Error('Could not extract instance from "' + this.id + '"');
this.instance = match[1];
return this.instance;
@ -210,4 +231,12 @@ export class Room {
get group(): string | null {
return this._group;
}
get expireOn(): Date | undefined {
return this._expireOn;
}
get canReport(): boolean {
return this._canReport;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +0,0 @@
import { Subject } from "rxjs";
class WorldFullMessageStream {
private _stream: Subject<string | null> = new Subject<string | null>();
public stream = this._stream.asObservable();
onMessage(message?: string) {
this._stream.next(message);
}
}
export const worldFullMessageStream = new WorldFullMessageStream();

View file

@ -1 +0,0 @@
/generated/

View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -0,0 +1 @@
*

View file

@ -1,21 +1,21 @@
import { PositionMessage } from "../Messages/generated/messages_pb";
import Direction = PositionMessage.Direction;
import { PositionMessage, PositionMessage_Direction } from "../Messages/ts-proto-generated/messages";
import type { PointInterface } from "../Connexion/ConnexionModels";
export class ProtobufClientUtils {
public static toPointInterface(position: PositionMessage): PointInterface {
let direction: string;
switch (position.getDirection()) {
case Direction.UP:
switch (position.direction) {
case PositionMessage_Direction.UP:
direction = "up";
break;
case Direction.DOWN:
case PositionMessage_Direction.DOWN:
direction = "down";
break;
case Direction.LEFT:
case PositionMessage_Direction.LEFT:
direction = "left";
break;
case Direction.RIGHT:
case PositionMessage_Direction.RIGHT:
direction = "right";
break;
default:
@ -24,10 +24,10 @@ export class ProtobufClientUtils {
// sending to all clients in room except sender
return {
x: position.getX(),
y: position.getY(),
x: position.x,
y: position.y,
direction,
moving: position.getMoving(),
moving: position.moving,
};
}
}

View file

@ -41,13 +41,15 @@ export class Companion extends Container {
this.companionName = name;
this._pictureStore = writable(undefined);
texturePromise.then((resource) => {
this.addResource(resource);
this.invisible = false;
return this.getSnapshot().then((htmlImageElementSrc) => {
this._pictureStore.set(htmlImageElementSrc);
});
});
texturePromise
.then((resource) => {
this.addResource(resource);
this.invisible = false;
return this.getSnapshot().then((htmlImageElementSrc) => {
this._pictureStore.set(htmlImageElementSrc);
});
})
.catch((e) => console.error(e));
this.scene.physics.world.enableBody(this);

View file

@ -3,7 +3,7 @@ import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./Co
export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => {
COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => {
lazyLoadCompanionResource(loader, resource.name);
lazyLoadCompanionResource(loader, resource.name).catch((e) => console.error(e));
});
return COMPANION_RESOURCES;

View file

@ -72,9 +72,11 @@ export class Loader {
if (this.loadingText) {
this.loadingText.destroy();
}
promiseLoadLogoTexture.then((resLoadingImage: Phaser.GameObjects.Image) => {
resLoadingImage.destroy();
});
promiseLoadLogoTexture
.then((resLoadingImage: Phaser.GameObjects.Image) => {
resLoadingImage.destroy();
})
.catch((e) => console.error(e));
this.progress.destroy();
this.progressContainer.destroy();
if (this.scene instanceof DirtyScene) {

View file

@ -13,7 +13,8 @@ import { isSilentStore } from "../../Stores/MediaStore";
import { lazyLoadPlayerCharacterTextures, loadAllDefaultModels } from "./PlayerTexturesLoadingManager";
import { TexturesHelper } from "../Helpers/TexturesHelper";
import type { PictureStore } from "../../Stores/PictureStore";
import { Writable, writable } from "svelte/store";
import { Unsubscriber, Writable, writable } from "svelte/store";
import { createColorStore } from "../../Stores/OutlineColorStore";
const playerNameY = -25;
@ -32,7 +33,7 @@ export abstract class Character extends Container {
private readonly playerName: Text;
public PlayerValue: string;
public sprites: Map<string, Sprite>;
private lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
protected lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
//private teleportation: Sprite;
private invisible: boolean;
public companion?: Companion;
@ -40,6 +41,8 @@ export abstract class Character extends Container {
private emoteTween: Phaser.Tweens.Tween | null = null;
scene: GameScene;
private readonly _pictureStore: Writable<string | undefined>;
private readonly outlineColorStore = createColorStore();
private readonly outlineColorStoreUnsubscribe: Unsubscriber;
constructor(
scene: GameScene,
@ -97,18 +100,26 @@ export abstract class Character extends Container {
});
this.on("pointerover", () => {
this.getOutlinePlugin()?.add(this.playerName, {
thickness: 2,
outlineColor: 0xffff00,
});
this.scene.markDirty();
this.outlineColorStore.pointerOver();
});
this.on("pointerout", () => {
this.getOutlinePlugin()?.remove(this.playerName);
this.scene.markDirty();
this.outlineColorStore.pointerOut();
});
}
this.outlineColorStoreUnsubscribe = this.outlineColorStore.subscribe((color) => {
if (color === undefined) {
this.getOutlinePlugin()?.remove(this.playerName);
} else {
this.getOutlinePlugin()?.remove(this.playerName);
this.getOutlinePlugin()?.add(this.playerName, {
thickness: 2,
outlineColor: color,
});
}
this.scene.markDirty();
});
scene.add.existing(this);
this.scene.physics.world.enableBody(this);
@ -266,24 +277,20 @@ export abstract class Character extends Container {
body.setVelocity(x, y);
// up or down animations are prioritized over left and right
if (body.velocity.y < 0) {
//moving up
this.lastDirection = PlayerAnimationDirections.Up;
this.playAnimation(PlayerAnimationDirections.Up, true);
} else if (body.velocity.y > 0) {
//moving down
this.lastDirection = PlayerAnimationDirections.Down;
this.playAnimation(PlayerAnimationDirections.Down, true);
} else if (body.velocity.x > 0) {
//moving right
this.lastDirection = PlayerAnimationDirections.Right;
this.playAnimation(PlayerAnimationDirections.Right, true);
} else if (body.velocity.x < 0) {
//moving left
this.lastDirection = PlayerAnimationDirections.Left;
this.playAnimation(PlayerAnimationDirections.Left, true);
if (Math.abs(body.velocity.x) > Math.abs(body.velocity.y)) {
if (body.velocity.x < 0) {
this.lastDirection = PlayerAnimationDirections.Left;
} else if (body.velocity.x > 0) {
this.lastDirection = PlayerAnimationDirections.Right;
}
} else {
if (body.velocity.y < 0) {
this.lastDirection = PlayerAnimationDirections.Up;
} else if (body.velocity.y > 0) {
this.lastDirection = PlayerAnimationDirections.Down;
}
}
this.playAnimation(this.lastDirection, true);
this.setDepth(this.y);
@ -315,6 +322,7 @@ export abstract class Character extends Container {
}
}
this.list.forEach((objectContaining) => objectContaining.destroy());
this.outlineColorStoreUnsubscribe();
super.destroy();
}
@ -401,4 +409,12 @@ export abstract class Character extends Container {
public get pictureStore(): PictureStore {
return this._pictureStore;
}
public setOutlineColor(color: number): void {
this.outlineColorStore.setColor(color);
}
public removeOutlineColor(): void {
this.outlineColorStore.removeColor();
}
}

View file

@ -90,7 +90,7 @@ export const getRessourceDescriptor = (
const playerResource = LAYERS[i][textureName];
if (playerResource !== undefined) return playerResource;
}
throw "Could not find a data for texture " + textureName;
throw new Error("Could not find a data for texture " + textureName);
};
export const createLoadingPromise = (

View file

@ -44,6 +44,7 @@ export class CameraManager extends Phaser.Events.EventEmitter {
private startFollowTween?: Phaser.Tweens.Tween;
private playerToFollow?: Player;
private cameraLocked: boolean;
constructor(scene: GameScene, cameraBounds: { x: number; y: number }, waScaleManager: WaScaleManager) {
super();
@ -51,6 +52,7 @@ export class CameraManager extends Phaser.Events.EventEmitter {
this.camera = scene.cameras.main;
this.cameraBounds = cameraBounds;
this.cameraLocked = false;
this.waScaleManager = waScaleManager;
@ -123,6 +125,8 @@ export class CameraManager extends Phaser.Events.EventEmitter {
this.waScaleManager.saveZoom();
this.waScaleManager.setFocusTarget(focusOn);
this.cameraLocked = true;
this.unlockCameraWithDelay(duration);
this.restoreZoomTween?.stop();
this.startFollowTween?.stop();
const marginMult = 1 + margin;
@ -143,8 +147,9 @@ export class CameraManager extends Phaser.Events.EventEmitter {
);
}
public leaveFocusMode(player: Player, duration: number = 1000): void {
public leaveFocusMode(player: Player, duration = 0): void {
this.waScaleManager.setFocusTarget();
this.unlockCameraWithDelay(duration);
this.startFollowPlayer(player, duration);
this.restoreZoom(duration);
}
@ -196,8 +201,14 @@ export class CameraManager extends Phaser.Events.EventEmitter {
);
}
public isCameraZoomLocked(): boolean {
return [CameraMode.Focus, CameraMode.Positioned].includes(this.cameraMode);
public isCameraLocked(): boolean {
return this.cameraLocked;
}
private unlockCameraWithDelay(delay: number): void {
this.scene.time.delayedCall(delay, () => {
this.cameraLocked = false;
});
}
private setCameraMode(mode: CameraMode): void {

View file

@ -1,13 +1,13 @@
import { emoteEventStream } from "../../Connexion/EmoteEventStream";
import type { GameScene } from "./GameScene";
import type { Subscription } from "rxjs";
import type { RoomConnection } from "../../Connexion/RoomConnection";
export class EmoteManager {
private subscription: Subscription;
constructor(private scene: GameScene) {
this.subscription = emoteEventStream.stream.subscribe((event) => {
const actor = this.scene.MapPlayersByKey.get(event.userId);
constructor(private scene: GameScene, private connection: RoomConnection) {
this.subscription = connection.emoteEventMessageStream.subscribe((event) => {
const actor = this.scene.MapPlayersByKey.get(event.actorUserId);
if (actor) {
actor.playEmote(event.emote);
}

View file

@ -66,7 +66,7 @@ export class GameManager {
getCharacterLayers(): string[] {
if (!this.characterLayers) {
throw "characterLayers are not set";
throw new Error("characterLayers are not set");
}
return this.characterLayers;
}
@ -119,7 +119,7 @@ export class GameManager {
* This will close the socket connections and stop the gameScene, but won't remove it.
*/
leaveGame(targetSceneName: string, sceneClass: Phaser.Scene): void {
if (this.currentGameSceneName === null) throw "No current scene id set!";
if (this.currentGameSceneName === null) throw new Error("No current scene id set!");
const gameScene: GameScene = this.scenePlugin.get(this.currentGameSceneName) as GameScene;
gameScene.cleanupClosingScene();
gameScene.createSuccessorGameScene(false, false);
@ -143,7 +143,7 @@ export class GameManager {
}
public getCurrentGameScene(): GameScene {
if (this.currentGameSceneName === null) throw "No current scene id set!";
if (this.currentGameSceneName === null) throw new Error("No current scene id set!");
return this.scenePlugin.get(this.currentGameSceneName) as GameScene;
}

View file

@ -81,7 +81,14 @@ export class GameMap {
let depth = -2;
for (const layer of this.flatLayers) {
if (layer.type === "tilelayer") {
this.phaserLayers.push(phaserMap.createLayer(layer.name, terrains, 0, 0).setDepth(depth));
this.phaserLayers.push(
phaserMap
.createLayer(layer.name, terrains, (layer.x || 0) * 32, (layer.y || 0) * 32)
.setDepth(depth)
.setAlpha(layer.opacity)
.setVisible(layer.visible)
.setSize(layer.width, layer.height)
);
}
if (layer.type === "objectgroup" && layer.name === "floorLayer") {
depth = DEPTH_OVERLAY_INDEX;

View file

@ -123,7 +123,7 @@ export class GameMapPropertiesListener {
.then((coWebsite) => {
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
coWebsiteManager.closeCoWebsite(coWebsite);
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => console.error(e));
this.coWebsitesOpenByLayer.delete(layer);
this.coWebsitesActionTriggerByLayer.delete(layer);
} else {
@ -132,7 +132,8 @@ export class GameMapPropertiesListener {
state: OpenCoWebsiteState.OPENED,
});
}
});
})
.catch((e) => console.error(e));
layoutManagerActionStore.removeAction(actionUuid);
};
@ -198,7 +199,7 @@ export class GameMapPropertiesListener {
}
if (coWebsiteOpen.coWebsite !== undefined) {
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite);
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite).catch((e) => console.error(e));
}
this.coWebsitesOpenByLayer.delete(layer);

View file

@ -1,7 +1,7 @@
import type { Subscription } from "rxjs";
import AnimatedTiles from "phaser-animated-tiles";
import { Queue } from "queue-typescript";
import { get } from "svelte/store";
import { get, Unsubscriber } from "svelte/store";
import { userMessageManager } from "../../Administration/UserMessageManager";
import { connectionManager } from "../../Connexion/ConnectionManager";
@ -12,7 +12,7 @@ import { UserInputManager } from "../UserInput/UserInputManager";
import { gameManager } from "./GameManager";
import { touchScreenManager } from "../../Touch/TouchScreenManager";
import { PinchManager } from "../UserInput/PinchManager";
import { waScaleManager } from "../Services/WaScaleManager";
import { waScaleManager, WaScaleManagerEvent } from "../Services/WaScaleManager";
import { EmoteManager } from "./EmoteManager";
import { soundManager } from "./SoundManager";
import { SharedVariablesManager } from "./SharedVariablesManager";
@ -40,7 +40,6 @@ import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene";
import { GameMap } from "./GameMap";
import { PlayerMovement } from "./PlayerMovement";
import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator";
import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream";
import { DirtyScene } from "./DirtyScene";
import { TextUtils } from "../Components/TextUtils";
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
@ -55,11 +54,11 @@ import type {
MessageUserMovedInterface,
MessageUserPositionInterface,
OnConnectInterface,
PlayerDetailsUpdatedMessageInterface,
PointInterface,
PositionInterface,
RoomJoinedMessageInterface,
} from "../../Connexion/ConnexionModels";
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
import type { RoomConnection } from "../../Connexion/RoomConnection";
import type { ActionableItem } from "../Items/ActionableItem";
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
@ -87,9 +86,13 @@ import GameObject = Phaser.GameObjects.GameObject;
import DOMElement = Phaser.GameObjects.DOMElement;
import Tileset = Phaser.Tilemaps.Tileset;
import SpriteSheetFile = Phaser.Loader.FileTypes.SpriteSheetFile;
import Camera = Phaser.Cameras.Scene2D.Camera;
import { deepCopy } from "deep-copy-ts";
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import { MapStore } from "../../Stores/Utils/MapStore";
import { followUsersColorStore, followUsersStore } from "../../Stores/FollowStore";
import { getColorRgbFromHue } from "../../WebRtc/ColorGenerator";
import Camera = Phaser.Cameras.Scene2D.Camera;
export interface GameSceneInitInterface {
initPosition: PointInterface | null;
reconnecting: boolean;
@ -125,6 +128,11 @@ interface DeleteGroupEventInterface {
groupId: number;
}
interface PlayerDetailsUpdatedInterface {
type: "PlayerDetailsUpdated";
details: PlayerDetailsUpdatedMessageInterface;
}
export class GameScene extends DirtyScene {
Terrains: Array<Phaser.Tilemaps.Tileset>;
CurrentPlayer!: Player;
@ -137,20 +145,14 @@ export class GameScene extends DirtyScene {
groups: Map<number, Sprite>;
circleTexture!: CanvasTexture;
circleRedTexture!: CanvasTexture;
pendingEvents: Queue<
| InitUserPositionEventInterface
| AddPlayerEventInterface
| RemovePlayerEventInterface
| UserMovedEventInterface
| GroupCreatedUpdatedEventInterface
| DeleteGroupEventInterface
> = new Queue<
pendingEvents = new Queue<
| InitUserPositionEventInterface
| AddPlayerEventInterface
| RemovePlayerEventInterface
| UserMovedEventInterface
| GroupCreatedUpdatedEventInterface
| DeleteGroupEventInterface
| PlayerDetailsUpdatedInterface
>();
private initPosition: PositionInterface | null = null;
private playersPositionInterpolator = new PlayersPositionInterpolator();
@ -164,9 +166,11 @@ export class GameScene extends DirtyScene {
private createPromise: Promise<void>;
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
private iframeSubscriptionList!: Array<Subscription>;
private peerStoreUnsubscribe!: () => void;
private emoteUnsubscribe!: () => void;
private emoteMenuUnsubscribe!: () => void;
private peerStoreUnsubscribe!: Unsubscriber;
private emoteUnsubscribe!: Unsubscriber;
private emoteMenuUnsubscribe!: Unsubscriber;
private followUsersColorStoreUnsubscribe!: Unsubscriber;
private biggestAvailableAreaStoreUnsubscribe!: () => void;
MapUrlFile: string;
roomUrl: string;
@ -237,7 +241,7 @@ export class GameScene extends DirtyScene {
const textures = localUser?.textures;
if (textures) {
for (const texture of textures) {
loadCustomTexture(this.load, texture);
loadCustomTexture(this.load, texture).catch((e) => console.error(e));
}
}
@ -264,7 +268,7 @@ export class GameScene extends DirtyScene {
this.load.on(
"filecomplete-tilemapJSON-" + this.MapUrlFile,
(key: string, type: string, data: unknown) => {
this.onMapLoad(data);
this.onMapLoad(data).catch((e) => console.error(e));
}
);
return;
@ -288,14 +292,14 @@ export class GameScene extends DirtyScene {
this.load.on(
"filecomplete-tilemapJSON-" + this.MapUrlFile,
(key: string, type: string, data: unknown) => {
this.onMapLoad(data);
this.onMapLoad(data).catch((e) => console.error(e));
}
);
// If the map has already been loaded as part of another GameScene, the "on load" event will not be triggered.
// In this case, we check in the cache to see if the map is here and trigger the event manually.
if (this.cache.tilemap.exists(this.MapUrlFile)) {
const data = this.cache.tilemap.get(this.MapUrlFile);
this.onMapLoad(data);
this.onMapLoad(data).catch((e) => console.error(e));
}
return;
}
@ -316,7 +320,7 @@ export class GameScene extends DirtyScene {
});
this.load.scenePlugin("AnimatedTiles", AnimatedTiles, "animatedTiles", "animatedTiles");
this.load.on("filecomplete-tilemapJSON-" + this.MapUrlFile, (key: string, type: string, data: unknown) => {
this.onMapLoad(data);
this.onMapLoad(data).catch((e) => console.error(e));
});
//TODO strategy to add access token
this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile);
@ -324,7 +328,7 @@ export class GameScene extends DirtyScene {
// In this case, we check in the cache to see if the map is here and trigger the event manually.
if (this.cache.tilemap.exists(this.MapUrlFile)) {
const data = this.cache.tilemap.get(this.MapUrlFile);
this.onMapLoad(data);
this.onMapLoad(data).catch((e) => console.error(e));
}
//eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -345,7 +349,10 @@ export class GameScene extends DirtyScene {
private async onMapLoad(data: any): Promise<void> {
// Triggered when the map is loaded
// Load tiles attached to the map recursively
this.mapFile = data.data;
// The map file can be modified by the scripting API and we don't want to tamper the Phaser cache (in case we come back on the map after visiting other maps)
// So we are doing a deep copy
this.mapFile = deepCopy(data.data);
const url = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/"));
this.mapFile.tilesets.forEach((tileset) => {
if (typeof tileset.name === "undefined" || typeof tileset.image === "undefined") {
@ -399,21 +406,23 @@ export class GameScene extends DirtyScene {
this.load.on("complete", () => {
// FIXME: the factory might fail because the resources might not be loaded yet...
// We would need to add a loader ended event in addition to the createPromise
this.createPromise.then(async () => {
itemFactory.create(this);
this.createPromise
.then(async () => {
itemFactory.create(this);
const roomJoinedAnswer = await this.connectionAnswerPromise;
const roomJoinedAnswer = await this.connectionAnswerPromise;
for (const object of objectsOfType) {
// TODO: we should pass here a factory to create sprites (maybe?)
for (const object of objectsOfType) {
// TODO: we should pass here a factory to create sprites (maybe?)
// Do we have a state for this object?
const state = roomJoinedAnswer.items[object.id];
// Do we have a state for this object?
const state = roomJoinedAnswer.items[object.id];
const actionableItem = itemFactory.factory(this, object, state);
this.actionableItems.set(actionableItem.getId(), actionableItem);
}
});
const actionableItem = itemFactory.factory(this, object, state);
this.actionableItems.set(actionableItem.getId(), actionableItem);
}
})
.catch((e) => console.error(e));
});
}
}
@ -442,13 +451,9 @@ export class GameScene extends DirtyScene {
this.pinchManager = new PinchManager(this);
}
this.messageSubscription = worldFullMessageStream.stream.subscribe((message) =>
this.showWorldFullError(message)
);
const playerName = gameManager.getPlayerName();
if (!playerName) {
throw "playerName is not set";
throw new Error("playerName is not set");
}
this.playerName = playerName;
this.characterLayers = gameManager.getCharacterLayers();
@ -483,11 +488,11 @@ export class GameScene extends DirtyScene {
if (exitSceneUrl !== undefined) {
this.loadNextGame(
Room.getRoomPathFromExitSceneUrl(exitSceneUrl, window.location.toString(), this.MapUrlFile)
);
).catch((e) => console.error(e));
}
const exitUrl = this.getExitUrl(layer);
if (exitUrl !== undefined) {
this.loadNextGameFromExitUrl(exitUrl);
this.loadNextGameFromExitUrl(exitUrl).catch((e) => console.error(e));
}
}
if (layer.type === "objectgroup") {
@ -527,7 +532,7 @@ export class GameScene extends DirtyScene {
}
this.gameMap.exitUrls.forEach((exitUrl) => {
this.loadNextGameFromExitUrl(exitUrl);
this.loadNextGameFromExitUrl(exitUrl).catch((e) => console.error(e));
});
this.startPositionCalculator = new StartPositionCalculator(
@ -548,7 +553,10 @@ export class GameScene extends DirtyScene {
mediaManager.setUserInputManager(this.userInputManager);
if (localUserStore.getFullscreen()) {
document.querySelector("body")?.requestFullscreen();
document
.querySelector("body")
?.requestFullscreen()
.catch((e) => console.error(e));
}
//notify game manager can to create currentUser in map
@ -613,8 +621,6 @@ export class GameScene extends DirtyScene {
this.connect();
}
this.emoteManager = new EmoteManager(this);
let oldPeerNumber = 0;
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
const newPeerNumber = peers.size;
@ -646,9 +652,26 @@ export class GameScene extends DirtyScene {
}
});
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises]).then(() => {
this.scene.wake();
this.followUsersColorStoreUnsubscribe = followUsersColorStore.subscribe((color) => {
if (color !== undefined) {
this.CurrentPlayer.setOutlineColor(color);
this.connection?.emitPlayerOutlineColor(color);
} else {
this.CurrentPlayer.removeOutlineColor();
this.connection?.emitPlayerOutlineColor(null);
}
});
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises])
.then(() => {
this.scene.wake();
})
.catch((e) =>
console.error(
"Some scripts failed to load ot the connection failed to establish to WorkAdventure server",
e
)
);
}
/**
@ -679,7 +702,7 @@ export class GameScene extends DirtyScene {
playersStore.connectToRoomConnection(this.connection);
userIsAdminStore.set(this.connection.hasTag("admin"));
this.connection.onUserJoins((message: MessageUserJoined) => {
this.connection.userJoinedMessageStream.subscribe((message) => {
const userMessage: AddPlayerInterface = {
userId: message.userId,
characterLayers: message.characterLayers,
@ -688,35 +711,38 @@ export class GameScene extends DirtyScene {
visitCardUrl: message.visitCardUrl,
companion: message.companion,
userUuid: message.userUuid,
outlineColor: message.outlineColor,
};
this.addPlayer(userMessage);
});
this.connection.onUserMoved((message: UserMovedMessage) => {
const position = message.getPosition();
this.connection.userMovedMessageStream.subscribe((message) => {
const position = message.position;
if (position === undefined) {
throw new Error("Position missing from UserMovedMessage");
}
const messageUserMoved: MessageUserMovedInterface = {
userId: message.getUserid(),
userId: message.userId,
position: ProtobufClientUtils.toPointInterface(position),
};
this.updatePlayerPosition(messageUserMoved);
});
this.connection.onUserLeft((userId: number) => {
this.removePlayer(userId);
this.connection.userLeftMessageStream.subscribe((message) => {
this.removePlayer(message.userId);
});
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
});
this.connection.groupUpdateMessageStream.subscribe(
(groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
}
);
this.connection.onGroupDeleted((groupId: number) => {
this.connection.groupDeleteMessageStream.subscribe((message) => {
try {
this.deleteGroup(groupId);
this.deleteGroup(message.groupId);
} catch (e) {
console.error(e);
}
@ -728,7 +754,7 @@ export class GameScene extends DirtyScene {
this.createSuccessorGameScene(true, true);
});
this.connection.onActionableEvent((message) => {
this.connection.itemEventMessageStream.subscribe((message) => {
const item = this.actionableItems.get(message.itemId);
if (item === undefined) {
console.warn(
@ -741,11 +767,29 @@ export class GameScene extends DirtyScene {
item.fire(message.event, message.state, message.parameters);
});
this.connection.playerDetailsUpdatedMessageStream.subscribe((message) => {
if (message.details === undefined) {
throw new Error("Malformed message. Missing details in PlayerDetailsUpdatedMessage");
}
this.pendingEvents.enqueue({
type: "PlayerDetailsUpdated",
details: {
userId: message.userId,
outlineColor: message.details.outlineColor,
removeOutlineColor: message.details.removeOutlineColor,
},
});
});
/**
* Triggered when we receive the JWT token to connect to Jitsi
*/
this.connection.onStartJitsiRoom((jwt, room) => {
this.startJitsi(room, jwt);
this.connection.sendJitsiJwtMessageStream.subscribe((message) => {
this.startJitsi(message.jitsiRoom, message.jwt);
});
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
this.showWorldFullError(message);
});
// When connection is performed, let's connect SimplePeer
@ -811,7 +855,7 @@ export class GameScene extends DirtyScene {
for (const zone of zones) {
const focusable = zone.properties?.find((property) => property.name === "focusable");
if (focusable && focusable.value === true) {
this.cameraManager.leaveFocusMode(this.CurrentPlayer);
this.cameraManager.leaveFocusMode(this.CurrentPlayer, 1000);
break;
}
}
@ -820,12 +864,15 @@ export class GameScene extends DirtyScene {
});
});
this.emoteManager = new EmoteManager(this, this.connection);
// this.gameMap.onLeaveLayer((layers) => {
// layers.forEach((layer) => {
// iframeListener.sendLeaveLayerEvent(layer.name);
// });
// });
});
})
.catch((e) => console.error(e));
}
//todo: into dedicated classes
@ -878,7 +925,7 @@ export class GameScene extends DirtyScene {
if (newValue) {
this.onMapExit(
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
);
).catch((e) => console.error(e));
} else {
setTimeout(() => {
layoutManagerActionStore.removeAction("roomAccessDenied");
@ -887,7 +934,9 @@ export class GameScene extends DirtyScene {
});
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
if (newValue) {
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()));
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString())).catch((e) =>
console.error(e)
);
} else {
setTimeout(() => {
layoutManagerActionStore.removeAction("roomAccessDenied");
@ -1095,7 +1144,9 @@ ${escapedMessage}
this.iframeSubscriptionList.push(
iframeListener.playSoundStream.subscribe((playSoundEvent) => {
const url = new URL(playSoundEvent.url, this.MapUrlFile);
soundManager.playSound(this.load, this.sound, url.toString(), playSoundEvent.config);
soundManager
.playSound(this.load, this.sound, url.toString(), playSoundEvent.config)
.catch((e) => console.error(e));
})
);
@ -1136,7 +1187,7 @@ ${escapedMessage}
this.iframeSubscriptionList.push(
iframeListener.loadSoundStream.subscribe((loadSoundEvent) => {
const url = new URL(loadSoundEvent.url, this.MapUrlFile);
soundManager.loadSound(this.load, this.sound, url.toString());
soundManager.loadSound(this.load, this.sound, url.toString()).catch((e) => console.error(e));
})
);
@ -1147,11 +1198,15 @@ ${escapedMessage}
);
this.iframeSubscriptionList.push(
iframeListener.loadPageStream.subscribe((url: string) => {
this.loadNextGameFromExitUrl(url).then(() => {
this.events.once(EVENT_TYPE.POST_UPDATE, () => {
this.onMapExit(Room.getRoomPathFromExitUrl(url, window.location.toString()));
});
});
this.loadNextGameFromExitUrl(url)
.then(() => {
this.events.once(EVENT_TYPE.POST_UPDATE, () => {
this.onMapExit(Room.getRoomPathFromExitUrl(url, window.location.toString())).catch((e) =>
console.error(e)
);
});
})
.catch((e) => console.error(e));
})
);
let scriptedBubbleSprite: Sprite;
@ -1379,6 +1434,21 @@ ${escapedMessage}
layoutManagerActionStore.removeAction(message.uuid);
});
iframeListener.registerAnswerer("setPlayerOutline", (message) => {
const normalizeColor = (color: number) => Math.min(Math.max(0, Math.round(color)), 255);
const red = normalizeColor(message.red);
const green = normalizeColor(message.green);
const blue = normalizeColor(message.blue);
const color = (red << 16) | (green << 8) | blue;
this.CurrentPlayer.setOutlineColor(color);
this.connection?.emitPlayerOutlineColor(color);
});
iframeListener.registerAnswerer("removePlayerOutline", (message) => {
this.CurrentPlayer.removeOutlineColor();
this.connection?.emitPlayerOutlineColor(null);
});
iframeListener.registerAnswerer("getPlayerPosition", () => {
return {
x: this.CurrentPlayer.x,
@ -1393,7 +1463,7 @@ ${escapedMessage}
propertyValue: string | number | boolean | undefined
): void {
if (propertyName === GameMapProperties.EXIT_URL && typeof propertyValue === "string") {
this.loadNextGameFromExitUrl(propertyValue);
this.loadNextGameFromExitUrl(propertyValue).catch((e) => console.error(e));
}
this.gameMap.setLayerProperty(layerName, propertyName, propertyValue);
}
@ -1478,7 +1548,7 @@ ${escapedMessage}
public cleanupClosingScene(): void {
// stop playing audio, close any open website, stop any open Jitsi
coWebsiteManager.closeCoWebsites();
coWebsiteManager.closeCoWebsites().catch((e) => console.error(e));
// Stop the script, if any
const scripts = this.getScriptUrls(this.mapFile);
for (const script of scripts) {
@ -1499,6 +1569,7 @@ ${escapedMessage}
this.peerStoreUnsubscribe();
this.emoteUnsubscribe();
this.emoteMenuUnsubscribe();
this.followUsersColorStoreUnsubscribe();
this.biggestAvailableAreaStoreUnsubscribe();
iframeListener.unregisterAnswerer("getState");
iframeListener.unregisterAnswerer("loadTileset");
@ -1507,6 +1578,7 @@ ${escapedMessage}
iframeListener.unregisterAnswerer("removeActionMessage");
iframeListener.unregisterAnswerer("openCoWebsite");
iframeListener.unregisterAnswerer("getCoWebsites");
iframeListener.unregisterAnswerer("setPlayerOutline");
iframeListener.unregisterAnswerer("setVariable");
this.sharedVariablesManager?.close();
this.embeddedWebsiteManager?.close();
@ -1762,6 +1834,12 @@ ${escapedMessage}
case "DeleteGroupEvent":
this.doDeleteGroup(event.groupId);
break;
case "PlayerDetailsUpdated":
this.doUpdatePlayerDetails(event.details);
break;
default: {
const tmp: never = event;
}
}
}
// Let's move all users
@ -1835,6 +1913,9 @@ ${escapedMessage}
addPlayerData.companion,
addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined
);
if (addPlayerData.outlineColor !== undefined) {
player.setOutlineColor(addPlayerData.outlineColor);
}
this.MapPlayers.add(player);
this.MapPlayersByKey.set(player.userId, player);
player.updatePosition(addPlayerData.position);
@ -1938,6 +2019,23 @@ ${escapedMessage}
this.groups.delete(groupId);
}
doUpdatePlayerDetails(message: PlayerDetailsUpdatedMessageInterface): void {
const character = this.MapPlayersByKey.get(message.userId);
if (character === undefined) {
console.log(
"Could not set new details to character with ID ",
message.userId,
". Did he/she left before te message was received?"
);
return;
}
if (message.removeOutlineColor) {
character.removeOutlineColor();
} else {
character.setOutlineColor(message.outlineColor);
}
}
/**
* Sends to the server an event emitted by one of the ActionableItems.
*/
@ -1992,7 +2090,9 @@ ${escapedMessage}
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth);
jitsiFactory
.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth)
.catch((e) => console.error(e));
this.connection?.setSilent(true);
mediaManager.hideGameOverlay();
analyticsClient.enteredJitsi(roomName, this.room.id);
@ -2047,10 +2147,10 @@ ${escapedMessage}
}
zoomByFactor(zoomFactor: number) {
if (this.cameraManager.isCameraZoomLocked()) {
if (this.cameraManager.isCameraLocked()) {
return;
}
waScaleManager.zoomModifier *= zoomFactor;
waScaleManager.handleZoomByFactor(zoomFactor);
biggestAvailableAreaStore.recompute();
}

View file

@ -8,4 +8,5 @@ export interface PlayerInterface {
companion: string | null;
userUuid: string;
color?: string;
outlineColor?: number;
}

View file

@ -41,7 +41,7 @@ export class PlayerMovement {
oldX: this.startPosition.x,
oldY: this.startPosition.y,
direction: this.endPosition.direction,
moving: true,
moving: this.endPosition.moving,
};
}
}

View file

@ -42,7 +42,7 @@ export class SharedVariablesManager {
this._variables.set(name, value);
}
roomConnection.onSetVariable((name, value) => {
roomConnection.variableMessageStream.subscribe(({ name, value }) => {
this._variables.set(name, value);
// On server change, let's notify the iframes

View file

@ -40,19 +40,21 @@ export class CustomizeScene extends AbstractCharacterScene {
}
preload() {
this.loadCustomSceneSelectCharacters().then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
if (
bodyResourceDescription.level == undefined ||
bodyResourceDescription.level < 0 ||
bodyResourceDescription.level > 5
) {
throw "Texture level is null";
}
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
});
this.lazyloadingAttempt = true;
});
this.loadCustomSceneSelectCharacters()
.then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
if (
bodyResourceDescription.level == undefined ||
bodyResourceDescription.level < 0 ||
bodyResourceDescription.level > 5
) {
throw new Error("Texture level is null");
}
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
});
this.lazyloadingAttempt = true;
})
.catch((e) => console.error(e));
this.layers = loadAllLayers(this.load);
this.lazyloadingAttempt = false;

View file

@ -41,12 +41,14 @@ export class SelectCharacterScene extends AbstractCharacterScene {
}
preload() {
this.loadSelectSceneCharacters().then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
this.playerModels.push(bodyResourceDescription);
});
this.lazyloadingAttempt = true;
});
this.loadSelectSceneCharacters()
.then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
this.playerModels.push(bodyResourceDescription);
});
this.lazyloadingAttempt = true;
})
.catch((e) => console.error(e));
this.playerModels = loadAllDefaultModels(this.load);
this.lazyloadingAttempt = false;

View file

@ -162,6 +162,7 @@ export interface ITiledTileSet {
imageheight: number;
imagewidth: number;
columns: number;
margin: number;
name: string;
properties?: ITiledMapProperty[];

View file

@ -1,16 +1,17 @@
import { PlayerAnimationDirections } from "./Animation";
import type { GameScene } from "../Game/GameScene";
import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
import { ActiveEventList, UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
import { Character } from "../Entity/Character";
import type { RemotePlayer } from "../Entity/RemotePlayer";
import { get } from "svelte/store";
import { userMovingStore } from "../../Stores/GameStore";
import { followStateStore, followRoleStore, followUsersStore } from "../../Stores/FollowStore";
export const hasMovedEventName = "hasMoved";
export const requestEmoteEventName = "requestEmote";
export class Player extends Character {
private previousDirection: string = PlayerAnimationDirections.Down;
private wasMoving: boolean = false;
constructor(
Scene: GameScene,
x: number,
@ -29,71 +30,105 @@ export class Player extends Character {
this.getBody().setImmovable(false);
}
moveUser(delta: number): void {
//if user client on shift, camera and player speed
let direction = null;
let moving = false;
const activeEvents = this.userInputManager.getEventListForGameTick();
const speedMultiplier = activeEvents.get(UserInputEvent.SpeedUp) ? 25 : 9;
const moveAmount = speedMultiplier * 20;
let x = 0;
let y = 0;
private inputStep(activeEvents: ActiveEventList, x: number, y: number) {
// Process input events
if (activeEvents.get(UserInputEvent.MoveUp)) {
y = -moveAmount;
direction = PlayerAnimationDirections.Up;
moving = true;
y = y - 1;
} else if (activeEvents.get(UserInputEvent.MoveDown)) {
y = moveAmount;
direction = PlayerAnimationDirections.Down;
moving = true;
y = y + 1;
}
if (activeEvents.get(UserInputEvent.MoveLeft)) {
x = -moveAmount;
direction = PlayerAnimationDirections.Left;
moving = true;
x = x - 1;
} else if (activeEvents.get(UserInputEvent.MoveRight)) {
x = moveAmount;
direction = PlayerAnimationDirections.Right;
moving = true;
x = x + 1;
}
moving = moving || activeEvents.get(UserInputEvent.JoystickMove);
if (x !== 0 || y !== 0) {
// Compute movement deltas
const followMode = get(followStateStore) !== "off";
const speedup = activeEvents.get(UserInputEvent.SpeedUp) && !followMode ? 25 : 9;
const moveAmount = speedup * 20;
x = x * moveAmount;
y = y * moveAmount;
// Compute moving state
const joystickMovement = activeEvents.get(UserInputEvent.JoystickMove);
const moving = x !== 0 || y !== 0 || joystickMovement;
// Compute direction
let direction = this.lastDirection;
if (moving && !joystickMovement) {
if (Math.abs(x) > Math.abs(y)) {
direction = x < 0 ? PlayerAnimationDirections.Left : PlayerAnimationDirections.Right;
} else {
direction = y < 0 ? PlayerAnimationDirections.Up : PlayerAnimationDirections.Down;
}
}
// Send movement events
const emit = () => this.emit(hasMovedEventName, { moving, direction, x: this.x, y: this.y });
if (moving) {
this.move(x, y);
this.emit(hasMovedEventName, { moving, direction, x: this.x, y: this.y, oldX: x, oldY: y });
} else if (this.wasMoving && moving) {
// slow joystick movement
this.move(0, 0);
this.emit(hasMovedEventName, {
moving,
direction: this.previousDirection,
x: this.x,
y: this.y,
oldX: x,
oldY: y,
});
} else if (this.wasMoving && !moving) {
emit();
} else if (get(userMovingStore)) {
this.stop();
this.emit(hasMovedEventName, {
moving,
direction: this.previousDirection,
x: this.x,
y: this.y,
oldX: x,
oldY: y,
});
emit();
}
if (direction !== null) {
this.previousDirection = direction;
}
this.wasMoving = moving;
// Update state
userMovingStore.set(moving);
}
public isMoving(): boolean {
return this.wasMoving;
private computeFollowMovement(): number[] {
// Find followed WOKA and abort following if we lost it
const player = this.scene.MapPlayersByKey.get(get(followUsersStore)[0]);
if (!player) {
this.scene.connection?.emitFollowAbort();
followStateStore.set("off");
return [0, 0];
}
// Compute movement direction
const xDistance = player.x - this.x;
const yDistance = player.y - this.y;
const distance = Math.pow(xDistance, 2) + Math.pow(yDistance, 2);
if (distance < 2000) {
return [0, 0];
}
const xMovement = xDistance / Math.sqrt(distance);
const yMovement = yDistance / Math.sqrt(distance);
return [xMovement, yMovement];
}
public moveUser(delta: number): void {
const activeEvents = this.userInputManager.getEventListForGameTick();
const state = get(followStateStore);
const role = get(followRoleStore);
if (activeEvents.get(UserInputEvent.Follow)) {
if (state === "off" && this.scene.groups.size > 0) {
this.sendFollowRequest();
} else if (state === "active") {
followStateStore.set("ending");
}
}
let x = 0;
let y = 0;
if ((state === "active" || state === "ending") && role === "follower") {
[x, y] = this.computeFollowMovement();
}
this.inputStep(activeEvents, x, y);
}
public sendFollowRequest() {
this.scene.connection?.emitFollowRequest();
followRoleStore.set("leader");
followStateStore.set("active");
}
public startFollowing() {
followStateStore.set("active");
this.scene.connection?.emitFollowConfirmation();
}
}

View file

@ -78,6 +78,9 @@ export class ErrorScene extends Phaser.Scene {
*/
public static showError(error: unknown, scene: ScenePlugin): void {
console.error(error);
if (error instanceof Error) {
console.error("Stacktrace: ", error.stack);
}
console.trace();
if (typeof error === "string" || error instanceof String) {

View file

@ -5,6 +5,10 @@ import type { Game } from "../Game/Game";
import { ResizableScene } from "../Login/ResizableScene";
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
export enum WaScaleManagerEvent {
RefreshFocusOnTarget = "wa-scale-manager:refresh-focus-on-target",
}
export class WaScaleManager {
private hdpiManager: HdpiManager;
private scaleManager!: ScaleManager;
@ -31,6 +35,10 @@ export class WaScaleManager {
height: height * devicePixelRatio,
});
if (gameSize.width == 0) {
return;
}
this.actualZoom = realSize.width / gameSize.width / devicePixelRatio;
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio);
@ -65,7 +73,7 @@ export class WaScaleManager {
return;
}
this.zoomModifier = this.getTargetZoomModifierFor(this.focusTarget.width, this.focusTarget.height);
this.game.events.emit("wa-scale-manager:refresh-focus-on-target", this.focusTarget);
this.game.events.emit(WaScaleManagerEvent.RefreshFocusOnTarget, this.focusTarget);
}
public setFocusTarget(targetDimensions?: { x: number; y: number; width: number; height: number }): void {
@ -94,6 +102,17 @@ export class WaScaleManager {
this.applyNewSize();
}
public handleZoomByFactor(zoomFactor: number): void {
this.zoomModifier *= zoomFactor;
if (this.focusTarget) {
this.game.events.emit(WaScaleManagerEvent.RefreshFocusOnTarget, this.focusTarget);
}
}
public getFocusTarget(): { x: number; y: number; width: number; height: number } | undefined {
return this.focusTarget;
}
public saveZoom(): void {
this._saveZoom = this.hdpiManager.zoomModifier;
}

View file

@ -1,8 +1,8 @@
import type { Direction } from "../../types";
import type { GameScene } from "../Game/GameScene";
import { touchScreenManager } from "../../Touch/TouchScreenManager";
import { MobileJoystick } from "../Components/MobileJoystick";
import { enableUserInputsStore } from "../../Stores/UserInputStore";
import type { Direction } from "phaser3-rex-plugins/plugins/virtualjoystick.js";
interface UserInputManagerDatum {
keyInstance: Phaser.Input.Keyboard.Key;
@ -16,6 +16,7 @@ export enum UserInputEvent {
MoveDown,
SpeedUp,
Interact,
Follow,
Shout,
JoystickMove,
}
@ -147,6 +148,10 @@ export class UserInputManager {
event: UserInputEvent.Interact,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE, false),
},
{
event: UserInputEvent.Follow,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F, false),
},
{
event: UserInputEvent.Shout,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F, false),

View file

@ -26,7 +26,7 @@ export interface ChatMessage {
function getAuthor(authorId: number): PlayerInterface {
const author = playersStore.getPlayerById(authorId);
if (!author) {
throw "Could not find data for author " + authorId;
throw new Error("Could not find data for author " + authorId);
}
return author;
}

View file

@ -0,0 +1,89 @@
import { derived, writable } from "svelte/store";
import { getColorRgbFromHue } from "../WebRtc/ColorGenerator";
import { gameManager } from "../Phaser/Game/GameManager";
type FollowState = "off" | "requesting" | "active" | "ending";
type FollowRole = "leader" | "follower";
export const followStateStore = writable<FollowState>("off");
export const followRoleStore = writable<FollowRole>("leader");
function createFollowUsersStore() {
const { subscribe, update, set } = writable<number[]>([]);
return {
subscribe,
addFollowRequest(leader: number): void {
followStateStore.set("requesting");
followRoleStore.set("follower");
set([leader]);
},
addFollower(user: number): void {
update((followers) => {
followers.push(user);
return followers;
});
},
/**
* Removes the follower from the store.
* Will update followStateStore and followRoleStore if nobody is following anymore.
* @param user
*/
removeFollower(user: number): void {
update((followers) => {
const oldFollowerCount = followers.length;
followers = followers.filter((id) => id !== user);
if (followers.length === 0 && oldFollowerCount > 0) {
followStateStore.set("off");
followRoleStore.set("leader");
}
return followers;
});
},
stopFollowing(): void {
set([]);
followStateStore.set("off");
followRoleStore.set("leader");
},
};
}
export const followUsersStore = createFollowUsersStore();
/**
* This store contains the color of the follow group. It is derived from the ID of the leader.
*/
export const followUsersColorStore = derived(
[followStateStore, followRoleStore, followUsersStore],
([$followStateStore, $followRoleStore, $followUsersStore]) => {
if ($followStateStore !== "active") {
return undefined;
}
if ($followUsersStore.length === 0) {
return undefined;
}
let leaderId: number;
if ($followRoleStore === "leader") {
// Let's get my ID by a quite complicated way....
leaderId = gameManager.getCurrentGameScene().connection?.getUserId() ?? 0;
} else {
leaderId = $followUsersStore[0];
}
// Let's compute a random hue between 0 and 1 that varies enough to be interesting
const hue = ((leaderId * 197) % 255) / 255;
let { r, g, b } = getColorRgbFromHue(hue);
if ($followRoleStore === "follower") {
// Let's make the followers very slightly darker
r *= 0.9;
g *= 0.9;
b *= 0.9;
}
return (Math.round(r * 255) << 16) | (Math.round(g * 255) << 8) | Math.round(b * 255);
}
);

View file

@ -5,3 +5,5 @@ export const userMovingStore = writable(false);
export const requestVisitCardsStore = writable<string | null>(null);
export const userIsAdminStore = writable(false);
export const limitMapStore = writable(false);

View file

@ -360,39 +360,38 @@ const implementCorrectTrackBehavior = getNavigatorType() === NavigatorType.firef
/**
* Stops the camera from filming
*/
function applyCameraConstraints(currentStream: MediaStream | null, constraints: MediaTrackConstraints | boolean): void {
async function applyCameraConstraints(
currentStream: MediaStream | null,
constraints: MediaTrackConstraints | boolean
): Promise<void[]> {
if (!currentStream) {
return;
}
for (const track of currentStream.getVideoTracks()) {
toggleConstraints(track, constraints);
return [];
}
return Promise.all(currentStream.getVideoTracks().map((track) => toggleConstraints(track, constraints)));
}
/**
* Stops the microphone from listening
*/
function applyMicrophoneConstraints(
async function applyMicrophoneConstraints(
currentStream: MediaStream | null,
constraints: MediaTrackConstraints | boolean
): void {
): Promise<void[]> {
if (!currentStream) {
return;
}
for (const track of currentStream.getAudioTracks()) {
toggleConstraints(track, constraints);
return [];
}
return Promise.all(currentStream.getAudioTracks().map((track) => toggleConstraints(track, constraints)));
}
function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): void {
async function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): Promise<void> {
if (implementCorrectTrackBehavior) {
track.enabled = constraints !== false;
} else if (constraints === false) {
track.stop();
}
// @ts-ignore
if (typeof constraints !== "boolean" && constraints !== true) {
track.applyConstraints(constraints);
return track.applyConstraints(constraints);
}
}
@ -426,7 +425,7 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
// TODO: does it make sense to pop this error when retrying?
set({
type: "error",
error: e,
error: e instanceof Error ? e : new Error("An unknown error happened"),
});
// Let's try without video constraints
if (constraints.video !== false) {
@ -444,7 +443,7 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
console.info("Error. Unable to get microphone and/or camera access.", constraints, e);
set({
type: "error",
error: e,
error: e instanceof Error ? e : new Error("An unknown error happened"),
});
}
}
@ -473,8 +472,8 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
}
}
applyMicrophoneConstraints(currentStream, constraints.audio || false);
applyCameraConstraints(currentStream, constraints.video || false);
applyMicrophoneConstraints(currentStream, constraints.audio || false).catch((e) => console.error(e));
applyCameraConstraints(currentStream, constraints.video || false).catch((e) => console.error(e));
if (implementCorrectTrackBehavior) {
//on good navigators like firefox, we can instantiate the stream once and simply disable or enable the tracks as needed
@ -484,7 +483,12 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
type: "success",
stream: null,
});
initStream(constraints);
initStream(constraints).catch((e) => {
set({
type: "error",
error: e instanceof Error ? e : new Error("An unknown error happened"),
});
});
}
} else {
//on bad navigators like chrome, we have to stop the tracks when we mute and reinstantiate the stream when we need to unmute
@ -496,7 +500,12 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
});
} //we reemit the stream if it was muted just to be sure
else if (constraints.audio /* && !oldConstraints.audio*/ || (!oldConstraints.video && constraints.video)) {
initStream(constraints);
initStream(constraints).catch((e) => {
set({
type: "error",
error: e instanceof Error ? e : new Error("An unknown error happened"),
});
});
}
oldConstraints = {
video: !!constraints.video,

View file

@ -0,0 +1,4 @@
import { writable } from "svelte/store";
export const showLimitRoomModalStore = writable(false);
export const showShareLinkMapModalStore = writable(false);

View file

@ -0,0 +1,40 @@
import { writable } from "svelte/store";
export function createColorStore() {
const { subscribe, set } = writable<number | undefined>(undefined);
let color: number | undefined = undefined;
let focused: boolean = false;
const updateColor = () => {
if (focused) {
set(0xffff00);
} else {
set(color);
}
};
return {
subscribe,
pointerOver() {
focused = true;
updateColor();
},
pointerOut() {
focused = false;
updateColor();
},
setColor(newColor: number) {
color = newColor;
updateColor();
},
removeColor() {
color = undefined;
updateColor();
},
};
}

View file

@ -3,6 +3,7 @@ import type { PlayerInterface } from "../Phaser/Game/PlayerInterface";
import type { RoomConnection } from "../Connexion/RoomConnection";
import { getRandomColor } from "../WebRtc/ColorGenerator";
import { localUserStore } from "../Connexion/LocalUserStore";
import room from "../Api/iframe/room";
let idCount = 0;
@ -19,7 +20,8 @@ function createPlayersStore() {
connectToRoomConnection: (roomConnection: RoomConnection) => {
players = new Map<number, PlayerInterface>();
set(players);
roomConnection.onUserJoins((message) => {
// TODO: it would be cool to unsubscribe properly here
roomConnection.userJoinedMessageStream.subscribe((message) => {
update((users) => {
users.set(message.userId, {
userId: message.userId,
@ -33,9 +35,9 @@ function createPlayersStore() {
return users;
});
});
roomConnection.onUserLeft((userId) => {
roomConnection.userLeftMessageStream.subscribe((message) => {
update((users) => {
users.delete(userId);
users.delete(message.userId);
return users;
});
});

View file

@ -153,10 +153,10 @@ export const screenSharingLocalStreamStore = derived<Readable<MediaStreamConstra
console.info("Error. Unable to share screen.", e);
set({
type: "error",
error: e,
error: e instanceof Error ? e : new Error("An unknown error happened"),
});
}
})();
})().catch((e) => console.error(e));
}
);

View file

@ -1,5 +1,3 @@
import { writable } from "svelte/store";
import { createMessageStore } from "./MessageStore";
export const banMessageVisibleStore = writable(false);
export const banMessageContentStore = writable("");
export const banMessageStore = createMessageStore();

View file

@ -0,0 +1,29 @@
import { writable } from "svelte/store";
import { v4 as uuidv4 } from "uuid";
export interface Message {
id: string;
text: string;
}
/**
* A store that contains a list of messages to be displayed.
*/
export function createMessageStore() {
const { subscribe, update } = writable<Message[]>([]);
return {
subscribe,
addMessage: (text: string): void => {
update((messages: Message[]) => {
return [...messages, { id: uuidv4(), text }];
});
},
clearMessageById: (id: string): void => {
update((messages: Message[]) => {
messages = messages.filter((message) => message.id !== id);
return messages;
});
},
};
}

View file

@ -1,5 +1,3 @@
import { writable } from "svelte/store";
import { createMessageStore } from "./MessageStore";
export const textMessageVisibleStore = writable(false);
export const textMessageContentStore = writable("");
export const textMessageStore = createMessageStore();

View file

@ -7,7 +7,7 @@ class TouchScreenManager {
//found here: https://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript#4819886
detectTouchscreen(): boolean {
return "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
}
}

View file

@ -2,8 +2,7 @@ import type { Room } from "../Connexion/Room";
import { localUserStore } from "../Connexion/LocalUserStore";
export enum GameConnexionTypes {
anonymous = 1,
organization,
room = 1,
register,
empty,
unknown,
@ -19,10 +18,8 @@ class UrlManager {
return GameConnexionTypes.login;
} else if (url === "/jwt") {
return GameConnexionTypes.jwt;
} else if (url.includes("_/")) {
return GameConnexionTypes.anonymous;
} else if (url.includes("@/")) {
return GameConnexionTypes.organization;
} else if (url.includes("_/") || url.includes("*/") || url.includes("@/")) {
return GameConnexionTypes.room;
} else if (url.includes("register/")) {
return GameConnexionTypes.register;
} else if (url === "/") {
@ -41,7 +38,7 @@ class UrlManager {
if (window.location.pathname === room.id) return;
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
//use href to keep # value
localUserStore.setLastRoomUrl(room.href);
localUserStore.setLastRoomUrl(room.href).catch((e) => console.error(e));
const hash = window.location.hash;
const search = room.search.toString();
history.pushState({}, "WorkAdventure", room.id + (search ? "?" + search : "") + hash);

View file

@ -149,7 +149,7 @@ class CoWebsiteManager {
}
buttonCloseCoWebsites.blur();
this.closeCoWebsites();
this.closeCoWebsites().catch((e) => console.error(e));
});
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
@ -515,70 +515,72 @@ class CoWebsiteManager {
throw new Error("Too many we");
}
Promise.resolve(callback(this.cowebsiteBufferDom)).then((iframe) => {
iframe?.classList.add("pixel");
Promise.resolve(callback(this.cowebsiteBufferDom))
.then((iframe) => {
iframe?.classList.add("pixel");
if (!iframe.id) {
do {
iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
} while (this.getCoWebsiteById(iframe.id));
}
const onloadPromise = new Promise<void>((resolve) => {
iframe.onload = () => resolve();
});
const icon = this.generateCoWebsiteIcon(iframe);
const coWebsite = {
iframe,
icon,
position: position ?? this.coWebsites.length,
};
// Iframe management on mobile
icon.addEventListener("click", () => {
if (this.isSmallScreen()) {
this.moveRightPreviousCoWebsite(coWebsite, 0);
if (!iframe.id) {
do {
iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
} while (this.getCoWebsiteById(iframe.id));
}
});
this.coWebsites.push(coWebsite);
this.cowebsiteSubIconsDom.appendChild(icon);
const onloadPromise = new Promise<void>((resolve) => {
iframe.onload = () => resolve();
});
const onTimeoutPromise = new Promise<void>((resolve) => {
setTimeout(() => resolve(), 2000);
});
const icon = this.generateCoWebsiteIcon(iframe);
this.currentOperationPromise = this.currentOperationPromise
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
.then(() => {
if (coWebsite.position === 0) {
this.openMain();
if (widthPercent) {
this.widthPercent = widthPercent;
}
const coWebsite = {
iframe,
icon,
position: position ?? this.coWebsites.length,
};
setTimeout(() => {
this.fire();
// Iframe management on mobile
icon.addEventListener("click", () => {
if (this.isSmallScreen()) {
this.moveRightPreviousCoWebsite(coWebsite, 0);
}
});
this.coWebsites.push(coWebsite);
this.cowebsiteSubIconsDom.appendChild(icon);
const onTimeoutPromise = new Promise<void>((resolve) => {
setTimeout(() => resolve(), 2000);
});
this.currentOperationPromise = this.currentOperationPromise
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
.then(() => {
if (coWebsite.position === 0) {
this.openMain();
if (widthPercent) {
this.widthPercent = widthPercent;
}
setTimeout(() => {
this.fire();
position !== undefined
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
: this.moveCoWebsite(coWebsite, coWebsite.position);
}, animationTime);
} else {
position !== undefined
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
: this.moveCoWebsite(coWebsite, coWebsite.position);
}, animationTime);
} else {
position !== undefined
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
: this.moveCoWebsite(coWebsite, coWebsite.position);
}
}
return resolve(coWebsite);
})
.catch((err) => {
console.error("Error loadCoWebsite => ", err);
this.removeCoWebsiteFromStack(coWebsite);
return reject();
});
});
return resolve(coWebsite);
})
.catch((err) => {
console.error("Error loadCoWebsite => ", err);
this.removeCoWebsiteFromStack(coWebsite);
return reject();
});
})
.catch((e) => console.error("Error loadCoWebsite >=> ", e));
});
}
@ -603,20 +605,23 @@ class CoWebsiteManager {
return this.currentOperationPromise;
}
public closeJitsi() {
public async closeJitsi() {
const jitsi = this.searchJitsi();
if (jitsi) {
this.closeCoWebsite(jitsi);
return this.closeCoWebsite(jitsi);
}
}
public closeCoWebsites(): Promise<void> {
this.currentOperationPromise = this.currentOperationPromise.then(() => {
this.coWebsites.forEach((coWebsite: CoWebsite) => {
this.closeCoWebsite(coWebsite);
});
public async closeCoWebsites(): Promise<void> {
await this.currentOperationPromise;
const promises: Promise<void>[] = [];
this.coWebsites.forEach((coWebsite: CoWebsite) => {
promises.push(this.closeCoWebsite(coWebsite));
});
return this.currentOperationPromise;
await Promise.all(promises);
// TODO: this.currentOperationPromise does not point any more on the last promise
return;
}
public getGameSize(): { width: number; height: number } {

View file

@ -1,13 +1,29 @@
export function getRandomColor(): string {
const { r, g, b } = getColorRgbFromHue(Math.random());
return toHexa(r, g, b);
}
function toHexa(r: number, g: number, b: number): string {
return "#" + Math.floor(r * 256).toString(16) + Math.floor(g * 256).toString(16) + Math.floor(b * 256).toString(16);
}
export function getColorRgbFromHue(hue: number): { r: number; g: number; b: number } {
const golden_ratio_conjugate = 0.618033988749895;
let hue = Math.random();
hue += golden_ratio_conjugate;
hue %= 1;
return hsv_to_rgb(hue, 0.5, 0.95);
}
function stringToDouble(string: string): number {
let num = 1;
for (const char of string.split("")) {
num *= char.charCodeAt(0);
}
return (num % 255) / 255;
}
//todo: test this.
function hsv_to_rgb(hue: number, saturation: number, brightness: number): string {
function hsv_to_rgb(hue: number, saturation: number, brightness: number): { r: number; g: number; b: number } {
const h_i = Math.floor(hue * 6);
const f = hue * 6 - h_i;
const p = brightness * (1 - saturation);
@ -46,7 +62,11 @@ function hsv_to_rgb(hue: number, saturation: number, brightness: number): string
b = q;
break;
default:
throw "h_i cannot be " + h_i;
throw new Error("h_i cannot be " + h_i);
}
return "#" + Math.floor(r * 256).toString(16) + Math.floor(g * 256).toString(16) + Math.floor(b * 256).toString(16);
return {
r,
g,
b,
};
}

View file

@ -22,7 +22,7 @@ export function getNavigatorType(): NavigatorType {
} else if (window.navigator.userAgent.includes("Safari")) {
return NavigatorType.safari;
}
throw "Couldn't detect navigator type";
throw new Error("Couldn't detect navigator type");
}
export function isAndroid(): boolean {
return window.navigator.userAgent.includes("Android");

View file

@ -1,5 +1,5 @@
import { JITSI_URL } from "../Enum/EnvironmentVariable";
import { coWebsiteManager } from "./CoWebsiteManager";
import { CoWebsite, coWebsiteManager } from "./CoWebsiteManager";
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
import { get } from "svelte/store";
@ -140,8 +140,8 @@ class JitsiFactory {
interfaceConfig?: object,
jitsiUrl?: string,
jitsiWidth?: number
): void {
coWebsiteManager.addCoWebsite(
): Promise<CoWebsite> {
return coWebsiteManager.addCoWebsite(
async (cowebsiteDiv) => {
// Jitsi meet external API maintains some data in local storage
// which is sent via the appData URL parameter when joining a
@ -200,7 +200,7 @@ class JitsiFactory {
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
if (jitsiCoWebsite) {
coWebsiteManager.closeJitsi();
coWebsiteManager.closeJitsi().catch((e) => console.error(e));
}
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);

View file

@ -75,30 +75,32 @@ export class SimplePeer {
*/
private initialise() {
//receive signal by gemer
this.Connection.receiveWebrtcSignal((message: WebRtcSignalReceivedMessageInterface) => {
this.Connection.webRtcSignalToClientMessageStream.subscribe((message: WebRtcSignalReceivedMessageInterface) => {
this.receiveWebrtcSignal(message);
});
//receive signal by gemer
this.Connection.receiveWebrtcScreenSharingSignal((message: WebRtcSignalReceivedMessageInterface) => {
this.receiveWebrtcScreenSharingSignal(message);
});
this.Connection.webRtcScreenSharingSignalToClientMessageStream.subscribe(
(message: WebRtcSignalReceivedMessageInterface) => {
this.receiveWebrtcScreenSharingSignal(message);
}
);
mediaManager.showGameOverlay();
//receive message start
this.Connection.receiveWebrtcStart((message: UserSimplePeerInterface) => {
this.Connection.webRtcStartMessageStream.subscribe((message: UserSimplePeerInterface) => {
this.receiveWebrtcStart(message);
});
this.Connection.disconnectMessage((data: WebRtcDisconnectMessageInterface): void => {
this.Connection.webRtcDisconnectMessageStream.subscribe((data: WebRtcDisconnectMessageInterface): void => {
this.closeConnection(data.userId);
});
}
private receiveWebrtcStart(user: UserSimplePeerInterface): void {
this.Users.push(user);
// Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joints a group)
// Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joins a group)
// So we can receive a request we already had before. (which will abort at the first line of createPeerConnection)
// This would be symmetrical to the way we handle disconnection.
@ -121,7 +123,7 @@ export class SimplePeer {
peerConnection.destroy();
const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId);
if (!peerConnexionDeleted) {
throw "Error to delete peer connection";
throw new Error("Error to delete peer connection");
}
//return this.createPeerConnection(user, localStream);
} else {
@ -175,7 +177,7 @@ export class SimplePeer {
peerConnection.destroy();
const peerConnexionDeleted = this.PeerScreenSharingConnectionArray.delete(user.userId);
if (!peerConnexionDeleted) {
throw "Error to delete peer connection";
throw new Error("Error to delete peer connection");
}
this.createPeerConnection(user);
} else {
@ -227,7 +229,7 @@ export class SimplePeer {
const userIndex = this.Users.findIndex((user) => user.userId === userId);
if (userIndex < 0) {
throw "Couldn't delete user";
throw new Error("Couldn't delete user");
} else {
this.Users.splice(userIndex, 1);
}

View file

@ -9,7 +9,7 @@ import {
} from "./Api/Events/IframeEvent";
import chat from "./Api/iframe/chat";
import type { IframeCallback } from "./Api/iframe/IframeApiContribution";
import nav from "./Api/iframe/nav";
import nav, { CoWebsite } from "./Api/iframe/nav";
import controls from "./Api/iframe/controls";
import ui from "./Api/iframe/ui";
import sound from "./Api/iframe/sound";
@ -136,17 +136,17 @@ const wa = {
/**
* @deprecated Use WA.nav.openCoWebSite instead
*/
openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = ""): void {
openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = ""): Promise<CoWebsite> {
console.warn("Method WA.openCoWebSite is deprecated. Please use WA.nav.openCoWebSite instead");
nav.openCoWebSite(url, allowApi, allowPolicy);
return nav.openCoWebSite(url, allowApi, allowPolicy);
},
/**
* @deprecated Use WA.nav.closeCoWebSite instead
*/
closeCoWebSite(): void {
closeCoWebSite(): Promise<void> {
console.warn("Method WA.closeCoWebSite is deprecated. Please use WA.nav.closeCoWebSite instead");
nav.closeCoWebSite();
return nav.closeCoWebSite();
},
/**

View file

@ -1,6 +1,39 @@
//import Phaser from "phaser";
declare module "phaser3-rex-plugins/plugins/virtualjoystick.js" {
const content: any; // eslint-disable-line
export default content;
/*const content: any; // eslint-disable-line
export default content;*/
import GameObject = Phaser.GameObjects.GameObject;
import { Scene } from "phaser";
type CursorKey = {
isDown: boolean;
};
export type Direction = "left" | "right" | "up" | "down";
interface CursorKeys extends Record<Direction, CursorKey> {
left: CursorKey;
right: CursorKey;
up: CursorKey;
down: CursorKey;
}
class VirtualJoystick extends GameObject {
constructor(scene: Scene, config: unknown);
enable: boolean;
base: GameObjects.Image;
thumb: GameObjects.Image;
setRadius: (radius: number) => void;
y: number;
x: number;
forceX: number;
forceY: number;
visible: boolean;
createCursorKeys: () => CursorKeys;
}
export default VirtualJoystick;
}
declare module "phaser3-rex-plugins/plugins/gestures-plugin.js" {
const content: any; // eslint-disable-line

View file

@ -1,27 +1,3 @@
import type Phaser from "phaser";
export type CursorKey = {
isDown: boolean;
};
export type Direction = "left" | "right" | "up" | "down";
export interface CursorKeys extends Record<Direction, CursorKey> {
left: CursorKey;
right: CursorKey;
up: CursorKey;
down: CursorKey;
}
export interface IVirtualJoystick extends Phaser.GameObjects.GameObject {
y: number;
x: number;
forceX: number;
forceY: number;
visible: boolean;
createCursorKeys: () => CursorKeys;
}
export enum Easing {
Linear = "Linear",
QuadEaseIn = "Quad.easeIn",

View file

@ -1066,6 +1066,7 @@ div.action.danger p.action-body{
width: 100%;
height: 100%;
pointer-events: none;
user-select: none;
& > div {
position: relative;

View file

@ -1,22 +1,24 @@
import "jasmine";
import {PlayerMovement} from "../../../src/Phaser/Game/PlayerMovement";
import { PlayerMovement } from "../../../src/Phaser/Game/PlayerMovement";
describe("Interpolation / Extrapolation", () => {
it("should interpolate", () => {
const playerMovement = new PlayerMovement({
x: 100, y: 200
}, 42000,
const playerMovement = new PlayerMovement(
{
x: 100,
y: 200,
},
42000,
{
x: 200,
y: 100,
oldX: 100,
oldY: 200,
moving: true,
direction: "up"
direction: "up",
},
42200
);
);
expect(playerMovement.isOutdated(42100)).toBe(false);
expect(playerMovement.isOutdated(43000)).toBe(true);
@ -26,8 +28,8 @@ describe("Interpolation / Extrapolation", () => {
y: 150,
oldX: 100,
oldY: 200,
direction: 'up',
moving: true
direction: "up",
moving: true,
});
expect(playerMovement.getPosition(42200)).toEqual({
@ -35,8 +37,8 @@ describe("Interpolation / Extrapolation", () => {
y: 100,
oldX: 100,
oldY: 200,
direction: 'up',
moving: true
direction: "up",
moving: true,
});
expect(playerMovement.getPosition(42300)).toEqual({
@ -44,22 +46,25 @@ describe("Interpolation / Extrapolation", () => {
y: 50,
oldX: 100,
oldY: 200,
direction: 'up',
moving: true
direction: "up",
moving: true,
});
});
it("should not extrapolate if we stop", () => {
const playerMovement = new PlayerMovement({
x: 100, y: 200
}, 42000,
const playerMovement = new PlayerMovement(
{
x: 100,
y: 200,
},
42000,
{
x: 200,
y: 100,
oldX: 100,
oldY: 200,
moving: false,
direction: "up"
direction: "up",
},
42200
);
@ -69,22 +74,25 @@ describe("Interpolation / Extrapolation", () => {
y: 100,
oldX: 100,
oldY: 200,
direction: 'up',
moving: false
direction: "up",
moving: false,
});
});
it("should should keep moving until it stops", () => {
const playerMovement = new PlayerMovement({
x: 100, y: 200
}, 42000,
it("should keep moving until it stops", () => {
const playerMovement = new PlayerMovement(
{
x: 100,
y: 200,
},
42000,
{
x: 200,
y: 100,
oldX: 100,
oldY: 200,
moving: false,
direction: "up"
direction: "up",
},
42200
);
@ -94,8 +102,8 @@ describe("Interpolation / Extrapolation", () => {
y: 150,
oldX: 100,
oldY: 200,
direction: 'up',
moving: true
direction: "up",
moving: false,
});
});
})
});

View file

@ -2,13 +2,6 @@
# yarn lockfile v1
"@babel/code-frame@7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
version "7.12.13"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
@ -21,7 +14,7 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288"
integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==
"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13":
"@babel/highlight@^7.12.13":
version "7.14.0"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf"
integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==
@ -37,23 +30,35 @@
dependencies:
regenerator-runtime "^0.13.4"
"@cspotcode/source-map-consumer@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
"@cspotcode/source-map-support@0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5"
integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
dependencies:
"@cspotcode/source-map-consumer" "0.8.0"
"@discoveryjs/json-ext@^0.5.0":
version "0.5.3"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d"
integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==
"@eslint/eslintrc@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14"
integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==
"@eslint/eslintrc@^1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318"
integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==
dependencies:
ajv "^6.12.4"
debug "^4.1.1"
espree "^7.3.0"
globals "^12.1.0"
debug "^4.3.2"
espree "^9.2.0"
globals "^13.9.0"
ignore "^4.0.6"
import-fresh "^3.2.1"
js-yaml "^3.13.1"
js-yaml "^4.1.0"
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
@ -88,6 +93,20 @@
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.35"
"@humanwhocodes/config-array@^0.9.2":
version "0.9.2"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914"
integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
minimatch "^3.0.4"
"@humanwhocodes/object-schema@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@joeattardi/emoji-button@^4.6.2":
version "4.6.2"
resolved "https://registry.yarnpkg.com/@joeattardi/emoji-button/-/emoji-button-4.6.2.tgz#75baf4ce27324e4d6fb90292f8b248235f638ad0"
@ -131,11 +150,84 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
"@protobufjs/base64@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
dependencies:
"@protobufjs/aspromise" "^1.1.1"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/float@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
"@protobufjs/path@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
"@protobufjs/pool@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@sentry/types@^6.11.0":
version "6.12.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==
"@tsconfig/node10@^1.0.7":
version "1.0.8"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
"@tsconfig/node12@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
"@tsconfig/node14@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
"@tsconfig/node16@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
"@tsconfig/svelte@^1.0.10":
version "1.0.10"
resolved "https://registry.yarnpkg.com/@tsconfig/svelte/-/svelte-1.0.10.tgz#30ec7feeee0bdf38b12a50f0686f8a2e7b6b9dc0"
@ -239,16 +331,26 @@
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.7.4.tgz#99a49aa9a5f8dc86fc249ed13ed59552c6ce862d"
integrity sha512-L3FKeEwMm8e8hqGvt7cSesVmGtavpRyHV1FNDq+Pm5pS4x5eFmE70ZERXCSBWAiLQqXBcZRUrwV59FZLQl/GxQ==
"@types/json-schema@*", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
"@types/json-schema@^7.0.9":
version "7.0.9"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/long@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
"@types/mime@^1":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
@ -273,11 +375,26 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.0.tgz#d6fed7d6bc6854306da3dea1af9f874b00783e26"
integrity sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==
"@types/node@>=13.7.0":
version "17.0.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.5.tgz#57ca67ec4e57ad9e4ef5a6bab48a15387a1c83e0"
integrity sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw==
"@types/object-hash@^1.3.0":
version "1.3.4"
resolved "https://registry.yarnpkg.com/@types/object-hash/-/object-hash-1.3.4.tgz#079ba142be65833293673254831b5e3e847fe58b"
integrity sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prettier@^1.19.0":
version "1.19.1"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f"
integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==
"@types/pug@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.4.tgz#8772fcd0418e3cd2cc171555d73007415051f4b2"
@ -393,75 +510,75 @@
"@types/webpack-sources" "*"
source-map "^0.6.0"
"@typescript-eslint/eslint-plugin@^4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz#29d3c9c81f6200b1fd6d8454cfb007ba176cde80"
integrity sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==
"@typescript-eslint/eslint-plugin@^5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz#efd8668b3d6627c46ce722c2afe813928fe120a0"
integrity sha512-MIbeMy5qfLqtgs1hWd088k1hOuRsN9JrHUPwVVKCD99EOUqScd7SrwoZl4Gso05EAP9w1kvLWUVGJOVpRPkDPA==
dependencies:
"@typescript-eslint/experimental-utils" "4.23.0"
"@typescript-eslint/scope-manager" "4.23.0"
debug "^4.1.1"
"@typescript-eslint/experimental-utils" "5.6.0"
"@typescript-eslint/scope-manager" "5.6.0"
debug "^4.3.2"
functional-red-black-tree "^1.0.1"
lodash "^4.17.15"
regexpp "^3.0.0"
semver "^7.3.2"
tsutils "^3.17.1"
ignore "^5.1.8"
regexpp "^3.2.0"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/experimental-utils@4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz#f2059434cd6e5672bfeab2fb03b7c0a20622266f"
integrity sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==
"@typescript-eslint/experimental-utils@5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.6.0.tgz#f3a5960f2004abdcac7bb81412bafc1560841c23"
integrity sha512-VDoRf3Qj7+W3sS/ZBXZh3LBzp0snDLEgvp6qj0vOAIiAPM07bd5ojQ3CTzF/QFl5AKh7Bh1ycgj6lFBJHUt/DA==
dependencies:
"@types/json-schema" "^7.0.3"
"@typescript-eslint/scope-manager" "4.23.0"
"@typescript-eslint/types" "4.23.0"
"@typescript-eslint/typescript-estree" "4.23.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "5.6.0"
"@typescript-eslint/types" "5.6.0"
"@typescript-eslint/typescript-estree" "5.6.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/parser@^4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.23.0.tgz#239315d38e42e852bef43a4b0b01bef78f78911c"
integrity sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==
"@typescript-eslint/parser@^5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.6.0.tgz#11677324659641400d653253c03dcfbed468d199"
integrity sha512-YVK49NgdUPQ8SpCZaOpiq1kLkYRPMv9U5gcMrywzI8brtwZjr/tG3sZpuHyODt76W/A0SufNjYt9ZOgrC4tLIQ==
dependencies:
"@typescript-eslint/scope-manager" "4.23.0"
"@typescript-eslint/types" "4.23.0"
"@typescript-eslint/typescript-estree" "4.23.0"
debug "^4.1.1"
"@typescript-eslint/scope-manager" "5.6.0"
"@typescript-eslint/types" "5.6.0"
"@typescript-eslint/typescript-estree" "5.6.0"
debug "^4.3.2"
"@typescript-eslint/scope-manager@4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz#8792ef7eacac122e2ec8fa2d30a59b8d9a1f1ce4"
integrity sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==
"@typescript-eslint/scope-manager@5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.6.0.tgz#9dd7f007dc8f3a34cdff6f79f5eaab27ae05157e"
integrity sha512-1U1G77Hw2jsGWVsO2w6eVCbOg0HZ5WxL/cozVSTfqnL/eB9muhb8THsP0G3w+BB5xAHv9KptwdfYFAUfzcIh4A==
dependencies:
"@typescript-eslint/types" "4.23.0"
"@typescript-eslint/visitor-keys" "4.23.0"
"@typescript-eslint/types" "5.6.0"
"@typescript-eslint/visitor-keys" "5.6.0"
"@typescript-eslint/types@4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.23.0.tgz#da1654c8a5332f4d1645b2d9a1c64193cae3aa3b"
integrity sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==
"@typescript-eslint/types@5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.6.0.tgz#745cb1b59daadcc1f32f7be95f0f68accf38afdd"
integrity sha512-OIZffked7mXv4mXzWU5MgAEbCf9ecNJBKi+Si6/I9PpTaj+cf2x58h2oHW5/P/yTnPkKaayfjhLvx+crnl5ubA==
"@typescript-eslint/typescript-estree@4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz#0753b292097523852428a6f5a1aa8ccc1aae6cd9"
integrity sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==
"@typescript-eslint/typescript-estree@5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.6.0.tgz#dfbb19c9307fdd81bd9c650c67e8397821d7faf0"
integrity sha512-92vK5tQaE81rK7fOmuWMrSQtK1IMonESR+RJR2Tlc7w4o0MeEdjgidY/uO2Gobh7z4Q1hhS94Cr7r021fMVEeA==
dependencies:
"@typescript-eslint/types" "4.23.0"
"@typescript-eslint/visitor-keys" "4.23.0"
debug "^4.1.1"
globby "^11.0.1"
is-glob "^4.0.1"
semver "^7.3.2"
tsutils "^3.17.1"
"@typescript-eslint/types" "5.6.0"
"@typescript-eslint/visitor-keys" "5.6.0"
debug "^4.3.2"
globby "^11.0.4"
is-glob "^4.0.3"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/visitor-keys@4.23.0":
version "4.23.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz#7215cc977bd3b4ef22467b9023594e32f9e4e455"
integrity sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==
"@typescript-eslint/visitor-keys@5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.6.0.tgz#3e36509e103fe9713d8f035ac977235fd63cb6e6"
integrity sha512-1p7hDp5cpRFUyE3+lvA74egs+RWSgumrBpzBCDzfTFv0aQ7lIeay80yU0hIxgAhwQ6PcasW35kaOCyDOv6O/Ng==
dependencies:
"@typescript-eslint/types" "4.23.0"
eslint-visitor-keys "^2.0.0"
"@typescript-eslint/types" "5.6.0"
eslint-visitor-keys "^3.0.0"
"@webassemblyjs/ast@1.11.0":
version "1.11.0"
@ -624,16 +741,21 @@ acorn-jsx@^5.3.1:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
acorn@^7.4.0:
version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^8.2.1:
version "8.2.4"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.4.tgz#caba24b08185c3b56e3168e97d15ed17f4d31fd0"
integrity sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg==
acorn@^8.4.1, acorn@^8.6.0:
version "8.6.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895"
integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
@ -667,16 +789,6 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^8.0.1:
version "8.4.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.4.0.tgz#48984fdb2ce225cab15795f0772a8d85669075e4"
integrity sha512-7QD2l6+KBSLwf+7MuYocbWvRPdOu63/trReTLu2KFwkgctnub1auoF+Y1WYcm09CTM7quuscrzqmASaLHC/K4Q==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
uri-js "^4.2.2"
ansi-colors@^3.0.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
@ -714,6 +826,11 @@ ansi-regex@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@ -749,12 +866,10 @@ arg@^4.1.0:
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
arr-diff@^4.0.0:
version "4.0.0"
@ -1614,6 +1729,11 @@ cssesc@^3.0.0:
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
dataloader@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8"
integrity sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -1628,13 +1748,20 @@ debug@^3.1.1, debug@^3.2.6:
dependencies:
ms "^2.1.1"
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
debug@^4.3.2:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@ -1657,6 +1784,11 @@ dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
deep-copy-ts@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/deep-copy-ts/-/deep-copy-ts-0.5.0.tgz#b9493d8e2bae85ef7d659c16eb707c13efb84499"
integrity sha512-/3cgBcMkznRf5BM8wu6YWz3SQUkHzgh/v1TZFjevztLj9sMjFvNFBtpN4uUtPzw/rA/TldyD6c6LRL1zno4+YA==
deep-equal@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
@ -2041,12 +2173,17 @@ escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
eslint-plugin-svelte3@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.2.1.tgz#f0f24150ecea3061c38c69e282bea26dc3e660c6"
integrity sha512-YoBR9mLoKCjGghJ/gvpnFZKaMEu/VRcuxpSRS8KuozuEo7CdBH7bmBHa6FmMm0i4kJnOyx+PVsaptz96K6H/4Q==
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
@ -2054,79 +2191,83 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
eslint-scope@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153"
integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==
dependencies:
eslint-visitor-keys "^1.1.0"
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
dependencies:
eslint-visitor-keys "^2.0.0"
eslint-visitor-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint@^7.26.0:
version "7.26.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.26.0.tgz#d416fdcdcb3236cd8f282065312813f8c13982f6"
integrity sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==
eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2"
integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==
eslint@^8.4.1:
version "8.4.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.4.1.tgz#d6531bbf3e598dffd7c0c7d35ec52a0b30fdfa2d"
integrity sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.1"
"@eslint/eslintrc" "^1.0.5"
"@humanwhocodes/config-array" "^0.9.2"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.0.1"
debug "^4.3.2"
doctrine "^3.0.0"
enquirer "^2.3.5"
eslint-scope "^5.1.1"
eslint-utils "^2.1.0"
eslint-visitor-keys "^2.0.0"
espree "^7.3.1"
escape-string-regexp "^4.0.0"
eslint-scope "^7.1.0"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.1.0"
espree "^9.2.0"
esquery "^1.4.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.0.0"
glob-parent "^6.0.1"
globals "^13.6.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
js-yaml "^3.13.1"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
lodash "^4.17.21"
lodash.merge "^4.6.2"
minimatch "^3.0.4"
natural-compare "^1.4.0"
optionator "^0.9.1"
progress "^2.0.0"
regexpp "^3.1.0"
regexpp "^3.2.0"
semver "^7.2.1"
strip-ansi "^6.0.0"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
table "^6.0.4"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^7.3.0, espree@^7.3.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
espree@^9.2.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.2.0.tgz#c50814e01611c2d0f8bd4daa83c369eabba80dbc"
integrity sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==
dependencies:
acorn "^7.4.0"
acorn "^8.6.0"
acorn-jsx "^5.3.1"
eslint-visitor-keys "^1.3.0"
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
eslint-visitor-keys "^3.1.0"
esquery@^1.4.0:
version "1.4.0"
@ -2308,7 +2449,7 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
fast-deep-equal@^3.1.1:
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
@ -2462,10 +2603,10 @@ foreach@^2.0.5:
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
fork-ts-checker-webpack-plugin@^6.2.9:
version "6.2.9"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.2.9.tgz#08f51b685a48b09ab3ec079a8501762422443120"
integrity sha512-D/KSb/2VeiOy3odDerrC16WiZ1t5TLwiFfZmuDeTXcf3Km79M+f8nTCIdKkokxybybrgMcStbx0QpGaseePxnA==
fork-ts-checker-webpack-plugin@^6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e"
integrity sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==
dependencies:
"@babel/code-frame" "^7.8.3"
"@types/json-schema" "^7.0.5"
@ -2609,13 +2750,20 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0, glob-parent@~5.1.2:
glob-parent@^5.1.0, glob-parent@~5.1.0, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
glob-parent@^6.0.1:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
dependencies:
is-glob "^4.0.3"
glob-to-regexp@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
@ -2633,13 +2781,6 @@ glob@^7.0.3, glob@^7.1.3, glob@^7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^12.1.0:
version "12.4.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8"
integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==
dependencies:
type-fest "^0.8.1"
globals@^13.6.0:
version "13.8.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.8.0.tgz#3e20f504810ce87a8d72e55aecf8435b50f4c1b3"
@ -2647,10 +2788,17 @@ globals@^13.6.0:
dependencies:
type-fest "^0.20.2"
globby@^11.0.1:
version "11.0.3"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
globals@^13.9.0:
version "13.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e"
integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==
dependencies:
type-fest "^0.20.2"
globby@^11.0.4:
version "11.0.4"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
@ -2951,6 +3099,11 @@ ignore@^5.1.4:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
ignore@^5.1.8:
version "5.1.9"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb"
integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==
import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@ -3193,6 +3346,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-nan@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
@ -3374,13 +3534,12 @@ js-tokens@^4.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^3.13.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
argparse "^2.0.1"
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2"
@ -3397,11 +3556,6 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema-traverse@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
@ -3576,22 +3730,17 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.truncate@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21:
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -3624,6 +3773,11 @@ lokijs@^1.5.12:
resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.12.tgz#cb55b37009bdf09ee7952a6adddd555b893653a0"
integrity sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==
long@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
lower-case@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
@ -4027,6 +4181,11 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-hash@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==
object-inspect@^1.9.0:
version "1.10.3"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
@ -4519,6 +4678,11 @@ prettier-plugin-svelte@^2.5.0:
resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.5.0.tgz#7922534729f7febe59b4c56c3f5360539f0d8ab1"
integrity sha512-+iHY2uGChOngrgKielJUnqo74gIL/EO5oeWm8MftFWjEi213lq9QYTOwm1pv4lI1nA61tdgf80CF2i5zMcu1kw==
prettier@^2.0.2:
version "2.5.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
prettier@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
@ -4547,6 +4711,25 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
protobufjs@^6.8.8:
version "6.11.2"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b"
integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
"@protobufjs/codegen" "^2.0.4"
"@protobufjs/eventemitter" "^1.1.0"
"@protobufjs/fetch" "^1.1.0"
"@protobufjs/float" "^1.0.2"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/path" "^1.1.2"
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/long" "^4.0.1"
"@types/node" ">=13.7.0"
long "^4.0.0"
proxy-addr@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
@ -4762,10 +4945,10 @@ regexp.prototype.flags@^1.2.0:
call-bind "^1.0.2"
define-properties "^1.1.3"
regexpp@^3.0.0, regexpp@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
relateurl@^0.2.7:
version "0.2.7"
@ -4803,11 +4986,6 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
require-main-filename@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
@ -5291,7 +5469,7 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.5.17, source-map-support@~0.5.12, source-map-support@~0.5.19:
source-map-support@~0.5.12, source-map-support@~0.5.19:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
@ -5375,11 +5553,6 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies:
extend-shallow "^3.0.0"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
standardized-audio-context@^25.2.4:
version "25.2.4"
resolved "https://registry.yarnpkg.com/standardized-audio-context/-/standardized-audio-context-25.2.4.tgz#d64dbdd70615171ec90d1b7151a0d945af94cf3d"
@ -5512,6 +5685,13 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@ -5614,18 +5794,6 @@ tabbable@^4.0.0:
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261"
integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==
table@^6.0.4:
version "6.7.1"
resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"
integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==
dependencies:
ajv "^8.0.1"
lodash.clonedeep "^4.5.0"
lodash.truncate "^4.4.2"
slice-ansi "^4.0.0"
string-width "^4.2.0"
strip-ansi "^6.0.0"
tapable@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
@ -5735,28 +5903,63 @@ toidentifier@1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
ts-loader@^9.1.2:
version "9.1.2"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.1.2.tgz#ba9b9abb05a514e8ff825791a3f6fcf793272728"
integrity sha512-ryMgATvLLl+z8zQvdlm6Pep0slmwxFWIEnq/5VdiLVjqQXnFJgO+qNLGIIP+d2N2jsFZ9MibZCVDb2bSp7OmEA==
ts-loader@^9.2.6:
version "9.2.6"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.6.tgz#9937c4dd0a1e3dbbb5e433f8102a6601c6615d74"
integrity sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^5.0.0"
micromatch "^4.0.0"
semver "^7.3.4"
ts-node@^9.1.1:
version "9.1.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
ts-node@^10.4.0:
version "10.4.0"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7"
integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==
dependencies:
"@cspotcode/source-map-support" "0.7.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.17"
yn "3.1.1"
ts-poet@^4.5.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/ts-poet/-/ts-poet-4.6.1.tgz#015dc823d726655af9f095c900f84ed7c60e2dd3"
integrity sha512-DXJ+mBJIDp+jiaUgB4N5I/sczHHDU2FWacdbDNVAVS4Mh4hb7ckpvUWVW7m7/nAOcjR0r4Wt+7AoO7FeJKExfA==
dependencies:
"@types/prettier" "^1.19.0"
lodash "^4.17.15"
prettier "^2.0.2"
ts-proto-descriptors@^1.2.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/ts-proto-descriptors/-/ts-proto-descriptors-1.3.1.tgz#760ebaaa19475b03662f7b358ffea45b9c5348f5"
integrity sha512-Cybb3fqceMwA6JzHdC32dIo8eVGVmXrM6TWhdk1XQVVHT/6OQqk0ioyX1dIdu3rCIBhRmWUhUE4HsyK+olmgMw==
dependencies:
long "^4.0.0"
protobufjs "^6.8.8"
ts-proto@^1.96.0:
version "1.96.0"
resolved "https://registry.yarnpkg.com/ts-proto/-/ts-proto-1.96.0.tgz#63768d7da533b337aee84db065dd66773bd4cac9"
integrity sha512-fKwaGzi8EOCU9xwmcXK917jj1WhFdLbFkPRawQ+5CAZM9eSXr/mpkz/yEctXCiuei364z6jAB2Odb64KCDFTPQ==
dependencies:
"@types/object-hash" "^1.3.0"
dataloader "^1.4.0"
object-hash "^1.3.1"
protobufjs "^6.8.8"
ts-poet "^4.5.0"
ts-proto-descriptors "^1.2.1"
tsconfig-paths@^3.9.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
@ -5777,7 +5980,7 @@ tslib@^2.0.0, tslib@^2.0.3, tslib@^2.2.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
tsutils@^3.17.1:
tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
@ -5821,11 +6024,6 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@ -5839,10 +6037,10 @@ typescript@*:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
typescript@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
typescript@^4.5.3:
version "4.5.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.3.tgz#afaa858e68c7103317d89eb90c5d8906268d353c"
integrity sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==
unbox-primitive@^1.0.0:
version "1.0.1"