Merge branch 'develop' of github.com:thecodingmachine/workadventure
This commit is contained in:
commit
5cc573ac49
@ -1,15 +1,15 @@
|
|||||||
// lib/server.ts
|
// lib/server.ts
|
||||||
import App from "./src/App";
|
import App from "./src/App";
|
||||||
import grpc from "grpc";
|
import grpc from "grpc";
|
||||||
import {roomManager} from "./src/RoomManager";
|
import { roomManager } from "./src/RoomManager";
|
||||||
import {IRoomManagerServer, RoomManagerService} from "./src/Messages/generated/messages_grpc_pb";
|
import { IRoomManagerServer, RoomManagerService } from "./src/Messages/generated/messages_grpc_pb";
|
||||||
import {HTTP_PORT, GRPC_PORT} from "./src/Enum/EnvironmentVariable";
|
import { HTTP_PORT, GRPC_PORT } from "./src/Enum/EnvironmentVariable";
|
||||||
|
|
||||||
App.listen(HTTP_PORT, () => console.log(`WorkAdventure HTTP API starting on port %d!`, HTTP_PORT))
|
App.listen(HTTP_PORT, () => console.log(`WorkAdventure HTTP API starting on port %d!`, HTTP_PORT));
|
||||||
|
|
||||||
const server = new grpc.Server();
|
const server = new grpc.Server();
|
||||||
server.addService<IRoomManagerServer>(RoomManagerService, roomManager);
|
server.addService<IRoomManagerServer>(RoomManagerService, roomManager);
|
||||||
|
|
||||||
server.bind(`0.0.0.0:${GRPC_PORT}`, grpc.ServerCredentials.createInsecure());
|
server.bind(`0.0.0.0:${GRPC_PORT}`, grpc.ServerCredentials.createInsecure());
|
||||||
server.start();
|
server.start();
|
||||||
console.log('WorkAdventure HTTP/2 API starting on port %d!', GRPC_PORT);
|
console.log("WorkAdventure HTTP/2 API starting on port %d!", GRPC_PORT);
|
||||||
|
@ -73,7 +73,7 @@ services:
|
|||||||
DEBUG: "socket:*"
|
DEBUG: "socket:*"
|
||||||
STARTUP_COMMAND_1: yarn install
|
STARTUP_COMMAND_1: yarn install
|
||||||
# wait for files generated by "messages" container to exists
|
# wait for files generated by "messages" container to exists
|
||||||
STARTUP_COMMAND_2: while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
STARTUP_COMMAND_2: sleep 5; while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
||||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||||
SECRET_KEY: yourSecretKey
|
SECRET_KEY: yourSecretKey
|
||||||
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
||||||
@ -132,7 +132,7 @@ services:
|
|||||||
DEBUG: "*"
|
DEBUG: "*"
|
||||||
STARTUP_COMMAND_1: yarn install
|
STARTUP_COMMAND_1: yarn install
|
||||||
# wait for files generated by "messages" container to exists
|
# wait for files generated by "messages" container to exists
|
||||||
STARTUP_COMMAND_2: while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
STARTUP_COMMAND_2: sleep 5; while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
||||||
SECRET_KEY: yourSecretKey
|
SECRET_KEY: yourSecretKey
|
||||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||||
ALLOW_ARTILLERY: "true"
|
ALLOW_ARTILLERY: "true"
|
||||||
|
@ -35,7 +35,6 @@ module.exports = {
|
|||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
"@typescript-eslint/no-explicit-any": "error",
|
||||||
// TODO: remove those ignored rules and write a stronger code!
|
// TODO: remove those ignored rules and write a stronger code!
|
||||||
"@typescript-eslint/no-floating-promises": "off",
|
|
||||||
"@typescript-eslint/no-unsafe-call": "off",
|
"@typescript-eslint/no-unsafe-call": "off",
|
||||||
"@typescript-eslint/restrict-plus-operands": "off",
|
"@typescript-eslint/restrict-plus-operands": "off",
|
||||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||||
|
@ -18,64 +18,84 @@ class AnalyticsClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
identifyUser(uuid: string, email: string | null) {
|
identifyUser(uuid: string, email: string | null) {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.identify(uuid, { uuid, email, wa: true });
|
?.then((posthog) => {
|
||||||
});
|
posthog.identify(uuid, { uuid, email, wa: true });
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
loggedWithSso() {
|
loggedWithSso() {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-logged-sso");
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-logged-sso");
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
loggedWithToken() {
|
loggedWithToken() {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-logged-token");
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-logged-token");
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
enteredRoom(roomId: string, roomGroup: string | null) {
|
enteredRoom(roomId: string, roomGroup: string | null) {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("$pageView", { roomId, roomGroup });
|
?.then((posthog) => {
|
||||||
posthog.capture("enteredRoom");
|
posthog.capture("$pageView", { roomId, roomGroup });
|
||||||
});
|
posthog.capture("enteredRoom");
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
openedMenu() {
|
openedMenu() {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-opened-menu");
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-opened-menu");
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
launchEmote(emote: string) {
|
launchEmote(emote: string) {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-emote-launch", { emote });
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-emote-launch", { emote });
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
enteredJitsi(roomName: string, roomId: string) {
|
enteredJitsi(roomName: string, roomId: string) {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-entered-jitsi", { roomName, roomId });
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-entered-jitsi", { roomName, roomId });
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
validationName() {
|
validationName() {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-name-validation");
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-name-validation");
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
validationWoka(scene: string) {
|
validationWoka(scene: string) {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-woka-validation", { scene });
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-woka-validation", { scene });
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
validationVideo() {
|
validationVideo() {
|
||||||
this.posthogPromise?.then((posthog) => {
|
this.posthogPromise
|
||||||
posthog.capture("wa-video-validation");
|
?.then((posthog) => {
|
||||||
});
|
posthog.capture("wa-video-validation");
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const analyticsClient = new AnalyticsClient();
|
export const analyticsClient = new AnalyticsClient();
|
||||||
|
@ -26,7 +26,7 @@ export class ActionMessage {
|
|||||||
this.message = actionMessageOptions.message;
|
this.message = actionMessageOptions.message;
|
||||||
this.type = actionMessageOptions.type ?? "message";
|
this.type = actionMessageOptions.type ?? "message";
|
||||||
this.callback = actionMessageOptions.callback;
|
this.callback = actionMessageOptions.callback;
|
||||||
this.create();
|
this.create().catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async create() {
|
private async create() {
|
||||||
|
@ -95,7 +95,7 @@ export function createState(target: "global" | "player"): WorkadventureStateComm
|
|||||||
set(target: WorkadventureStateCommands, p: PropertyKey, value: unknown, receiver: unknown): boolean {
|
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.
|
// 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.
|
// 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;
|
return true;
|
||||||
},
|
},
|
||||||
has(target: WorkadventureStateCommands, p: PropertyKey): boolean {
|
has(target: WorkadventureStateCommands, p: PropertyKey): boolean {
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
import { chatVisibilityStore } from "../Stores/ChatStore";
|
import { chatVisibilityStore } from "../Stores/ChatStore";
|
||||||
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
|
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
|
||||||
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
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 AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||||
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
||||||
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
||||||
@ -136,6 +139,16 @@
|
|||||||
<HelpCameraSettingsPopup />
|
<HelpCameraSettingsPopup />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $showLimitRoomModalStore}
|
||||||
|
<div>
|
||||||
|
<LimitRoomModal />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if $showShareLinkMapModalStore}
|
||||||
|
<div>
|
||||||
|
<ShareLinkMapModal />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $requestVisitCardsStore}
|
{#if $requestVisitCardsStore}
|
||||||
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
HTMLAudioPlayer.loop = get(audioManagerVolumeStore).loop;
|
HTMLAudioPlayer.loop = get(audioManagerVolumeStore).loop;
|
||||||
HTMLAudioPlayer.volume = get(audioManagerVolumeStore).volume;
|
HTMLAudioPlayer.volume = get(audioManagerVolumeStore).volume;
|
||||||
HTMLAudioPlayer.muted = get(audioManagerVolumeStore).muted;
|
HTMLAudioPlayer.muted = get(audioManagerVolumeStore).muted;
|
||||||
HTMLAudioPlayer.play();
|
void HTMLAudioPlayer.play();
|
||||||
});
|
});
|
||||||
unsubscriberVolumeStore = audioManagerVolumeStore.subscribe((audioManager: audioManagerVolume) => {
|
unsubscriberVolumeStore = audioManagerVolumeStore.subscribe((audioManager: audioManagerVolume) => {
|
||||||
const reduceVolume = audioManager.talking && audioManager.decreaseWhileTalking;
|
const reduceVolume = audioManager.talking && audioManager.decreaseWhileTalking;
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
uploadAudioActive = true;
|
uploadAudioActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function send() {
|
async function send(): Promise<void> {
|
||||||
if (inputSendTextActive) {
|
if (inputSendTextActive) {
|
||||||
handleSendText.sendTextMessage(broadcastToWorld);
|
return handleSendText.sendTextMessage(broadcastToWorld);
|
||||||
}
|
}
|
||||||
if (uploadAudioActive) {
|
if (uploadAudioActive) {
|
||||||
handleSendAudio.sendAudioMessage(broadcastToWorld);
|
return handleSendAudio.sendAudioMessage(broadcastToWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -21,12 +21,12 @@
|
|||||||
<div class="guest-main">
|
<div class="guest-main">
|
||||||
<section class="container-overflow">
|
<section class="container-overflow">
|
||||||
<section class="share-url not-mobile">
|
<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()} />
|
<input type="text" readonly id="input-share-link" value={location.toString()} />
|
||||||
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
|
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
|
||||||
</section>
|
</section>
|
||||||
<section class="is-mobile">
|
<section class="is-mobile">
|
||||||
<h3>Share the link of the room !</h3>
|
<h3>Share the link of the room!</h3>
|
||||||
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
||||||
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import logoWA from "../images/menu.svg"
|
import logoWA from "../images/menu.svg"
|
||||||
import logoTalk from "../images/chat.svg"
|
import logoTalk from "../images/chat.svg"
|
||||||
|
import logoInvite from "../images/logo-invite-pixel.png";
|
||||||
|
import logoRegister from "../images/logo-register-pixel.png";
|
||||||
import { menuVisiblilityStore } from "../../Stores/MenuStore";
|
import { menuVisiblilityStore } from "../../Stores/MenuStore";
|
||||||
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
||||||
|
import { limitMapStore } from "../../Stores/GameStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
|
||||||
|
import { showShareLinkMapModalStore } from "../../Stores/ModalStore";
|
||||||
|
|
||||||
function showMenu() {
|
function showMenu() {
|
||||||
menuVisiblilityStore.set(!get(menuVisiblilityStore));
|
menuVisiblilityStore.set(!get(menuVisiblilityStore));
|
||||||
@ -11,17 +16,33 @@
|
|||||||
function showChat() {
|
function showChat() {
|
||||||
chatVisibilityStore.set(true);
|
chatVisibilityStore.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function register() {
|
||||||
|
window.open(`${ADMIN_URL}/second-step-register`, "_self");
|
||||||
|
}
|
||||||
|
function showInvite() {
|
||||||
|
showShareLinkMapModalStore.set(true);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window />
|
<svelte:window />
|
||||||
|
|
||||||
<main class="menuIcon">
|
<main class="menuIcon">
|
||||||
<span class="nes-btn is-dark">
|
{#if $limitMapStore}
|
||||||
<img src={logoWA} alt="open menu" on:click|preventDefault={showMenu} />
|
<span class="nes-btn is-dark">
|
||||||
</span>
|
<img src={logoInvite} alt="open menu" on:click|preventDefault={showInvite} />
|
||||||
<span class="nes-btn is-dark">
|
</span>
|
||||||
<img src={logoTalk} alt="open menu" on:click|preventDefault={showChat} />
|
<span class="nes-btn is-dark">
|
||||||
</span>
|
<img src={logoRegister} alt="open menu" on:click|preventDefault={register} />
|
||||||
|
</span>
|
||||||
|
{:else}
|
||||||
|
<span class="nes-btn is-dark">
|
||||||
|
<img src={logoWA} alt="open menu" on:click|preventDefault={showMenu} />
|
||||||
|
</span>
|
||||||
|
<span class="nes-btn is-dark">
|
||||||
|
<img src={logoTalk} alt="open menu" on:click|preventDefault={showChat} />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -41,10 +41,10 @@
|
|||||||
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
function logOut() {
|
async function logOut() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
loginSceneVisibleStore.set(true);
|
loginSceneVisibleStore.set(true);
|
||||||
connectionManager.logout();
|
return connectionManager.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProfileUrl() {
|
function getProfileUrl() {
|
||||||
|
@ -33,9 +33,9 @@
|
|||||||
const body = HtmlUtils.querySelectorOrFail("body");
|
const body = HtmlUtils.querySelectorOrFail("body");
|
||||||
if (body) {
|
if (body) {
|
||||||
if (document.fullscreenElement !== null && !fullscreen) {
|
if (document.fullscreenElement !== null && !fullscreen) {
|
||||||
document.exitFullscreen();
|
document.exitFullscreen().catch((e) => console.error(e));
|
||||||
} else {
|
} else {
|
||||||
body.requestFullscreen();
|
body.requestFullscreen().catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
localUserStore.setFullscreen(fullscreen);
|
localUserStore.setFullscreen(fullscreen);
|
||||||
}
|
}
|
||||||
@ -45,14 +45,16 @@
|
|||||||
if (Notification.permission === "granted") {
|
if (Notification.permission === "granted") {
|
||||||
localUserStore.setNotification(notification ? "granted" : "denied");
|
localUserStore.setNotification(notification ? "granted" : "denied");
|
||||||
} else {
|
} else {
|
||||||
Notification.requestPermission().then((response) => {
|
Notification.requestPermission()
|
||||||
if (response === "granted") {
|
.then((response) => {
|
||||||
localUserStore.setNotification(notification ? "granted" : "denied");
|
if (response === "granted") {
|
||||||
} else {
|
localUserStore.setNotification(notification ? "granted" : "denied");
|
||||||
localUserStore.setNotification("denied");
|
} else {
|
||||||
notification = false;
|
localUserStore.setNotification("denied");
|
||||||
}
|
notification = false;
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
front/src/Components/Modal/LimitRoomModal.svelte
Normal file
47
front/src/Components/Modal/LimitRoomModal.svelte
Normal 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>
|
90
front/src/Components/Modal/ShareLinkMapModal.svelte
Normal file
90
front/src/Components/Modal/ShareLinkMapModal.svelte
Normal 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>
|
@ -6,12 +6,11 @@
|
|||||||
import type { Unsubscriber } from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import { playersStore } from "../../Stores/PlayersStore";
|
import { playersStore } from "../../Stores/PlayersStore";
|
||||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
import { GameConnexionTypes } from "../../Url/UrlManager";
|
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
let blockActive = true;
|
let blockActive = true;
|
||||||
let reportActive = !blockActive;
|
let reportActive = !blockActive;
|
||||||
let anonymous: boolean = false;
|
let disableReport: boolean = false;
|
||||||
let userUUID: string | undefined = playersStore.getPlayerById(get(showReportScreenStore).userId)?.userUuid;
|
let userUUID: string | undefined = playersStore.getPlayerById(get(showReportScreenStore).userId)?.userUuid;
|
||||||
let userName = "No name";
|
let userName = "No name";
|
||||||
let unsubscriber: Unsubscriber;
|
let unsubscriber: Unsubscriber;
|
||||||
@ -26,7 +25,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
anonymous = connectionManager.getConnexionType === GameConnexionTypes.anonymous;
|
disableReport = !connectionManager.currentRoom?.canReport ?? true;
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@ -65,7 +64,7 @@
|
|||||||
<button type="button" class="nes-btn" on:click|preventDefault={close}>X</button>
|
<button type="button" class="nes-btn" on:click|preventDefault={close}>X</button>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section class="report-menu-action {anonymous ? 'hidden' : ''}">
|
<section class="report-menu-action {disableReport ? 'hidden' : ''}">
|
||||||
<section class="justify-center">
|
<section class="justify-center">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
audio.play();
|
audio.play().catch((e) => console.error(e));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,20 +1,26 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
import { userIsAdminStore, limitMapStore } from "../../Stores/GameStore";
|
||||||
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
|
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
const upgradeLink = ADMIN_URL + "/pricing";
|
const upgradeLink = ADMIN_URL + "/pricing";
|
||||||
|
const registerLink = ADMIN_URL + "/second-step-register";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="warningMain" transition:fly={{ y: -200, duration: 500 }}>
|
<main class="warningMain" transition:fly={{ y: -200, duration: 500 }}>
|
||||||
<h2>Warning!</h2>
|
|
||||||
{#if $userIsAdminStore}
|
{#if $userIsAdminStore}
|
||||||
|
<h2>Warning!</h2>
|
||||||
<p>
|
<p>
|
||||||
This world is close to its limit!. You can upgrade its capacity <a href={upgradeLink} target="_blank"
|
This world is close to its limit!. You can upgrade its capacity <a href={upgradeLink} target="_blank"
|
||||||
>here</a
|
>here</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
{:else if $limitMapStore}
|
||||||
|
<p>
|
||||||
|
This map is available for 2 days. You can register your domain <a href={registerLink}>here</a>!
|
||||||
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
|
<h2>Warning!</h2>
|
||||||
<p>This world is close to its limit!</p>
|
<p>This world is close to its limit!</p>
|
||||||
{/if}
|
{/if}
|
||||||
</main>
|
</main>
|
||||||
|
BIN
front/src/Components/images/logo-invite-pixel.png
Normal file
BIN
front/src/Components/images/logo-invite-pixel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
front/src/Components/images/logo-register-pixel.png
Normal file
BIN
front/src/Components/images/logo-register-pixel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 977 B |
@ -8,13 +8,15 @@ import { CharacterTexture, LocalUser } from "./LocalUser";
|
|||||||
import { Room } from "./Room";
|
import { Room } from "./Room";
|
||||||
import { _ServiceWorker } from "../Network/ServiceWorker";
|
import { _ServiceWorker } from "../Network/ServiceWorker";
|
||||||
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
||||||
import { userIsConnected } from "../Stores/MenuStore";
|
import { userIsConnected, warningContainerStore } from "../Stores/MenuStore";
|
||||||
import { analyticsClient } from "../Administration/AnalyticsClient";
|
import { analyticsClient } from "../Administration/AnalyticsClient";
|
||||||
import { gameManager } from "../Phaser/Game/GameManager";
|
import { gameManager } from "../Phaser/Game/GameManager";
|
||||||
import { axiosWithRetry } from "./AxiosUtils";
|
import { axiosWithRetry } from "./AxiosUtils";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
|
import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
|
||||||
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
||||||
|
import { limitMapStore } from "../Stores/GameStore";
|
||||||
|
import { showLimitRoomModalStore } from "../Stores/ModalStore";
|
||||||
|
|
||||||
class ConnectionManager {
|
class ConnectionManager {
|
||||||
private localUser!: LocalUser;
|
private localUser!: LocalUser;
|
||||||
@ -153,11 +155,7 @@ class ConnectionManager {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
urlManager.pushRoomIdToUrl(this._currentRoom);
|
urlManager.pushRoomIdToUrl(this._currentRoom);
|
||||||
} else if (
|
} else if (connexionType === GameConnexionTypes.room || connexionType === GameConnexionTypes.empty) {
|
||||||
connexionType === GameConnexionTypes.organization ||
|
|
||||||
connexionType === GameConnexionTypes.anonymous ||
|
|
||||||
connexionType === GameConnexionTypes.empty
|
|
||||||
) {
|
|
||||||
this.authToken = localUserStore.getAuthToken();
|
this.authToken = localUserStore.getAuthToken();
|
||||||
|
|
||||||
let roomPath: string;
|
let roomPath: string;
|
||||||
@ -189,7 +187,7 @@ class ConnectionManager {
|
|||||||
|
|
||||||
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
|
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
|
||||||
//use href to keep # value
|
//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.
|
//todo: add here some kind of warning if authToken has expired.
|
||||||
if (!this.authToken && !this._currentRoom.authenticationMandatory) {
|
if (!this.authToken && !this._currentRoom.authenticationMandatory) {
|
||||||
@ -238,6 +236,17 @@ class ConnectionManager {
|
|||||||
analyticsClient.identifyUser(this.localUser.uuid, this.localUser.email);
|
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();
|
this.serviceWorker = new _ServiceWorker();
|
||||||
return Promise.resolve(this._currentRoom);
|
return Promise.resolve(this._currentRoom);
|
||||||
}
|
}
|
||||||
@ -302,7 +311,7 @@ class ConnectionManager {
|
|||||||
this.reconnectingTimeout = setTimeout(() => {
|
this.reconnectingTimeout = setTimeout(() => {
|
||||||
//todo: allow a way to break recursion?
|
//todo: allow a way to break recursion?
|
||||||
//todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely.
|
//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)
|
(connection) => resolve(connection)
|
||||||
);
|
);
|
||||||
}, 4000 + Math.floor(Math.random() * 2000));
|
}, 4000 + Math.floor(Math.random() * 2000));
|
||||||
|
@ -136,13 +136,12 @@ class LocalUserStore {
|
|||||||
return localStorage.getItem(ignoreFollowRequests) === "true";
|
return localStorage.getItem(ignoreFollowRequests) === "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
setLastRoomUrl(roomUrl: string): void {
|
async setLastRoomUrl(roomUrl: string): Promise<void> {
|
||||||
localStorage.setItem(lastRoomUrl, roomUrl.toString());
|
localStorage.setItem(lastRoomUrl, roomUrl.toString());
|
||||||
if ("caches" in window) {
|
if ("caches" in window) {
|
||||||
caches.open(cacheAPIIndex).then((cache) => {
|
const cache = await caches.open(cacheAPIIndex);
|
||||||
const stringResponse = new Response(JSON.stringify({ roomUrl }));
|
const stringResponse = new Response(JSON.stringify({ roomUrl }));
|
||||||
cache.put(`/${lastRoomUrl}`, stringResponse);
|
await cache.put(`/${lastRoomUrl}`, stringResponse);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getLastRoomUrl(): string {
|
getLastRoomUrl(): string {
|
||||||
|
@ -18,7 +18,10 @@ export interface RoomRedirect {
|
|||||||
|
|
||||||
export class Room {
|
export class Room {
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
public readonly isPublic: boolean;
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
private readonly isPublic: boolean;
|
||||||
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS;
|
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS;
|
||||||
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
|
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
|
||||||
private _mapUrl: string | undefined;
|
private _mapUrl: string | undefined;
|
||||||
@ -27,6 +30,8 @@ export class Room {
|
|||||||
private readonly _search: URLSearchParams;
|
private readonly _search: URLSearchParams;
|
||||||
private _contactPage: string | undefined;
|
private _contactPage: string | undefined;
|
||||||
private _group: string | null = null;
|
private _group: string | null = null;
|
||||||
|
private _expireOn: Date | undefined;
|
||||||
|
private _canReport: boolean = false;
|
||||||
|
|
||||||
private constructor(private roomUrl: URL) {
|
private constructor(private roomUrl: URL) {
|
||||||
this.id = roomUrl.pathname;
|
this.id = roomUrl.pathname;
|
||||||
@ -34,7 +39,7 @@ export class Room {
|
|||||||
if (this.id.startsWith("/")) {
|
if (this.id.startsWith("/")) {
|
||||||
this.id = this.id.substr(1);
|
this.id = this.id.substr(1);
|
||||||
}
|
}
|
||||||
if (this.id.startsWith("_/")) {
|
if (this.id.startsWith("_/") || this.id.startsWith("*/")) {
|
||||||
this.isPublic = true;
|
this.isPublic = true;
|
||||||
} else if (this.id.startsWith("@/")) {
|
} else if (this.id.startsWith("@/")) {
|
||||||
this.isPublic = false;
|
this.isPublic = false;
|
||||||
@ -121,6 +126,10 @@ export class Room {
|
|||||||
data.authenticationMandatory != null ? data.authenticationMandatory : DISABLE_ANONYMOUS;
|
data.authenticationMandatory != null ? data.authenticationMandatory : DISABLE_ANONYMOUS;
|
||||||
this._iframeAuthentication = data.iframeAuthentication || OPID_LOGIN_SCREEN_PROVIDER;
|
this._iframeAuthentication = data.iframeAuthentication || OPID_LOGIN_SCREEN_PROVIDER;
|
||||||
this._contactPage = data.contactPage || CONTACT_URL;
|
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);
|
return new MapDetail(data.mapUrl, data.textures);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
||||||
@ -143,6 +152,8 @@ export class Room {
|
|||||||
* Instance name is:
|
* Instance name is:
|
||||||
* - In a public URL: the second part of the URL ( _/[instance]/map.json)
|
* - In a public URL: the second part of the URL ( _/[instance]/map.json)
|
||||||
* - In a private URL: [organizationId/worldId]
|
* - In a private URL: [organizationId/worldId]
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
public getInstance(): string {
|
public getInstance(): string {
|
||||||
if (this.instance !== undefined) {
|
if (this.instance !== undefined) {
|
||||||
@ -150,7 +161,7 @@ export class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.isPublic) {
|
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 + '"');
|
if (!match) throw new Error('Could not extract instance from "' + this.id + '"');
|
||||||
this.instance = match[1];
|
this.instance = match[1];
|
||||||
return this.instance;
|
return this.instance;
|
||||||
@ -223,4 +234,12 @@ export class Room {
|
|||||||
get group(): string | null {
|
get group(): string | null {
|
||||||
return this._group;
|
return this._group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get expireOn(): Date | undefined {
|
||||||
|
return this._expireOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canReport(): boolean {
|
||||||
|
return this._canReport;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,7 +352,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "tokenExpiredMessage": {
|
case "tokenExpiredMessage": {
|
||||||
connectionManager.logout();
|
connectionManager.logout().catch((e) => console.error(e));
|
||||||
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
|
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,15 @@ export class Companion extends Container {
|
|||||||
this.companionName = name;
|
this.companionName = name;
|
||||||
this._pictureStore = writable(undefined);
|
this._pictureStore = writable(undefined);
|
||||||
|
|
||||||
texturePromise.then((resource) => {
|
texturePromise
|
||||||
this.addResource(resource);
|
.then((resource) => {
|
||||||
this.invisible = false;
|
this.addResource(resource);
|
||||||
return this.getSnapshot().then((htmlImageElementSrc) => {
|
this.invisible = false;
|
||||||
this._pictureStore.set(htmlImageElementSrc);
|
return this.getSnapshot().then((htmlImageElementSrc) => {
|
||||||
});
|
this._pictureStore.set(htmlImageElementSrc);
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
|
||||||
this.scene.physics.world.enableBody(this);
|
this.scene.physics.world.enableBody(this);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./Co
|
|||||||
|
|
||||||
export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => {
|
export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => {
|
||||||
COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => {
|
COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => {
|
||||||
lazyLoadCompanionResource(loader, resource.name);
|
lazyLoadCompanionResource(loader, resource.name).catch((e) => console.error(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
return COMPANION_RESOURCES;
|
return COMPANION_RESOURCES;
|
||||||
|
@ -72,9 +72,11 @@ export class Loader {
|
|||||||
if (this.loadingText) {
|
if (this.loadingText) {
|
||||||
this.loadingText.destroy();
|
this.loadingText.destroy();
|
||||||
}
|
}
|
||||||
promiseLoadLogoTexture.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
promiseLoadLogoTexture
|
||||||
resLoadingImage.destroy();
|
.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
||||||
});
|
resLoadingImage.destroy();
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
this.progress.destroy();
|
this.progress.destroy();
|
||||||
this.progressContainer.destroy();
|
this.progressContainer.destroy();
|
||||||
if (this.scene instanceof DirtyScene) {
|
if (this.scene instanceof DirtyScene) {
|
||||||
|
@ -127,7 +127,7 @@ export class GameMapPropertiesListener {
|
|||||||
.then((coWebsite) => {
|
.then((coWebsite) => {
|
||||||
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
||||||
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
|
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite);
|
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => console.error(e));
|
||||||
this.coWebsitesOpenByLayer.delete(layer);
|
this.coWebsitesOpenByLayer.delete(layer);
|
||||||
this.coWebsitesActionTriggerByLayer.delete(layer);
|
this.coWebsitesActionTriggerByLayer.delete(layer);
|
||||||
} else {
|
} else {
|
||||||
@ -136,7 +136,8 @@ export class GameMapPropertiesListener {
|
|||||||
state: OpenCoWebsiteState.OPENED,
|
state: OpenCoWebsiteState.OPENED,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
|
||||||
layoutManagerActionStore.removeAction(actionUuid);
|
layoutManagerActionStore.removeAction(actionUuid);
|
||||||
};
|
};
|
||||||
@ -236,7 +237,7 @@ export class GameMapPropertiesListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (coWebsiteOpen.coWebsite !== undefined) {
|
if (coWebsiteOpen.coWebsite !== undefined) {
|
||||||
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite);
|
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.coWebsitesOpenByLayer.delete(layer);
|
this.coWebsitesOpenByLayer.delete(layer);
|
||||||
|
@ -243,7 +243,7 @@ export class GameScene extends DirtyScene {
|
|||||||
const textures = localUser?.textures;
|
const textures = localUser?.textures;
|
||||||
if (textures) {
|
if (textures) {
|
||||||
for (const texture of textures) {
|
for (const texture of textures) {
|
||||||
loadCustomTexture(this.load, texture);
|
loadCustomTexture(this.load, texture).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ export class GameScene extends DirtyScene {
|
|||||||
this.load.on(
|
this.load.on(
|
||||||
"filecomplete-tilemapJSON-" + this.MapUrlFile,
|
"filecomplete-tilemapJSON-" + this.MapUrlFile,
|
||||||
(key: string, type: string, data: unknown) => {
|
(key: string, type: string, data: unknown) => {
|
||||||
this.onMapLoad(data);
|
this.onMapLoad(data).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -294,14 +294,14 @@ export class GameScene extends DirtyScene {
|
|||||||
this.load.on(
|
this.load.on(
|
||||||
"filecomplete-tilemapJSON-" + this.MapUrlFile,
|
"filecomplete-tilemapJSON-" + this.MapUrlFile,
|
||||||
(key: string, type: string, data: unknown) => {
|
(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.
|
// 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.
|
// 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)) {
|
if (this.cache.tilemap.exists(this.MapUrlFile)) {
|
||||||
const data = this.cache.tilemap.get(this.MapUrlFile);
|
const data = this.cache.tilemap.get(this.MapUrlFile);
|
||||||
this.onMapLoad(data);
|
this.onMapLoad(data).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -322,7 +322,7 @@ export class GameScene extends DirtyScene {
|
|||||||
});
|
});
|
||||||
this.load.scenePlugin("AnimatedTiles", AnimatedTiles, "animatedTiles", "animatedTiles");
|
this.load.scenePlugin("AnimatedTiles", AnimatedTiles, "animatedTiles", "animatedTiles");
|
||||||
this.load.on("filecomplete-tilemapJSON-" + this.MapUrlFile, (key: string, type: string, data: unknown) => {
|
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
|
//TODO strategy to add access token
|
||||||
this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile);
|
this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile);
|
||||||
@ -330,7 +330,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.
|
// 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)) {
|
if (this.cache.tilemap.exists(this.MapUrlFile)) {
|
||||||
const data = this.cache.tilemap.get(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
|
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@ -408,21 +408,23 @@ export class GameScene extends DirtyScene {
|
|||||||
this.load.on("complete", () => {
|
this.load.on("complete", () => {
|
||||||
// FIXME: the factory might fail because the resources might not be loaded yet...
|
// 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
|
// We would need to add a loader ended event in addition to the createPromise
|
||||||
this.createPromise.then(async () => {
|
this.createPromise
|
||||||
itemFactory.create(this);
|
.then(async () => {
|
||||||
|
itemFactory.create(this);
|
||||||
|
|
||||||
const roomJoinedAnswer = await this.connectionAnswerPromise;
|
const roomJoinedAnswer = await this.connectionAnswerPromise;
|
||||||
|
|
||||||
for (const object of objectsOfType) {
|
for (const object of objectsOfType) {
|
||||||
// TODO: we should pass here a factory to create sprites (maybe?)
|
// TODO: we should pass here a factory to create sprites (maybe?)
|
||||||
|
|
||||||
// Do we have a state for this object?
|
// Do we have a state for this object?
|
||||||
const state = roomJoinedAnswer.items[ object.id ];
|
const state = roomJoinedAnswer.items[object.id];
|
||||||
|
|
||||||
const actionableItem = itemFactory.factory(this, object, state);
|
const actionableItem = itemFactory.factory(this, object, state);
|
||||||
this.actionableItems.set(actionableItem.getId(), actionableItem);
|
this.actionableItems.set(actionableItem.getId(), actionableItem);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,11 +505,11 @@ export class GameScene extends DirtyScene {
|
|||||||
if (exitSceneUrl !== undefined) {
|
if (exitSceneUrl !== undefined) {
|
||||||
this.loadNextGame(
|
this.loadNextGame(
|
||||||
Room.getRoomPathFromExitSceneUrl(exitSceneUrl, window.location.toString(), this.MapUrlFile)
|
Room.getRoomPathFromExitSceneUrl(exitSceneUrl, window.location.toString(), this.MapUrlFile)
|
||||||
);
|
).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
const exitUrl = this.getExitUrl(layer);
|
const exitUrl = this.getExitUrl(layer);
|
||||||
if (exitUrl !== undefined) {
|
if (exitUrl !== undefined) {
|
||||||
this.loadNextGameFromExitUrl(exitUrl);
|
this.loadNextGameFromExitUrl(exitUrl).catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layer.type === "objectgroup") {
|
if (layer.type === "objectgroup") {
|
||||||
@ -547,7 +549,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.gameMap.exitUrls.forEach((exitUrl) => {
|
this.gameMap.exitUrls.forEach((exitUrl) => {
|
||||||
this.loadNextGameFromExitUrl(exitUrl);
|
this.loadNextGameFromExitUrl(exitUrl).catch((e) => console.error(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.startPositionCalculator = new StartPositionCalculator(
|
this.startPositionCalculator = new StartPositionCalculator(
|
||||||
@ -568,7 +570,10 @@ export class GameScene extends DirtyScene {
|
|||||||
mediaManager.setUserInputManager(this.userInputManager);
|
mediaManager.setUserInputManager(this.userInputManager);
|
||||||
|
|
||||||
if (localUserStore.getFullscreen()) {
|
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
|
//notify game manager can to create currentUser in map
|
||||||
@ -674,9 +679,16 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises]).then(() => {
|
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises])
|
||||||
this.scene.wake();
|
.then(() => {
|
||||||
});
|
this.scene.wake();
|
||||||
|
})
|
||||||
|
.catch((e) =>
|
||||||
|
console.error(
|
||||||
|
"Some scripts failed to load ot the connection failed to establish to WorkAdventure server",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -876,7 +888,8 @@ export class GameScene extends DirtyScene {
|
|||||||
// iframeListener.sendLeaveLayerEvent(layer.name);
|
// iframeListener.sendLeaveLayerEvent(layer.name);
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
});
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: into dedicated classes
|
//todo: into dedicated classes
|
||||||
@ -929,7 +942,7 @@ export class GameScene extends DirtyScene {
|
|||||||
if (newValue) {
|
if (newValue) {
|
||||||
this.onMapExit(
|
this.onMapExit(
|
||||||
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
|
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
|
||||||
);
|
).catch((e) => console.error(e));
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layoutManagerActionStore.removeAction("roomAccessDenied");
|
layoutManagerActionStore.removeAction("roomAccessDenied");
|
||||||
@ -938,7 +951,9 @@ export class GameScene extends DirtyScene {
|
|||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
|
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()));
|
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString())).catch((e) =>
|
||||||
|
console.error(e)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layoutManagerActionStore.removeAction("roomAccessDenied");
|
layoutManagerActionStore.removeAction("roomAccessDenied");
|
||||||
@ -1128,7 +1143,9 @@ export class GameScene extends DirtyScene {
|
|||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
iframeListener.playSoundStream.subscribe((playSoundEvent) => {
|
iframeListener.playSoundStream.subscribe((playSoundEvent) => {
|
||||||
const url = new URL(playSoundEvent.url, this.MapUrlFile);
|
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));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1166,7 +1183,7 @@ export class GameScene extends DirtyScene {
|
|||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
iframeListener.loadSoundStream.subscribe((loadSoundEvent) => {
|
iframeListener.loadSoundStream.subscribe((loadSoundEvent) => {
|
||||||
const url = new URL(loadSoundEvent.url, this.MapUrlFile);
|
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));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1177,11 +1194,15 @@ export class GameScene extends DirtyScene {
|
|||||||
);
|
);
|
||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
iframeListener.loadPageStream.subscribe((url: string) => {
|
iframeListener.loadPageStream.subscribe((url: string) => {
|
||||||
this.loadNextGameFromExitUrl(url).then(() => {
|
this.loadNextGameFromExitUrl(url)
|
||||||
this.events.once(EVENT_TYPE.POST_UPDATE, () => {
|
.then(() => {
|
||||||
this.onMapExit(Room.getRoomPathFromExitUrl(url, window.location.toString()));
|
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;
|
let scriptedBubbleSprite: Sprite;
|
||||||
@ -1450,7 +1471,7 @@ export class GameScene extends DirtyScene {
|
|||||||
propertyValue: string | number | boolean | undefined
|
propertyValue: string | number | boolean | undefined
|
||||||
): void {
|
): void {
|
||||||
if (propertyName === GameMapProperties.EXIT_URL && typeof propertyValue === "string") {
|
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);
|
this.gameMap.setLayerProperty(layerName, propertyName, propertyValue);
|
||||||
}
|
}
|
||||||
@ -1535,7 +1556,7 @@ export class GameScene extends DirtyScene {
|
|||||||
|
|
||||||
public cleanupClosingScene(): void {
|
public cleanupClosingScene(): void {
|
||||||
// stop playing audio, close any open website, stop any open Jitsi
|
// stop playing audio, close any open website, stop any open Jitsi
|
||||||
coWebsiteManager.closeCoWebsites();
|
coWebsiteManager.closeCoWebsites().catch((e) => console.error(e));
|
||||||
// Stop the script, if any
|
// Stop the script, if any
|
||||||
const scripts = this.getScriptUrls(this.mapFile);
|
const scripts = this.getScriptUrls(this.mapFile);
|
||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
@ -2077,10 +2098,11 @@ export class GameScene extends DirtyScene {
|
|||||||
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||||
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
|
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
|
||||||
|
|
||||||
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth);
|
|
||||||
|
|
||||||
const jitsiKeepCircle = allProps.get("jitsiKeepCircle") as boolean | false;
|
const jitsiKeepCircle = allProps.get("jitsiKeepCircle") as boolean | false;
|
||||||
|
|
||||||
|
jitsiFactory
|
||||||
|
.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth)
|
||||||
|
.catch((e) => console.error(e));
|
||||||
this.connection?.setSilent(true);
|
this.connection?.setSilent(true);
|
||||||
mediaManager.hideGameOverlay();
|
mediaManager.hideGameOverlay();
|
||||||
|
|
||||||
|
@ -40,19 +40,21 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
this.loadCustomSceneSelectCharacters().then((bodyResourceDescriptions) => {
|
this.loadCustomSceneSelectCharacters()
|
||||||
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
.then((bodyResourceDescriptions) => {
|
||||||
if (
|
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
||||||
bodyResourceDescription.level == undefined ||
|
if (
|
||||||
bodyResourceDescription.level < 0 ||
|
bodyResourceDescription.level == undefined ||
|
||||||
bodyResourceDescription.level > 5
|
bodyResourceDescription.level < 0 ||
|
||||||
) {
|
bodyResourceDescription.level > 5
|
||||||
throw "Texture level is null";
|
) {
|
||||||
}
|
throw "Texture level is null";
|
||||||
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
|
}
|
||||||
});
|
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
|
||||||
this.lazyloadingAttempt = true;
|
});
|
||||||
});
|
this.lazyloadingAttempt = true;
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
|
||||||
this.layers = loadAllLayers(this.load);
|
this.layers = loadAllLayers(this.load);
|
||||||
this.lazyloadingAttempt = false;
|
this.lazyloadingAttempt = false;
|
||||||
|
@ -41,12 +41,14 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
this.loadSelectSceneCharacters().then((bodyResourceDescriptions) => {
|
this.loadSelectSceneCharacters()
|
||||||
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
.then((bodyResourceDescriptions) => {
|
||||||
this.playerModels.push(bodyResourceDescription);
|
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
||||||
});
|
this.playerModels.push(bodyResourceDescription);
|
||||||
this.lazyloadingAttempt = true;
|
});
|
||||||
});
|
this.lazyloadingAttempt = true;
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(e));
|
||||||
this.playerModels = loadAllDefaultModels(this.load);
|
this.playerModels = loadAllDefaultModels(this.load);
|
||||||
this.lazyloadingAttempt = false;
|
this.lazyloadingAttempt = false;
|
||||||
|
|
||||||
|
@ -5,3 +5,5 @@ export const userMovingStore = writable(false);
|
|||||||
export const requestVisitCardsStore = writable<string | null>(null);
|
export const requestVisitCardsStore = writable<string | null>(null);
|
||||||
|
|
||||||
export const userIsAdminStore = writable(false);
|
export const userIsAdminStore = writable(false);
|
||||||
|
|
||||||
|
export const limitMapStore = writable(false);
|
||||||
|
@ -360,32 +360,27 @@ const implementCorrectTrackBehavior = getNavigatorType() === NavigatorType.firef
|
|||||||
/**
|
/**
|
||||||
* Stops the camera from filming
|
* 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) {
|
if (!currentStream) {
|
||||||
return;
|
return [];
|
||||||
}
|
|
||||||
for (const track of currentStream.getVideoTracks()) {
|
|
||||||
toggleConstraints(track, constraints).catch((e) =>
|
|
||||||
console.error("Error while setting new camera constraints:", e)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return Promise.all(currentStream.getVideoTracks().map((track) => toggleConstraints(track, constraints)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the microphone from listening
|
* Stops the microphone from listening
|
||||||
*/
|
*/
|
||||||
function applyMicrophoneConstraints(
|
async function applyMicrophoneConstraints(
|
||||||
currentStream: MediaStream | null,
|
currentStream: MediaStream | null,
|
||||||
constraints: MediaTrackConstraints | boolean
|
constraints: MediaTrackConstraints | boolean
|
||||||
): void {
|
): Promise<void[]> {
|
||||||
if (!currentStream) {
|
if (!currentStream) {
|
||||||
return;
|
return [];
|
||||||
}
|
|
||||||
for (const track of currentStream.getAudioTracks()) {
|
|
||||||
toggleConstraints(track, constraints).catch((e) =>
|
|
||||||
console.error("Error while setting new audio constraints:", e)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return Promise.all(currentStream.getAudioTracks().map((track) => toggleConstraints(track, constraints)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): Promise<void> {
|
async function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): Promise<void> {
|
||||||
@ -477,8 +472,8 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyMicrophoneConstraints(currentStream, constraints.audio || false);
|
applyMicrophoneConstraints(currentStream, constraints.audio || false).catch((e) => console.error(e));
|
||||||
applyCameraConstraints(currentStream, constraints.video || false);
|
applyCameraConstraints(currentStream, constraints.video || false).catch((e) => console.error(e));
|
||||||
|
|
||||||
if (implementCorrectTrackBehavior) {
|
if (implementCorrectTrackBehavior) {
|
||||||
//on good navigators like firefox, we can instantiate the stream once and simply disable or enable the tracks as needed
|
//on good navigators like firefox, we can instantiate the stream once and simply disable or enable the tracks as needed
|
||||||
|
4
front/src/Stores/ModalStore.ts
Normal file
4
front/src/Stores/ModalStore.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const showLimitRoomModalStore = writable(false);
|
||||||
|
export const showShareLinkMapModalStore = writable(false);
|
@ -156,7 +156,7 @@ export const screenSharingLocalStreamStore = derived<Readable<MediaStreamConstra
|
|||||||
error: e instanceof Error ? e : new Error("An unknown error happened"),
|
error: e instanceof Error ? e : new Error("An unknown error happened"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})().catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import type { Room } from "../Connexion/Room";
|
|||||||
import { localUserStore } from "../Connexion/LocalUserStore";
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||||
|
|
||||||
export enum GameConnexionTypes {
|
export enum GameConnexionTypes {
|
||||||
anonymous = 1,
|
room = 1,
|
||||||
organization,
|
|
||||||
register,
|
register,
|
||||||
empty,
|
empty,
|
||||||
unknown,
|
unknown,
|
||||||
@ -19,10 +18,8 @@ class UrlManager {
|
|||||||
return GameConnexionTypes.login;
|
return GameConnexionTypes.login;
|
||||||
} else if (url === "/jwt") {
|
} else if (url === "/jwt") {
|
||||||
return GameConnexionTypes.jwt;
|
return GameConnexionTypes.jwt;
|
||||||
} else if (url.includes("_/")) {
|
} else if (url.includes("_/") || url.includes("*/") || url.includes("@/")) {
|
||||||
return GameConnexionTypes.anonymous;
|
return GameConnexionTypes.room;
|
||||||
} else if (url.includes("@/")) {
|
|
||||||
return GameConnexionTypes.organization;
|
|
||||||
} else if (url.includes("register/")) {
|
} else if (url.includes("register/")) {
|
||||||
return GameConnexionTypes.register;
|
return GameConnexionTypes.register;
|
||||||
} else if (url === "/") {
|
} else if (url === "/") {
|
||||||
@ -41,7 +38,7 @@ class UrlManager {
|
|||||||
if (window.location.pathname === room.id) return;
|
if (window.location.pathname === room.id) return;
|
||||||
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
|
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
|
||||||
//use href to keep # value
|
//use href to keep # value
|
||||||
localUserStore.setLastRoomUrl(room.href);
|
localUserStore.setLastRoomUrl(room.href).catch((e) => console.error(e));
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
const search = room.search.toString();
|
const search = room.search.toString();
|
||||||
history.pushState({}, "WorkAdventure", room.id + (search ? "?" + search : "") + hash);
|
history.pushState({}, "WorkAdventure", room.id + (search ? "?" + search : "") + hash);
|
||||||
|
@ -155,7 +155,7 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonCloseCoWebsites.blur();
|
buttonCloseCoWebsites.blur();
|
||||||
this.closeCoWebsites();
|
this.closeCoWebsites().catch((e) => console.error(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
||||||
@ -523,71 +523,62 @@ class CoWebsiteManager {
|
|||||||
throw new Error("Too many we");
|
throw new Error("Too many we");
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.resolve(callback(this.cowebsiteBufferDom)).then((iframe) => {
|
Promise.resolve(callback(this.cowebsiteBufferDom))
|
||||||
iframe?.classList.add("pixel");
|
.then((iframe) => {
|
||||||
|
iframe?.classList.add("pixel");
|
||||||
|
|
||||||
if (!iframe.id) {
|
if (!iframe.id) {
|
||||||
do {
|
do {
|
||||||
iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
|
iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
|
||||||
} while (this.getCoWebsiteById(iframe.id));
|
} while (this.getCoWebsiteById(iframe.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const onloadPromise = new Promise<void>((resolve) => {
|
const onloadPromise = new Promise<void>((resolve) => {
|
||||||
iframe.onload = () => resolve();
|
iframe.onload = () => resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
// const icon = this.generateCoWebsiteIcon(iframe);
|
const coWebsite = {
|
||||||
|
iframe,
|
||||||
|
state : CoWebsiteState.OPENED,
|
||||||
|
position: position ?? this.coWebsites.length,
|
||||||
|
};
|
||||||
|
|
||||||
const coWebsite = {
|
this.coWebsites.push(coWebsite);
|
||||||
iframe,
|
|
||||||
// icon,
|
|
||||||
state : CoWebsiteState.OPENED,
|
|
||||||
position: position ?? this.coWebsites.length,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Iframe management on mobile
|
const onTimeoutPromise = new Promise<void>((resolve) => {
|
||||||
// icon.addEventListener("click", () => {
|
setTimeout(() => resolve(), 2000);
|
||||||
// if (this.isSmallScreen()) {
|
});
|
||||||
// this.moveRightPreviousCoWebsite(coWebsite, 0);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
this.coWebsites.push(coWebsite);
|
this.currentOperationPromise = this.currentOperationPromise
|
||||||
// this.cowebsiteSubIconsDom.appendChild(icon);
|
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
||||||
|
.then(() => {
|
||||||
|
if (coWebsite.position === 0) {
|
||||||
|
this.openMain();
|
||||||
|
if (widthPercent) {
|
||||||
|
this.widthPercent = widthPercent;
|
||||||
|
}
|
||||||
|
|
||||||
const onTimeoutPromise = new Promise<void>((resolve) => {
|
setTimeout(() => {
|
||||||
setTimeout(() => resolve(), 2000);
|
this.fire();
|
||||||
});
|
position !== undefined
|
||||||
|
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
|
||||||
this.currentOperationPromise = this.currentOperationPromise
|
: this.moveCoWebsite(coWebsite, coWebsite.position);
|
||||||
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
}, animationTime);
|
||||||
.then(() => {
|
} else {
|
||||||
if (coWebsite.position === 0) {
|
|
||||||
this.openMain();
|
|
||||||
if (widthPercent) {
|
|
||||||
this.widthPercent = widthPercent;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.fire();
|
|
||||||
position !== undefined
|
position !== undefined
|
||||||
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
|
? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position)
|
||||||
: this.moveCoWebsite(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);
|
return resolve(coWebsite);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Error loadCoWebsite => ", err);
|
console.error("Error loadCoWebsite => ", err);
|
||||||
this.removeCoWebsiteFromStack(coWebsite);
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
return reject();
|
return reject();
|
||||||
});
|
});
|
||||||
});
|
})
|
||||||
|
.catch((e) => console.error("Error loadCoWebsite >=> ", e));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,17 +603,21 @@ class CoWebsiteManager {
|
|||||||
return this.currentOperationPromise;
|
return this.currentOperationPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeJitsi() {
|
public async closeJitsi() {
|
||||||
const jitsi = this.searchJitsi();
|
const jitsi = this.searchJitsi();
|
||||||
if (jitsi) {
|
if (jitsi) {
|
||||||
this.closeCoWebsite(jitsi);
|
return this.closeCoWebsite(jitsi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeCoWebsites(): Promise<void> {
|
public closeCoWebsites(): Promise<void> {
|
||||||
this.currentOperationPromise = this.currentOperationPromise.then(() => {
|
this.currentOperationPromise = this.currentOperationPromise.then(() => {
|
||||||
|
const promises: Promise<void>[] = [];
|
||||||
this.coWebsites.forEach((coWebsite: CoWebsite) => {
|
this.coWebsites.forEach((coWebsite: CoWebsite) => {
|
||||||
this.closeCoWebsite(coWebsite);
|
promises.push(this.closeCoWebsite(coWebsite));
|
||||||
|
});
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
return;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return this.currentOperationPromise;
|
return this.currentOperationPromise;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
||||||
import { coWebsiteManager } from "./CoWebsiteManager";
|
import { CoWebsite, coWebsiteManager } from "./CoWebsiteManager";
|
||||||
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
@ -143,8 +143,8 @@ class JitsiFactory {
|
|||||||
interfaceConfig?: object,
|
interfaceConfig?: object,
|
||||||
jitsiUrl?: string,
|
jitsiUrl?: string,
|
||||||
jitsiWidth?: number
|
jitsiWidth?: number
|
||||||
): void {
|
): Promise<CoWebsite> {
|
||||||
coWebsiteManager.addCoWebsite(
|
return coWebsiteManager.addCoWebsite(
|
||||||
async (cowebsiteDiv) => {
|
async (cowebsiteDiv) => {
|
||||||
// Jitsi meet external API maintains some data in local storage
|
// Jitsi meet external API maintains some data in local storage
|
||||||
// which is sent via the appData URL parameter when joining a
|
// which is sent via the appData URL parameter when joining a
|
||||||
@ -203,7 +203,7 @@ class JitsiFactory {
|
|||||||
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
|
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
|
||||||
|
|
||||||
if (jitsiCoWebsite) {
|
if (jitsiCoWebsite) {
|
||||||
coWebsiteManager.closeJitsi();
|
coWebsiteManager.closeJitsi().catch((e) => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
|
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
} from "./Api/Events/IframeEvent";
|
} from "./Api/Events/IframeEvent";
|
||||||
import chat from "./Api/iframe/chat";
|
import chat from "./Api/iframe/chat";
|
||||||
import type { IframeCallback } from "./Api/iframe/IframeApiContribution";
|
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 controls from "./Api/iframe/controls";
|
||||||
import ui from "./Api/iframe/ui";
|
import ui from "./Api/iframe/ui";
|
||||||
import sound from "./Api/iframe/sound";
|
import sound from "./Api/iframe/sound";
|
||||||
@ -136,17 +136,17 @@ const wa = {
|
|||||||
/**
|
/**
|
||||||
* @deprecated Use WA.nav.openCoWebSite instead
|
* @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");
|
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
|
* @deprecated Use WA.nav.closeCoWebSite instead
|
||||||
*/
|
*/
|
||||||
closeCoWebSite(): void {
|
closeCoWebSite(): Promise<void> {
|
||||||
console.warn("Method WA.closeCoWebSite is deprecated. Please use WA.nav.closeCoWebSite instead");
|
console.warn("Method WA.closeCoWebSite is deprecated. Please use WA.nav.closeCoWebSite instead");
|
||||||
nav.closeCoWebSite();
|
return nav.closeCoWebSite();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
import "jasmine";
|
import "jasmine";
|
||||||
import {PlayerMovement} from "../../../src/Phaser/Game/PlayerMovement";
|
import { PlayerMovement } from "../../../src/Phaser/Game/PlayerMovement";
|
||||||
|
|
||||||
describe("Interpolation / Extrapolation", () => {
|
describe("Interpolation / Extrapolation", () => {
|
||||||
it("should interpolate", () => {
|
it("should interpolate", () => {
|
||||||
const playerMovement = new PlayerMovement({
|
const playerMovement = new PlayerMovement(
|
||||||
x: 100, y: 200
|
{
|
||||||
}, 42000,
|
x: 100,
|
||||||
|
y: 200,
|
||||||
|
},
|
||||||
|
42000,
|
||||||
{
|
{
|
||||||
x: 200,
|
x: 200,
|
||||||
y: 100,
|
y: 100,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
moving: true,
|
moving: true,
|
||||||
direction: "up"
|
direction: "up",
|
||||||
},
|
},
|
||||||
42200
|
42200
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
expect(playerMovement.isOutdated(42100)).toBe(false);
|
expect(playerMovement.isOutdated(42100)).toBe(false);
|
||||||
expect(playerMovement.isOutdated(43000)).toBe(true);
|
expect(playerMovement.isOutdated(43000)).toBe(true);
|
||||||
@ -26,8 +28,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
y: 150,
|
y: 150,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: "up",
|
||||||
moving: true
|
moving: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(playerMovement.getPosition(42200)).toEqual({
|
expect(playerMovement.getPosition(42200)).toEqual({
|
||||||
@ -35,8 +37,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
y: 100,
|
y: 100,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: "up",
|
||||||
moving: true
|
moving: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(playerMovement.getPosition(42300)).toEqual({
|
expect(playerMovement.getPosition(42300)).toEqual({
|
||||||
@ -44,22 +46,25 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
y: 50,
|
y: 50,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: "up",
|
||||||
moving: true
|
moving: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not extrapolate if we stop", () => {
|
it("should not extrapolate if we stop", () => {
|
||||||
const playerMovement = new PlayerMovement({
|
const playerMovement = new PlayerMovement(
|
||||||
x: 100, y: 200
|
{
|
||||||
}, 42000,
|
x: 100,
|
||||||
|
y: 200,
|
||||||
|
},
|
||||||
|
42000,
|
||||||
{
|
{
|
||||||
x: 200,
|
x: 200,
|
||||||
y: 100,
|
y: 100,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
moving: false,
|
moving: false,
|
||||||
direction: "up"
|
direction: "up",
|
||||||
},
|
},
|
||||||
42200
|
42200
|
||||||
);
|
);
|
||||||
@ -69,22 +74,25 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
y: 100,
|
y: 100,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: "up",
|
||||||
moving: false
|
moving: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should keep moving until it stops", () => {
|
it("should keep moving until it stops", () => {
|
||||||
const playerMovement = new PlayerMovement({
|
const playerMovement = new PlayerMovement(
|
||||||
x: 100, y: 200
|
{
|
||||||
}, 42000,
|
x: 100,
|
||||||
|
y: 200,
|
||||||
|
},
|
||||||
|
42000,
|
||||||
{
|
{
|
||||||
x: 200,
|
x: 200,
|
||||||
y: 100,
|
y: 100,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
moving: false,
|
moving: false,
|
||||||
direction: "up"
|
direction: "up",
|
||||||
},
|
},
|
||||||
42200
|
42200
|
||||||
);
|
);
|
||||||
@ -94,8 +102,8 @@ describe("Interpolation / Extrapolation", () => {
|
|||||||
y: 150,
|
y: 150,
|
||||||
oldX: 100,
|
oldX: 100,
|
||||||
oldY: 200,
|
oldY: 200,
|
||||||
direction: 'up',
|
direction: "up",
|
||||||
moving: false
|
moving: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
@ -20,6 +20,10 @@ export const isMapDetailsData = new tg.IsInterface()
|
|||||||
})
|
})
|
||||||
.withOptionalProperties({
|
.withOptionalProperties({
|
||||||
iframeAuthentication: tg.isNullable(tg.isString),
|
iframeAuthentication: tg.isNullable(tg.isString),
|
||||||
|
// The date (in ISO 8601 format) at which the room will expire
|
||||||
|
expireOn: tg.isString,
|
||||||
|
// Whether the "report" feature is enabled or not on this room
|
||||||
|
canReport: tg.isBoolean,
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user