Release 1.9.6 (#2021)

* Change accès token with query privateAccessToken in the url

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* Add play uri param

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* PlayUri parameter

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* removed unused imports

* send group userIds to players

* sending info about group lock state. wip

* listening to lockGroupMessage on front

* cleanup

* Updating GroupDescriptors on LockGroupMessage

* remove console logs

* group circles with color fill

* fix GameRoom text

* remove obsolete check

* cr fixes #1 wip

* much cleaner approach to group lock update

* fix compilation error

* well-known values wip

* Removing old unused images

Just a bit of cleanup!

* update with dan suggest

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* Change roomId by playUri

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* hide voice indicator for player leaving still existing bubble conversation

* Refactor access by token

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* Refactor connexion manager

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* Adds settings options and localUser functions

* PrivacyShutdownStore modifies constraints according to the user's setting

* switches dropdown for checkboxes and adjusts wording

* Adds the todo about German translation

* Adds test map

* Makes the default setting: camera off and mic on

* Add z-index on embeds screens and action menu

* Fixes tileset import

* Adds settings options and localUser functions

* PrivacyShutdownStore modifies constraints according to the user's setting

* switches dropdown for checkboxes and adjusts wording

* Adds the todo about German translation

* Adds test map

* Makes the default setting: camera off and mic on

* Fixes tileset import

* Applying German translation, thanks to @Lurkars

* removed obsolete console.log

* fix linter issues

* make use of proto well knows types

* fixed types for RoomConnection

* fix locking bubble when returning from away mode

* Fix run pretty

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* prevent actions menu from appearing when inserting space key on chat

* Bump ansi-regex from 4.1.0 to 4.1.1 in /maps

Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump minimist from 1.2.5 to 1.2.6 in /desktop/local-app

Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ansi-regex from 4.1.0 to 4.1.1 in /desktop/electron

Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ansi-regex from 4.1.0 to 4.1.1 in /uploader

Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump plist from 3.0.4 to 3.0.5 in /desktop/electron

Bumps [plist](https://github.com/TooTallNate/node-plist) from 3.0.4 to 3.0.5.
- [Release notes](https://github.com/TooTallNate/node-plist/releases)
- [Changelog](https://github.com/TooTallNate/plist.js/blob/master/History.md)
- [Commits](https://github.com/TooTallNate/node-plist/commits)

---
updated-dependencies:
- dependency-name: plist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Hanusiak Piotr <piotr@ltmp.co>
Co-authored-by: David Négrier <d.negrier@thecodingmachine.com>
Co-authored-by: Piotr 'pwh' Hanusiak <p.hanusiak@workadventu.re>
Co-authored-by: Benedicte Quimbert <b.quimbert@workadventu.re>
Co-authored-by: Alexis Faizeau <a.faizeau@workadventu.re>
Co-authored-by: Bénédicte Q <37311765+HimeShaman@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
grégoire parant 2022-03-30 11:13:27 +02:00 committed by GitHub
parent 987325e787
commit 003bc86262
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 533 additions and 98 deletions

View File

@ -6,6 +6,7 @@ import {
EmoteCallback,
EntersCallback,
LeavesCallback,
LockGroupCallback,
MovesCallback,
PlayerDetailsUpdatedCallback,
} from "_Model/Zone";
@ -44,7 +45,7 @@ export class GameRoom {
// Users, sorted by ID
private readonly users = new Map<number, User>();
private readonly usersByUuid = new Map<string, User>();
private readonly groups = new Set<Group>();
private readonly groups: Map<number, Group> = new Map<number, Group>();
private readonly admins = new Set<Admin>();
private itemsState = new Map<number, unknown>();
@ -66,6 +67,7 @@ export class GameRoom {
onMoves: MovesCallback,
onLeaves: LeavesCallback,
onEmote: EmoteCallback,
onLockGroup: LockGroupCallback,
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
) {
// A zone is 10 sprites wide.
@ -76,6 +78,7 @@ export class GameRoom {
onMoves,
onLeaves,
onEmote,
onLockGroup,
onPlayerDetailsUpdated
);
}
@ -90,6 +93,7 @@ export class GameRoom {
onMoves: MovesCallback,
onLeaves: LeavesCallback,
onEmote: EmoteCallback,
onLockGroup: LockGroupCallback,
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
): Promise<GameRoom> {
const mapDetails = await GameRoom.getMapDetails(roomUrl);
@ -105,6 +109,7 @@ export class GameRoom {
onMoves,
onLeaves,
onEmote,
onLockGroup,
onPlayerDetailsUpdated
);
@ -244,7 +249,7 @@ export class GameRoom {
this.disconnectCallback,
this.positionNotifier
);
this.groups.add(group);
this.groups.set(group.getId(), group);
}
}
} else {
@ -328,7 +333,7 @@ export class GameRoom {
this.disconnectCallback,
this.positionNotifier
);
this.groups.add(newGroup);
this.groups.set(newGroup.getId(), newGroup);
} else {
this.leaveGroup(user);
}
@ -375,10 +380,10 @@ export class GameRoom {
group.leave(user);
if (group.isEmpty()) {
group.destroy();
if (!this.groups.has(group)) {
if (!this.groups.has(group.getId())) {
throw new Error(`Could not find group ${group.getId()} referenced by user ${user.id} in World.`);
}
this.groups.delete(group);
this.groups.delete(group.getId());
//todo: is the group garbage collected?
} else {
group.updatePosition();
@ -418,7 +423,7 @@ export class GameRoom {
});
this.groups.forEach((group: Group) => {
if (group.isFull()) {
if (group.isFull() || group.isLocked()) {
return;
}
const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), group.getPosition());
@ -544,6 +549,10 @@ export class GameRoom {
this.positionNotifier.emitEmoteEvent(user, emoteEventMessage);
}
public emitLockGroupEvent(user: User, groupId: number) {
this.positionNotifier.emitLockGroupEvent(user, groupId);
}
public addRoomListener(socket: RoomSocket) {
this.roomListeners.add(socket);
}
@ -657,4 +666,8 @@ export class GameRoom {
const variablesManager = await this.getVariableManager();
return variablesManager.getVariablesForTags(tags);
}
public getGroupById(id: number): Group | undefined {
return this.groups.get(id);
}
}

View File

@ -14,6 +14,7 @@ export class Group implements Movable {
private x!: number;
private y!: number;
private wasDestroyed: boolean = false;
private locked: boolean = false;
private roomId: string;
private currentZone: Zone | null = null;
/**
@ -141,15 +142,19 @@ export class Group implements Movable {
return this.users.size >= MAX_PER_GROUP;
}
isLocked(): boolean {
return this.locked;
}
isEmpty(): boolean {
return this.users.size <= 1;
}
join(user: User): void {
// Broadcast on the right event
this.connectCallback(user, this);
this.users.add(user);
user.group = this;
this.connectCallback(user, this);
}
leave(user: User): void {
@ -167,6 +172,10 @@ export class Group implements Movable {
this.disconnectCallback(user, this);
}
lock(lock: boolean = true): void {
this.locked = lock;
}
/**
* Let's kick everybody out.
* Usually used when there is only one user left.

View File

@ -12,6 +12,7 @@ import {
EmoteCallback,
EntersCallback,
LeavesCallback,
LockGroupCallback,
MovesCallback,
PlayerDetailsUpdatedCallback,
Zone,
@ -50,6 +51,7 @@ export class PositionNotifier {
private onUserMoves: MovesCallback,
private onUserLeaves: LeavesCallback,
private onEmote: EmoteCallback,
private onLockGroup: LockGroupCallback,
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
) {}
@ -111,6 +113,7 @@ export class PositionNotifier {
this.onUserMoves,
this.onUserLeaves,
this.onEmote,
this.onLockGroup,
this.onPlayerDetailsUpdated,
i,
j
@ -137,6 +140,12 @@ export class PositionNotifier {
zone.emitEmoteEvent(emoteEventMessage);
}
public emitLockGroupEvent(user: User, groupId: number) {
const zoneDesc = this.getZoneDescriptorFromCoordinates(user.getPosition().x, user.getPosition().y);
const zone = this.getZone(zoneDesc.i, zoneDesc.j);
zone.emitLockGroupEvent(groupId);
}
public *getAllUsersInSquareAroundZone(zone: Zone): Generator<User> {
const zoneDescriptor = this.getZoneDescriptorFromCoordinates(zone.x, zone.y);
for (const d of getNearbyDescriptorsMatrix(zoneDescriptor)) {

View File

@ -13,6 +13,7 @@ export type EntersCallback = (thing: Movable, fromZone: Zone | null, listener: Z
export type MovesCallback = (thing: Movable, position: PositionInterface, listener: ZoneSocket) => void;
export type LeavesCallback = (thing: Movable, newZone: Zone | null, listener: ZoneSocket) => void;
export type EmoteCallback = (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => void;
export type LockGroupCallback = (groupId: number, listener: ZoneSocket) => void;
export type PlayerDetailsUpdatedCallback = (
playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage,
listener: ZoneSocket
@ -27,6 +28,7 @@ export class Zone {
private onMoves: MovesCallback,
private onLeaves: LeavesCallback,
private onEmote: EmoteCallback,
private onLockGroup: LockGroupCallback,
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback,
public readonly x: number,
public readonly y: number
@ -108,6 +110,12 @@ export class Zone {
}
}
public emitLockGroupEvent(groupId: number) {
for (const listener of this.listeners) {
this.onLockGroup(groupId, listener);
}
}
public updatePlayerDetails(user: User, playerDetails: SetPlayerDetailsMessage) {
const playerDetailsUpdatedMessage = new PlayerDetailsUpdatedMessage();
playerDetailsUpdatedMessage.setUserid(user.id);

View File

@ -29,6 +29,7 @@ import {
WebRtcSignalToServerMessage,
WorldFullWarningToRoomMessage,
ZoneMessage,
LockGroupPromptMessage,
} from "./Messages/generated/messages_pb";
import { sendUnaryData, ServerDuplexStream, ServerUnaryCall, ServerWritableStream } from "grpc";
import { socketManager } from "./Services/SocketManager";
@ -135,6 +136,12 @@ const roomManager: IRoomManagerServer = {
user,
message.getFollowabortmessage() as FollowAbortMessage
);
} else if (message.hasLockgrouppromptmessage()) {
socketManager.handleLockGroupPromptMessage(
room,
user,
message.getLockgrouppromptmessage() as LockGroupPromptMessage
);
} else if (message.hasSendusermessage()) {
const sendUserMessage = message.getSendusermessage();
socketManager.handleSendUserMessage(user, sendUserMessage as SendUserMessage);

View File

@ -38,6 +38,9 @@ import {
SubToPusherRoomMessage,
SetPlayerDetailsMessage,
PlayerDetailsUpdatedMessage,
GroupUsersUpdateMessage,
LockGroupPromptMessage,
RoomMessage,
} from "../Messages/generated/messages_pb";
import { User, UserSocket } from "../Model/User";
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
@ -68,7 +71,6 @@ function emitZoneMessage(subMessage: SubToPusherMessage, socket: ZoneSocket): vo
// TODO: should we batch those every 100ms?
const batchMessage = new BatchToPusherMessage();
batchMessage.addPayload(subMessage);
socket.write(batchMessage);
}
@ -266,18 +268,28 @@ export class SocketManager {
if (roomPromise === undefined) {
roomPromise = GameRoom.create(
roomId,
(user: User, group: Group) => this.joinWebRtcRoom(user, group),
(user: User, group: Group) => this.disConnectedUser(user, group),
(user: User, group: Group) => {
this.joinWebRtcRoom(user, group);
this.sendGroupUsersUpdateToGroupMembers(group);
},
(user: User, group: Group) => {
this.disConnectedUser(user, group);
this.sendGroupUsersUpdateToGroupMembers(group);
},
MINIMUM_DISTANCE,
GROUP_RADIUS,
(thing: Movable, fromZone: Zone | null, listener: ZoneSocket) =>
this.onZoneEnter(thing, fromZone, listener),
(thing: Movable, fromZone: Zone | null, listener: ZoneSocket) => {
this.onZoneEnter(thing, fromZone, listener);
},
(thing: Movable, position: PositionInterface, listener: ZoneSocket) =>
this.onClientMove(thing, position, listener),
(thing: Movable, newZone: Zone | null, listener: ZoneSocket) =>
this.onClientLeave(thing, newZone, listener),
(emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) =>
this.onEmote(emoteEventMessage, listener),
(groupId: number, listener: ZoneSocket) => {
void this.onLockGroup(groupId, listener, roomPromise);
},
(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, listener: ZoneSocket) =>
this.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener)
)
@ -381,10 +393,24 @@ export class SocketManager {
emitZoneMessage(subMessage, client);
}
private async onLockGroup(
groupId: number,
client: ZoneSocket,
roomPromise: PromiseLike<GameRoom> | undefined
): Promise<void> {
if (!roomPromise) {
return;
}
const group = (await roomPromise).getGroupById(groupId);
if (!group) {
return;
}
this.emitCreateUpdateGroupEvent(client, null, group);
}
private onPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, client: ZoneSocket) {
const subMessage = new SubToPusherMessage();
subMessage.setPlayerdetailsupdatedmessage(playerDetailsUpdatedMessage);
emitZoneMessage(subMessage, client);
}
@ -398,6 +424,7 @@ export class SocketManager {
groupUpdateMessage.setPosition(pointMessage);
groupUpdateMessage.setGroupsize(group.getSize);
groupUpdateMessage.setFromzone(this.toProtoZone(fromZone));
groupUpdateMessage.setLocked(group.isLocked());
const subMessage = new SubToPusherMessage();
subMessage.setGroupupdatezonemessage(groupUpdateMessage);
@ -413,7 +440,6 @@ export class SocketManager {
const subMessage = new SubToPusherMessage();
subMessage.setGroupleftzonemessage(groupDeleteMessage);
emitZoneMessage(subMessage, client);
//user.emitInBatch(subMessage);
}
@ -425,7 +451,6 @@ export class SocketManager {
const subMessage = new SubToPusherMessage();
subMessage.setUserleftzonemessage(userLeftMessage);
emitZoneMessage(subMessage, client);
}
@ -439,6 +464,19 @@ export class SocketManager {
return undefined;
}
private sendGroupUsersUpdateToGroupMembers(group: Group) {
const groupUserUpdateMessage = new GroupUsersUpdateMessage();
groupUserUpdateMessage.setGroupid(group.getId());
groupUserUpdateMessage.setUseridsList(group.getUsers().map((user) => user.id));
const clientMessage = new ServerToClientMessage();
clientMessage.setGroupusersupdatemessage(groupUserUpdateMessage);
group.getUsers().forEach((currentUser: User) => {
currentUser.socket.write(clientMessage);
});
}
private joinWebRtcRoom(user: User, group: Group) {
for (const otherUser of group.getUsers()) {
if (user === otherUser) {
@ -634,6 +672,7 @@ export class SocketManager {
const groupUpdateMessage = new GroupUpdateZoneMessage();
groupUpdateMessage.setGroupid(thing.getId());
groupUpdateMessage.setPosition(ProtobufUtils.toPointMessage(thing.getPosition()));
groupUpdateMessage.setLocked(thing.isLocked());
const subMessage = new SubToPusherMessage();
subMessage.setGroupupdatezonemessage(groupUpdateMessage);
@ -870,6 +909,15 @@ export class SocketManager {
leader?.delFollower(user);
}
}
handleLockGroupPromptMessage(room: GameRoom, user: User, message: LockGroupPromptMessage) {
const group = user.group;
if (!group) {
return;
}
group.lock(message.getLock());
room.emitLockGroupEvent(user, group.getId());
}
}
export const socketManager = new SocketManager();

View File

@ -52,6 +52,7 @@ describe("GameRoom", () => {
() => {},
() => {},
emote,
() => {},
() => {}
);
@ -88,6 +89,7 @@ describe("GameRoom", () => {
() => {},
() => {},
emote,
() => {},
() => {}
);
@ -128,6 +130,7 @@ describe("GameRoom", () => {
() => {},
() => {},
emote,
() => {},
() => {}
);

View File

@ -25,6 +25,7 @@ describe("PositionNotifier", () => {
leaveTriggered = true;
},
() => {},
() => {},
() => {}
);
@ -132,6 +133,7 @@ describe("PositionNotifier", () => {
leaveTriggered = true;
},
() => {},
() => {},
() => {}
);

View File

@ -295,9 +295,9 @@ ansi-escapes@^4.2.1:
type-fest "^0.21.3"
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
ansi-regex@^5.0.1:
version "5.0.1"
@ -2409,9 +2409,9 @@ pirates@^4.0.1:
integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==
plist@^3.0.1, plist@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe"
integrity sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==
version "3.0.5"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.5.tgz#2cbeb52d10e3cdccccf0c11a63a85d830970a987"
integrity sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==
dependencies:
base64-js "^1.5.1"
xmlbuilder "^9.0.7"

View File

@ -587,9 +587,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mkdirp@^0.5.1:
version "0.5.5"

View File

@ -77,6 +77,7 @@
height: max-content !important;
max-height: 40vh;
margin-top: 200px;
z-index: 425;
pointer-events: auto;
font-family: "Press Start 2P";

View File

@ -10,12 +10,14 @@
import layoutPresentationImg from "./images/layout-presentation.svg";
import layoutChatImg from "./images/layout-chat.svg";
import followImg from "./images/follow.svg";
import lockImg from "./images/lock.svg";
import { LayoutMode } from "../WebRtc/LayoutManager";
import { peerStore } from "../Stores/PeerStore";
import { onDestroy } from "svelte";
import { embedScreenLayout } from "../Stores/EmbedScreensStore";
import { followRoleStore, followStateStore, followUsersStore } from "../Stores/FollowStore";
import { gameManager } from "../Phaser/Game/GameManager";
import { currentPlayerGroupLockStateStore } from "../Stores/CurrentPlayerGroupStore";
const gameScene = gameManager.getCurrentGameScene();
@ -70,6 +72,10 @@
}
}
function lockClick() {
gameScene.connection?.emitLockGroup(!$currentPlayerGroupLockStateStore);
}
let isSilent: boolean;
const unsubscribeIsSilent = isSilentStore.subscribe((value) => {
isSilent = value;
@ -95,6 +101,15 @@
<img class="noselect" src={followImg} alt="" />
</div>
<div
class="btn-lock"
class:hide={$peerStore.size === 0 || isSilent}
class:disabled={$currentPlayerGroupLockStateStore}
on:click={lockClick}
>
<img class="noselect" src={lockImg} alt="" />
</div>
<div
class="btn-monitor"
on:click={screenSharingClick}
@ -162,7 +177,7 @@
transform: translateY(15px);
transition-timing-function: ease-in-out;
transition: all 0.3s;
margin: 0 4%;
margin: 0 2%;
&.hide {
transform: translateY(60px);
@ -211,6 +226,14 @@
}
}
.btn-lock {
pointer-events: auto;
img {
filter: brightness(0) invert(1);
}
}
@media (hover: none) {
/**
* If we cannot hover over elements, let's display camera button in full.

View File

@ -18,5 +18,7 @@
display: flex;
padding-top: 2%;
height: 100%;
position: relative;
z-index: 200;
}
</style>

View File

@ -54,6 +54,7 @@
});
</script>
<!-- Components ordered by z-index -->
<div id="main-layout" bind:this={mainLayout}>
<aside id="main-layout-left-aside">
{#if $menuIconVisiblilityStore}
@ -104,14 +105,14 @@
<ShareLinkMapModal />
{/if}
{#if $followStateStore !== "off" || $peerStore.size > 0}
<FollowMenu />
{/if}
{#if $actionsMenuStore}
<ActionsMenu />
{/if}
{#if $followStateStore !== "off" || $peerStore.size > 0}
<FollowMenu />
{/if}
{#if $requestVisitCardsStore}
<VisitCard visitCardUrl={$requestVisitCardsStore} />
{/if}

View File

@ -17,9 +17,14 @@
let valueGame: number = localUserStore.getGameQualityValue();
let valueVideo: number = localUserStore.getVideoQualityValue();
let valueLocale: string = $locale;
let valueCameraPrivacySettings = localUserStore.getCameraPrivacySettings();
let valueMicrophonePrivacySettings = localUserStore.getMicrophonePrivacySettings();
let previewValueGame = valueGame;
let previewValueVideo = valueVideo;
let previewValueLocale = valueLocale;
let previewCameraPrivacySettings = valueCameraPrivacySettings;
let previewMicrophonePrivacySettings = valueMicrophonePrivacySettings;
function saveSetting() {
let change = false;
@ -40,6 +45,16 @@
change = true;
}
if (valueCameraPrivacySettings !== previewCameraPrivacySettings) {
previewCameraPrivacySettings = valueCameraPrivacySettings;
localUserStore.setCameraPrivacySettings(valueCameraPrivacySettings);
}
if (valueMicrophonePrivacySettings !== previewMicrophonePrivacySettings) {
previewMicrophonePrivacySettings = valueMicrophonePrivacySettings;
localUserStore.setMicrophonePrivacySettings(valueMicrophonePrivacySettings);
}
audioManagerVolumeStore.setDecreaseWhileTalking(decreaseAudioPlayerVolumeWhileTalking);
if (change) {
@ -162,6 +177,19 @@
</select>
</div>
</section>
<section>
<h3>{$LL.menu.settings.privacySettings.title()}</h3>
<p>{$LL.menu.settings.privacySettings.explanation()}</p>
<label>
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={valueCameraPrivacySettings} />
<span>{$LL.menu.settings.privacySettings.cameraToggle()}</span>
</label>
<label>
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={valueMicrophonePrivacySettings} />
<span>{$LL.menu.settings.privacySettings.microphoneToggle()}</span>
</label>
</section>
<section class="settings-section-save">
<p>{$LL.menu.settings.save.warning()}</p>
<button type="button" class="nes-btn is-primary" on:click|preventDefault={saveSetting}
@ -204,15 +232,15 @@
on:change={changeIgnoreFollowRequests}
/>
<span>{$LL.menu.settings.ignoreFollowRequest()}</span>
</label>
<label>
<input
type="checkbox"
class="nes-checkbox is-dark"
bind:checked={decreaseAudioPlayerVolumeWhileTalking}
on:change={changeDecreaseAudioPlayerVolumeWhileTalking}
/>
<span>{$LL.audio.manager.reduce()}</span>
<label>
<input
type="checkbox"
class="nes-checkbox is-dark"
bind:checked={decreaseAudioPlayerVolumeWhileTalking}
on:change={changeDecreaseAudioPlayerVolumeWhileTalking}
/>
<span>{$LL.audio.manager.reduce()}</span>
</label>
</label>
</section>
</div>
@ -234,12 +262,15 @@
outline: none;
}
}
section.settings-section-save {
text-align: center;
p {
margin: 16px 0;
}
}
section.settings-section-noSaveOption {
display: flex;
align-items: center;

View File

@ -76,6 +76,7 @@
transform: translate(-50%, 0);
margin-top: 200px;
max-width: 80vw;
z-index: 350;
iframe {
border: 0;

View File

@ -0,0 +1 @@
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50px" height="50px"><path d="M 25 3 C 18.363281 3 13 8.363281 13 15 L 13 20 L 9 20 C 7.355469 20 6 21.355469 6 23 L 6 47 C 6 48.644531 7.355469 50 9 50 L 41 50 C 42.644531 50 44 48.644531 44 47 L 44 23 C 44 21.355469 42.644531 20 41 20 L 37 20 L 37 15 C 37 8.363281 31.636719 3 25 3 Z M 25 5 C 30.566406 5 35 9.433594 35 15 L 35 20 L 15 20 L 15 15 C 15 9.433594 19.433594 5 25 5 Z M 9 22 L 41 22 C 41.554688 22 42 22.445313 42 23 L 42 47 C 42 47.554688 41.554688 48 41 48 L 9 48 C 8.445313 48 8 47.554688 8 47 L 8 23 C 8 22.445313 8.445313 22 9 22 Z M 25 30 C 23.300781 30 22 31.300781 22 33 C 22 33.898438 22.398438 34.6875 23 35.1875 L 23 38 C 23 39.101563 23.898438 40 25 40 C 26.101563 40 27 39.101563 27 38 L 27 35.1875 C 27.601563 34.6875 28 33.898438 28 33 C 28 31.300781 26.699219 30 25 30 Z"/></svg>

After

Width:  |  Height:  |  Size: 891 B

View File

@ -1,5 +1,5 @@
import { Subject } from "rxjs";
import type { BanUserMessage, SendUserMessage } from "../Messages/ts-proto-generated/messages";
import type { BanUserMessage, SendUserMessage } from "../Messages/ts-proto-generated/protos/messages";
export enum AdminMessageEventTypes {
admin = "message",

View File

@ -88,8 +88,7 @@ class ConnectionManager {
* @return returns a promise to the Room we are going to load OR a pointer to the URL we must redirect to if authentication is needed.
*/
public async initGameConnexion(): Promise<Room | URL> {
const connexionType = urlManager.getGameConnexionType();
this.connexionType = connexionType;
this.connexionType = urlManager.getGameConnexionType();
this._currentRoom = null;
const urlParams = new URLSearchParams(window.location.search);
@ -102,14 +101,15 @@ class ConnectionManager {
urlParams.delete("token");
}
if (connexionType === GameConnexionTypes.login) {
if (this.connexionType === GameConnexionTypes.login) {
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
const redirect = this.loadOpenIDScreen();
if (redirect !== null) {
return redirect;
}
urlManager.pushRoomIdToUrl(this._currentRoom);
} else if (connexionType === GameConnexionTypes.jwt) {
} else if (this.connexionType === GameConnexionTypes.jwt) {
/** @deprecated */
if (!token) {
const code = urlParams.get("code");
const state = urlParams.get("state");
@ -135,8 +135,9 @@ class ConnectionManager {
return redirect;
}
urlManager.pushRoomIdToUrl(this._currentRoom);
} else if (connexionType === GameConnexionTypes.register) {
//@deprecated
}
//@deprecated
else if (this.connexionType === GameConnexionTypes.register) {
const organizationMemberToken = urlManager.getOrganizationToken();
const data = await Axios.post(`${PUSHER_URL}/register`, { organizationMemberToken }).then(
(res) => res.data
@ -165,11 +166,11 @@ class ConnectionManager {
)
);
urlManager.pushRoomIdToUrl(this._currentRoom);
} else if (connexionType === GameConnexionTypes.room || connexionType === GameConnexionTypes.empty) {
} else if (this.connexionType === GameConnexionTypes.room || this.connexionType === GameConnexionTypes.empty) {
this.authToken = localUserStore.getAuthToken();
let roomPath: string;
if (connexionType === GameConnexionTypes.empty) {
if (this.connexionType === GameConnexionTypes.empty) {
roomPath = localUserStore.getLastRoomUrl();
//get last room path from cache api
try {

View File

@ -43,7 +43,13 @@ export interface PositionInterface {
export interface GroupCreatedUpdatedMessageInterface {
position: PositionInterface;
groupId: number;
groupSize: number;
groupSize?: number;
locked?: boolean;
}
export interface GroupUsersUpdateMessageInterface {
groupId: number;
userIds: number[];
}
export interface WebRtcDisconnectMessageInterface {

View File

@ -25,11 +25,14 @@ const code = "code";
const cameraSetup = "cameraSetup";
const cacheAPIIndex = "workavdenture-cache";
const userProperties = "user-properties";
const cameraPrivacySettings = "cameraPrivacySettings";
const microphonePrivacySettings = "microphonePrivacySettings";
class LocalUserStore {
saveUser(localUser: LocalUser) {
localStorage.setItem("localUser", JSON.stringify(localUser));
}
getLocalUser(): LocalUser | null {
const data = localStorage.getItem("localUser");
return data ? JSON.parse(data) : null;
@ -38,6 +41,7 @@ class LocalUserStore {
setName(name: string): void {
localStorage.setItem(playerNameKey, name);
}
getName(): string | null {
const value = localStorage.getItem(playerNameKey) || "";
return isUserNameValid(value) ? value : null;
@ -46,6 +50,7 @@ class LocalUserStore {
setPlayerCharacterIndex(playerCharacterIndex: number): void {
localStorage.setItem(selectedPlayerKey, "" + playerCharacterIndex);
}
getPlayerCharacterIndex(): number {
return parseInt(localStorage.getItem(selectedPlayerKey) || "");
}
@ -53,6 +58,7 @@ class LocalUserStore {
setCustomCursorPosition(activeRow: number, selectedLayers: number[]): void {
localStorage.setItem(customCursorPositionKey, JSON.stringify({ activeRow, selectedLayers }));
}
getCustomCursorPosition(): { activeRow: number; selectedLayers: number[] } | null {
return JSON.parse(localStorage.getItem(customCursorPositionKey) || "null");
}
@ -60,6 +66,7 @@ class LocalUserStore {
setCharacterLayers(layers: string[]): void {
localStorage.setItem(characterLayersKey, JSON.stringify(layers));
}
getCharacterLayers(): string[] | null {
const value = JSON.parse(localStorage.getItem(characterLayersKey) || "null");
return areCharacterLayersValid(value) ? value : null;
@ -68,6 +75,7 @@ class LocalUserStore {
setCompanion(companion: string | null): void {
return localStorage.setItem(companionKey, JSON.stringify(companion));
}
getCompanion(): string | null {
const companion = JSON.parse(localStorage.getItem(companionKey) || "null");
@ -77,6 +85,7 @@ class LocalUserStore {
return companion;
}
wasCompanionSet(): boolean {
return localStorage.getItem(companionKey) ? true : false;
}
@ -84,6 +93,7 @@ class LocalUserStore {
setGameQualityValue(value: number): void {
localStorage.setItem(gameQualityKey, "" + value);
}
getGameQualityValue(): number {
return parseInt(localStorage.getItem(gameQualityKey) || "60");
}
@ -91,6 +101,7 @@ class LocalUserStore {
setVideoQualityValue(value: number): void {
localStorage.setItem(videoQualityKey, "" + value);
}
getVideoQualityValue(): number {
return parseInt(localStorage.getItem(videoQualityKey) || "20");
}
@ -98,6 +109,7 @@ class LocalUserStore {
setAudioPlayerVolume(value: number): void {
localStorage.setItem(audioPlayerVolumeKey, "" + value);
}
getAudioPlayerVolume(): number {
return parseFloat(localStorage.getItem(audioPlayerVolumeKey) || "1");
}
@ -105,6 +117,7 @@ class LocalUserStore {
setAudioPlayerMuted(value: boolean): void {
localStorage.setItem(audioPlayerMuteKey, value.toString());
}
getAudioPlayerMuted(): boolean {
return localStorage.getItem(audioPlayerMuteKey) === "true";
}
@ -112,6 +125,7 @@ class LocalUserStore {
setHelpCameraSettingsShown(): void {
localStorage.setItem(helpCameraSettingsShown, "1");
}
getHelpCameraSettingsShown(): boolean {
return localStorage.getItem(helpCameraSettingsShown) === "1";
}
@ -119,6 +133,7 @@ class LocalUserStore {
setFullscreen(value: boolean): void {
localStorage.setItem(fullscreenKey, value.toString());
}
getFullscreen(): boolean {
return localStorage.getItem(fullscreenKey) === "true";
}
@ -126,6 +141,7 @@ class LocalUserStore {
setForceCowebsiteTrigger(value: boolean): void {
localStorage.setItem(forceCowebsiteTriggerKey, value.toString());
}
getForceCowebsiteTrigger(): boolean {
return localStorage.getItem(forceCowebsiteTriggerKey) === "true";
}
@ -133,6 +149,7 @@ class LocalUserStore {
setIgnoreFollowRequests(value: boolean): void {
localStorage.setItem(ignoreFollowRequests, value.toString());
}
getIgnoreFollowRequests(): boolean {
return localStorage.getItem(ignoreFollowRequests) === "true";
}
@ -155,11 +172,13 @@ class LocalUserStore {
}
}
}
getLastRoomUrl(): string {
return (
localStorage.getItem(lastRoomUrl) ?? window.location.protocol + "//" + window.location.host + START_ROOM_URL
);
}
getLastRoomUrlCacheApi(): Promise<string | undefined> {
if (!("caches" in window)) {
return Promise.resolve(undefined);
@ -176,6 +195,7 @@ class LocalUserStore {
setAuthToken(value: string | null) {
value ? localStorage.setItem(authToken, value) : localStorage.removeItem(authToken);
}
getAuthToken(): string | null {
return localStorage.getItem(authToken);
}
@ -202,23 +222,29 @@ class LocalUserStore {
}
return oldValue === value;
}
setState(value: string) {
localStorage.setItem(state, value);
}
getState(): string | null {
return localStorage.getItem(state);
}
generateNonce(): string {
const newNonce = uuidv4();
localStorage.setItem(nonce, newNonce);
return newNonce;
}
getNonce(): string | null {
return localStorage.getItem(nonce);
}
setCode(value: string): void {
localStorage.setItem(code, value);
}
getCode(): string | null {
return localStorage.getItem(code);
}
@ -226,11 +252,36 @@ class LocalUserStore {
setCameraSetup(cameraId: string) {
localStorage.setItem(cameraSetup, cameraId);
}
getCameraSetup(): { video: unknown; audio: unknown } | undefined {
const cameraSetupValues = localStorage.getItem(cameraSetup);
return cameraSetupValues != undefined ? JSON.parse(cameraSetupValues) : undefined;
}
setCameraPrivacySettings(option: boolean) {
localStorage.setItem(cameraPrivacySettings, option.toString());
}
getCameraPrivacySettings() {
//if this setting doesn't exist in LocalUserStore, we set a default value
if (localStorage.getItem(cameraPrivacySettings) == null) {
localStorage.setItem(cameraPrivacySettings, "false");
}
return localStorage.getItem(cameraPrivacySettings) === "true";
}
setMicrophonePrivacySettings(option: boolean) {
localStorage.setItem(microphonePrivacySettings, option.toString());
}
getMicrophonePrivacySettings() {
//if this setting doesn't exist in LocalUserStore, we set a default value
if (localStorage.getItem(microphonePrivacySettings) == null) {
localStorage.setItem(microphonePrivacySettings, "true");
}
return localStorage.getItem(microphonePrivacySettings) === "true";
}
getAllUserProperties(): Map<string, unknown> {
const result = new Map<string, string>();
for (let i = 0; i < localStorage.length; i++) {

View File

@ -5,47 +5,35 @@ import type { UserSimplePeerInterface } from "../WebRtc/SimplePeer";
import { ProtobufClientUtils } from "../Network/ProtobufClientUtils";
import type {
GroupCreatedUpdatedMessageInterface,
ItemEventMessageInterface,
GroupUsersUpdateMessageInterface,
MessageUserJoined,
OnConnectInterface,
PlayerDetailsUpdatedMessageInterface,
PlayGlobalMessageInterface,
PositionInterface,
RoomJoinedMessageInterface,
ViewportInterface,
WebRtcDisconnectMessageInterface,
WebRtcSignalReceivedMessageInterface,
} from "./ConnexionModels";
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
import { adminMessagesService } from "./AdminMessagesService";
import { connectionManager } from "./ConnectionManager";
import { get } from "svelte/store";
import { followRoleStore, followUsersStore } from "../Stores/FollowStore";
import { menuIconVisiblilityStore, menuVisiblilityStore, warningContainerStore } from "../Stores/MenuStore";
import { followStateStore, followRoleStore, followUsersStore } from "../Stores/FollowStore";
import { localUserStore } from "./LocalUserStore";
import {
RefreshRoomMessage,
ServerToClientMessage as ServerToClientMessageTsProto,
TokenExpiredMessage,
WorldConnexionMessage,
WorldFullMessage,
ErrorMessage as ErrorMessageTsProto,
UserMovedMessage as UserMovedMessageTsProto,
GroupUpdateMessage as GroupUpdateMessageTsProto,
GroupDeleteMessage as GroupDeleteMessageTsProto,
UserJoinedMessage as UserJoinedMessageTsProto,
UserLeftMessage as UserLeftMessageTsProto,
ItemEventMessage as ItemEventMessageTsProto,
EmoteEventMessage as EmoteEventMessageTsProto,
VariableMessage as VariableMessageTsProto,
PlayerDetailsUpdatedMessage as PlayerDetailsUpdatedMessageTsProto,
WorldFullWarningMessage,
WebRtcDisconnectMessage as WebRtcDisconnectMessageTsProto,
PlayGlobalMessage as PlayGlobalMessageTsProto,
StopGlobalMessage as StopGlobalMessageTsProto,
SendJitsiJwtMessage as SendJitsiJwtMessageTsProto,
SendUserMessage as SendUserMessageTsProto,
BanUserMessage as BanUserMessageTsProto,
ClientToServerMessage as ClientToServerMessageTsProto,
PositionMessage as PositionMessageTsProto,
ViewportMessage as ViewportMessageTsProto,
@ -53,10 +41,8 @@ import {
SetPlayerDetailsMessage as SetPlayerDetailsMessageTsProto,
PingMessage as PingMessageTsProto,
CharacterLayerMessage,
} from "../Messages/ts-proto-generated/messages";
} from "../Messages/ts-proto-generated/protos/messages";
import { Subject } from "rxjs";
import { OpenPopupEvent } from "../Api/Events/OpenPopupEvent";
import { match } from "assert";
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
import { gameManager } from "../Phaser/Game/GameManager";
import { SelectCharacterScene, SelectCharacterSceneName } from "../Phaser/Login/SelectCharacterScene";
@ -116,6 +102,9 @@ export class RoomConnection implements RoomConnection {
private readonly _groupUpdateMessageStream = new Subject<GroupCreatedUpdatedMessageInterface>();
public readonly groupUpdateMessageStream = this._groupUpdateMessageStream.asObservable();
private readonly _groupUsersUpdateMessageStream = new Subject<GroupUsersUpdateMessageInterface>();
public readonly groupUsersUpdateMessageStream = this._groupUsersUpdateMessageStream.asObservable();
private readonly _groupDeleteMessageStream = new Subject<GroupDeleteMessageTsProto>();
public readonly groupDeleteMessageStream = this._groupDeleteMessageStream.asObservable();
@ -443,6 +432,10 @@ export class RoomConnection implements RoomConnection {
this._sendJitsiJwtMessageStream.next(message.sendJitsiJwtMessage);
break;
}
case "groupUsersUpdateMessage": {
this._groupUsersUpdateMessageStream.next(message.groupUsersUpdateMessage);
break;
}
case "sendUserMessage": {
adminMessagesService.onSendusermessage(message.sendUserMessage);
break;
@ -675,6 +668,7 @@ export class RoomConnection implements RoomConnection {
groupId: message.groupId,
position: position,
groupSize: message.groupSize,
locked: message.locked,
};
}
@ -890,6 +884,19 @@ export class RoomConnection implements RoomConnection {
this.socket.send(bytes);
}
public emitLockGroup(lock: boolean = true): void {
const bytes = ClientToServerMessageTsProto.encode({
message: {
$case: "lockGroupPromptMessage",
lockGroupPromptMessage: {
lock,
},
},
}).finish();
this.socket.send(bytes);
}
public getAllTags(): string[] {
return this.tags;
}

View File

@ -1,4 +1,4 @@
import { PositionMessage, PositionMessage_Direction } from "../Messages/ts-proto-generated/messages";
import { PositionMessage, PositionMessage_Direction } from "../Messages/ts-proto-generated/protos/messages";
import type { PointInterface } from "../Connexion/ConnexionModels";

View File

@ -76,6 +76,7 @@ import { userIsAdminStore } from "../../Stores/GameStore";
import { contactPageStore } from "../../Stores/MenuStore";
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
import { audioManagerFileStore } from "../../Stores/AudioManagerStore";
import { currentPlayerGroupLockStateStore } from "../../Stores/CurrentPlayerGroupStore";
import EVENT_TYPE = Phaser.Scenes.Events;
import Texture = Phaser.Textures.Texture;
@ -177,6 +178,7 @@ export class GameScene extends DirtyScene {
private volumeStoreUnsubscribers: Map<number, Unsubscriber> = new Map<number, Unsubscriber>();
private localVolumeStoreUnsubscriber: Unsubscriber | undefined;
private followUsersColorStoreUnsubscribe!: Unsubscriber;
private currentPlayerGroupIdStoreUnsubscribe!: Unsubscriber;
private biggestAvailableAreaStoreUnsubscribe!: () => void;
MapUrlFile: string;
@ -218,6 +220,7 @@ export class GameScene extends DirtyScene {
private loader: Loader;
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
private firstCameraUpdateSent: boolean = false;
private currentPlayerGroupId?: number;
public readonly superLoad: SuperLoaderPlugin;
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
@ -839,6 +842,10 @@ export class GameScene extends DirtyScene {
});
});
this.connection.groupUsersUpdateMessageStream.subscribe((message) => {
this.currentPlayerGroupId = message.groupId;
});
/**
* Triggered when we receive the JWT token to connect to Jitsi
*/
@ -969,7 +976,9 @@ export class GameScene extends DirtyScene {
context.arc(48, 48, 48, 0, 2 * Math.PI, false);
// context.lineWidth = 5;
context.strokeStyle = "#ffffff";
context.fillStyle = "#ffffff44";
context.stroke();
context.fill();
this.circleTexture.refresh();
//create red circle canvas use to create sprite
@ -979,7 +988,9 @@ export class GameScene extends DirtyScene {
contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false);
//context.lineWidth = 5;
contextRed.strokeStyle = "#ff0000";
contextRed.fillStyle = "#ff000044";
contextRed.stroke();
contextRed.fill();
this.circleRedTexture.refresh();
}
@ -1849,12 +1860,14 @@ ${escapedMessage}
case "GroupCreatedUpdatedEvent":
this.doShareGroupPosition(event.event);
break;
case "DeleteGroupEvent":
this.doDeleteGroup(event.groupId);
break;
case "PlayerDetailsUpdated":
this.doUpdatePlayerDetails(event.details);
break;
case "DeleteGroupEvent": {
this.doDeleteGroup(event.groupId);
currentPlayerGroupLockStateStore.set(undefined);
break;
}
default: {
const tmp: never = event;
}
@ -2028,11 +2041,16 @@ ${escapedMessage}
this,
Math.round(groupPositionMessage.position.x),
Math.round(groupPositionMessage.position.y),
groupPositionMessage.groupSize === MAX_PER_GROUP ? "circleSprite-red" : "circleSprite-white"
groupPositionMessage.groupSize === MAX_PER_GROUP || groupPositionMessage.locked
? "circleSprite-red"
: "circleSprite-white"
);
sprite.setDisplayOrigin(48, 48);
this.add.existing(sprite);
this.groups.set(groupPositionMessage.groupId, sprite);
if (this.currentPlayerGroupId === groupPositionMessage.groupId) {
currentPlayerGroupLockStateStore.set(groupPositionMessage.locked);
}
return sprite;
}

View File

@ -280,6 +280,9 @@ export class UserInputManager {
);
this.scene.input.keyboard.on("keyup-SPACE", (event: Event) => {
if (this.isInputDisabled) {
return;
}
this.userInputHandler.handleSpaceKeyUpEvent(event);
});
}

View File

@ -0,0 +1,3 @@
import { writable } from "svelte/store";
export const currentPlayerGroupLockStateStore = writable<boolean | undefined>(undefined);

View File

@ -11,7 +11,7 @@ import { peerStore } from "./PeerStore";
import { privacyShutdownStore } from "./PrivacyShutdownStore";
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
import { SoundMeter } from "../Phaser/Components/SoundMeter";
import { AudioContext } from "standardized-audio-context";
import { visibilityStore } from "./VisibilityStore";
/**
* A store that contains the camera state requested by the user (on or off).
@ -242,6 +242,7 @@ export const mediaStreamConstraintsStore = derived(
privacyShutdownStore,
cameraEnergySavingStore,
isSilentStore,
visibilityStore,
],
(
[
@ -254,6 +255,7 @@ export const mediaStreamConstraintsStore = derived(
$privacyShutdownStore,
$cameraEnergySavingStore,
$isSilentStore,
$visibilityStore,
],
set
) => {
@ -292,7 +294,14 @@ export const mediaStreamConstraintsStore = derived(
// Disable webcam for privacy reasons (the game is not visible and we were talking to no one)
if ($privacyShutdownStore === true) {
currentVideoConstraint = false;
const userMicrophonePrivacySetting = localUserStore.getMicrophonePrivacySettings();
const userCameraPrivacySetting = localUserStore.getCameraPrivacySettings();
if (!userMicrophonePrivacySetting) {
currentAudioConstraint = false;
}
if (!userCameraPrivacySetting) {
currentVideoConstraint = false;
}
}
// Disable webcam for energy reasons (the user is not moving and we are talking to no one)

View File

@ -3,10 +3,10 @@ import { localUserStore } from "../Connexion/LocalUserStore";
export enum GameConnexionTypes {
room = 1,
register,
register /*@deprecated*/,
empty,
unknown,
jwt,
jwt /*@deprecated*/,
login,
}
@ -16,11 +16,15 @@ class UrlManager {
const url = window.location.pathname.toString();
if (url === "/login") {
return GameConnexionTypes.login;
} else if (url === "/jwt") {
}
//@deprecated jwt url will be replace by "?token=<private access token>"
else if (url === "/jwt") {
return GameConnexionTypes.jwt;
} else if (url.includes("_/") || url.includes("*/") || url.includes("@/")) {
return GameConnexionTypes.room;
} else if (url.includes("register/")) {
}
//@deprecated register url will be replace by "?token=<private access token>"
else if (url.includes("register/")) {
return GameConnexionTypes.register;
} else if (url === "/") {
return GameConnexionTypes.empty;
@ -29,6 +33,9 @@ class UrlManager {
}
}
/**
* @deprecated
*/
public getOrganizationToken(): string | null {
const match = /\/register\/(.+)/.exec(window.location.pathname.toString());
return match ? match[1] : null;

View File

@ -57,6 +57,13 @@ const menu: NonNullable<Translation["menu"]> = {
language: {
title: "Sprache",
},
privacySettings: {
title: "Einstellungen Abwesenheitsmodus",
explanation:
"Falls der WorkAdventure Tab nicht aktiv ist wird in den Abwesenheitsmodus umgeschaltet. Für diesen Modus kann eingestellt werden, ob die Kamera und/oder das Mikrofon deaktiviert sind solange der Tab nicht sichtbar ist.",
cameraToggle: "Kamera",
microphoneToggle: "Mikrofon",
},
save: {
warning: "(Das Spiel wird nach dem Speichern neugestartet)",
button: "Speichern",

View File

@ -57,6 +57,13 @@ const menu: BaseTranslation = {
language: {
title: "Language",
},
privacySettings: {
title: "Away mode settings",
explanation:
'When the WorkAdventure tab is not visible, it switches to "away mode". In this mode, you can decide to automatically disable your webcam and/or microphone for as long as the tab stays hidden.',
cameraToggle: "Camera",
microphoneToggle: "Microphone",
},
save: {
warning: "(Saving these settings will restart the game)",
button: "Save",

View File

@ -57,6 +57,13 @@ const menu: NonNullable<Translation["menu"]> = {
language: {
title: "Langage",
},
privacySettings: {
title: "Paramètres du mode absent",
explanation:
"Quand l'onglet WorkAdventure n'est pas visible, vous passez en \"mode absent\". Lorsque ce mode est actif, vous pouvez décider de garder vos webcam et/ou micro désactivés tant que vous ne revenez pas sur l'onglet",
cameraToggle: "Camera",
microphoneToggle: "Microphone",
},
save: {
warning: "(La sauvegarde de ces paramètres redémarre le jeu)",
button: "Sauvegarder",

View File

@ -0,0 +1,97 @@
{ "compressionlevel":-1,
"height":20,
"infinite":false,
"layers":[
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":20,
"id":42,
"name":"start",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":20,
"x":0,
"y":0
},
{
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"height":20,
"id":39,
"name":"floor",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":20,
"x":0,
"y":0
},
{
"draworder":"topdown",
"id":43,
"name":"Test",
"objects":[
{
"height":225.333333333333,
"id":13,
"name":"",
"rotation":0,
"text":
{
"text":"Test: \n- Open two windows (you can use Private Mode) so that you control two Wokas.\n\n- On woka A window: go to Menu > Settings and set your away mode options\n- On woka A window: open a new tab in the browser, so that your WA tab is not visible\n\n- On woka B window: move to woka A to check that the options were applied",
"wrap":true
},
"type":"",
"visible":true,
"width":434.773333333333,
"x":97.9466666666667,
"y":33.8366666666667
},
{
"height":155,
"id":16,
"name":"",
"rotation":0,
"text":
{
"color":"#00007f",
"text":"Reminder: \nThere are 4 cases to test for your away mode (WA tab hidden) settings. \nCamera and microphone stay enabled\nOnly camera stays enabled\nOnly microphone stays enabled\nBoth are disabled",
"wrap":true
},
"type":"",
"visible":true,
"width":407.4375,
"x":96.9479166666667,
"y":322.5
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":44,
"nextobjectid":17,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.7.2",
"tileheight":32,
"tilesets":[
{
"columns":11,
"firstgid":1,
"image":"..\/tileset1.png",
"imageheight":352,
"imagewidth":352,
"margin":0,
"name":"tileset1",
"spacing":0,
"tilecount":121,
"tileheight":32,
"tilewidth":32
}],
"tilewidth":32,
"type":"map",
"version":"1.6",
"width":20
}

View File

@ -463,6 +463,14 @@
<a href="#" class="testLink" data-testmap="mousewheel.json" target="_blank">Testing zoom via mouse wheel</a>
</td>
</tr>
<tr>
<td>
<input type="radio" name="test-mouse-wheel"> Success <input type="radio" name="test-mouse-wheel"> Failure <input type="radio" name="test-mouse-wheel" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="AwayModeSettings/away_mode_settings.json" target="_blank">Away mode settings</a>
</td>
</tr>
</table>
</div>
<script>

View File

@ -124,9 +124,9 @@ ansi-escapes@^4.2.1:
type-fest "^0.21.3"
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
ansi-regex@^5.0.0:
version "5.0.1"

View File

@ -6,7 +6,7 @@
"proto": "grpc_tools_node_protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --grpc_out=generated --js_out=\"import_style=commonjs,binary:generated\" --ts_out=generated -I ./protos protos/*.proto",
"ts-proto": "grpc_tools_node_protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=ts-proto-generated --ts_proto_opt=oneof=unions --ts_proto_opt=esModuleInterop=true protos/*.proto",
"copy-to-back": "rm -rf ../back/src/Messages/generated && cp -rf generated/ ../back/src/Messages/generated",
"copy-to-front-ts-proto": "sed 's/import { Observable } from \"rxjs\";/import type { Observable } from \"rxjs\";/g' ts-proto-generated/protos/messages.ts > ../front/src/Messages/ts-proto-generated/messages.ts",
"copy-to-front-ts-proto": "cp -rf ts-proto-generated/* ../front/src/Messages/ts-proto-generated/ && sed -i 's/import { Observable } from \"rxjs\";/import type { Observable } from \"rxjs\";/g' ../front/src/Messages/ts-proto-generated/protos/messages.ts",
"copy-to-pusher": "rm -rf ../pusher/src/Messages/generated && cp -rf generated/ ../pusher/src/Messages/generated",
"json-copy-to-pusher": "rm -rf ../pusher/src/Messages/JsonMessages/* && cp -rf JsonMessages/* ../pusher/src/Messages/JsonMessages/",
"json-copy-to-back": "rm -rf ../back/src/Messages/JsonMessages/* && cp -rf JsonMessages/* ../back/src/Messages/JsonMessages/",

View File

@ -1,5 +1,7 @@
syntax = "proto3";
import "google/protobuf/wrappers.proto";
/*********** PARTIAL MESSAGES **************/
message PositionMessage {
@ -99,6 +101,10 @@ message FollowAbortMessage {
int32 follower = 2;
}
message LockGroupPromptMessage {
bool lock = 1;
}
message ClientToServerMessage {
oneof message {
UserMovesMessage userMovesMessage = 2;
@ -117,6 +123,7 @@ message ClientToServerMessage {
FollowRequestMessage followRequestMessage = 15;
FollowConfirmationMessage followConfirmationMessage = 16;
FollowAbortMessage followAbortMessage = 17;
LockGroupPromptMessage lockGroupPromptMessage = 18;
}
}
@ -184,7 +191,8 @@ message BatchMessage {
message GroupUpdateMessage {
int32 groupId = 1;
PointMessage position = 2;
int32 groupSize = 3;
google.protobuf.UInt32Value groupSize = 3;
google.protobuf.BoolValue locked = 4;
}
message GroupDeleteMessage {
@ -216,6 +224,11 @@ message ItemStateMessage {
string stateJson = 2;
}
message GroupUsersUpdateMessage {
int32 groupId = 1;
repeated int32 userIds = 2;
}
message RoomJoinedMessage {
//repeated UserJoinedMessage user = 1;
//repeated GroupUpdateMessage group = 2;
@ -316,6 +329,7 @@ message ServerToClientMessage {
FollowConfirmationMessage followConfirmationMessage = 22;
FollowAbortMessage followAbortMessage = 23;
InvalidTextureMessage invalidTextureMessage = 24;
GroupUsersUpdateMessage groupUsersUpdateMessage = 25;
}
}
@ -356,8 +370,9 @@ message UserLeftZoneMessage {
message GroupUpdateZoneMessage {
int32 groupId = 1;
PointMessage position = 2;
int32 groupSize = 3;
int32 groupSize = 3;
Zone fromZone = 4;
bool locked = 5;
}
message GroupLeftZoneMessage {
@ -403,6 +418,7 @@ message PusherToBackMessage {
FollowRequestMessage followRequestMessage = 16;
FollowConfirmationMessage followConfirmationMessage = 17;
FollowAbortMessage followAbortMessage = 18;
LockGroupPromptMessage lockGroupPromptMessage = 19;
}
}

View File

@ -320,10 +320,11 @@ export class AuthenticateController extends BaseHttpController {
//todo: what to do if the organizationMemberToken is already used?
const organizationMemberToken: string | null = param.organizationMemberToken;
const playUri: string | null = param.playUri;
try {
if (typeof organizationMemberToken != "string") throw new Error("No organization token");
const data = await adminApi.fetchMemberDataByToken(organizationMemberToken);
const data = await adminApi.fetchMemberDataByToken(organizationMemberToken, playUri);
const userUuid = data.userUuid;
const email = data.email;
const roomUrl = data.roomUrl;

View File

@ -21,6 +21,7 @@ import {
FollowConfirmationMessage,
FollowAbortMessage,
VariableMessage,
LockGroupPromptMessage,
} from "../Messages/generated/messages_pb";
import { UserMovesMessage } from "../Messages/generated/messages_pb";
import { parse } from "query-string";
@ -561,6 +562,11 @@ export class IoSocketController {
);
} else if (message.hasFollowabortmessage()) {
socketManager.handleFollowAbort(client, message.getFollowabortmessage() as FollowAbortMessage);
} else if (message.hasLockgrouppromptmessage()) {
socketManager.handleLockGroup(
client,
message.getLockgrouppromptmessage() as LockGroupPromptMessage
);
}
/* Ok is false if backpressure was built up, wait for drain */

View File

@ -13,14 +13,14 @@ export class OpenIdProfileController extends BaseHttpController {
}
try {
const resCheckTokenAuth = await openIDClient.checkTokenAuth(accessToken as string);
if (!resCheckTokenAuth.email) {
if (!resCheckTokenAuth.sub) {
throw new Error("Email was not found");
}
res.send(
this.buildHtml(
OPID_CLIENT_ISSUER,
resCheckTokenAuth.email as string,
resCheckTokenAuth.picture as string | undefined
resCheckTokenAuth.sub
/*resCheckTokenAuth.picture as string | undefined*/
)
);
return;

View File

@ -22,6 +22,7 @@ import {
import { ClientReadableStream } from "grpc";
import { PositionDispatcher } from "_Model/PositionDispatcher";
import Debug from "debug";
import { BoolValue, UInt32Value } from "google-protobuf/google/protobuf/wrappers_pb";
const debug = Debug("zone");
@ -123,19 +124,25 @@ export class UserDescriptor {
}
export class GroupDescriptor {
private constructor(public readonly groupId: number, private groupSize: number, private position: PointMessage) {}
private constructor(
public readonly groupId: number,
private groupSize: number | undefined,
private position: PointMessage,
private locked: boolean | undefined
) {}
public static createFromGroupUpdateZoneMessage(message: GroupUpdateZoneMessage): GroupDescriptor {
const position = message.getPosition();
if (position === undefined) {
throw new Error("Missing position");
}
return new GroupDescriptor(message.getGroupid(), message.getGroupsize(), position);
return new GroupDescriptor(message.getGroupid(), message.getGroupsize(), position, message.getLocked());
}
public update(groupDescriptor: GroupDescriptor) {
this.groupSize = groupDescriptor.groupSize;
this.position = groupDescriptor.position;
this.locked = groupDescriptor.locked;
}
public toGroupUpdateMessage(): GroupUpdateMessage {
@ -144,9 +151,13 @@ export class GroupDescriptor {
throw new Error("GroupDescriptor.groupId is not an integer: " + this.groupId);
}
groupUpdateMessage.setGroupid(this.groupId);
groupUpdateMessage.setGroupsize(this.groupSize);
if (this.groupSize !== undefined) {
groupUpdateMessage.setGroupsize(new UInt32Value().setValue(this.groupSize));
}
groupUpdateMessage.setPosition(this.position);
if (this.locked !== undefined) {
groupUpdateMessage.setLocked(new BoolValue().setValue(this.locked));
}
return groupUpdateMessage;
}
}
@ -206,9 +217,7 @@ export class Zone {
this.notifyGroupMove(groupDescriptor);
} else {
this.groups.set(groupId, groupDescriptor);
const fromZone = groupUpdateZoneMessage.getFromzone();
this.notifyGroupEnter(groupDescriptor, fromZone?.toObject());
}
} else if (message.hasUserleftzonemessage()) {

View File

@ -61,7 +61,7 @@ class AdminApi {
async fetchMemberDataByUuid(
userIdentifier: string | null,
roomId: string,
playUri: string,
ipAddress: string,
characterLayers: string[]
): Promise<FetchMemberDataByUuidResponse> {
@ -69,7 +69,12 @@ class AdminApi {
return Promise.reject(new Error("No admin backoffice set!"));
}
const res = await Axios.get<unknown, AxiosResponse<unknown>>(ADMIN_API_URL + "/api/room/access", {
params: { userIdentifier, roomId, ipAddress, characterLayers },
params: {
userIdentifier,
playUri,
ipAddress,
characterLayers,
},
headers: { Authorization: `${ADMIN_API_TOKEN}` },
paramsSerializer: (p) => {
return qs.stringify(p, { arrayFormat: "brackets" });
@ -84,12 +89,13 @@ class AdminApi {
return res.data;
}
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
async fetchMemberDataByToken(organizationMemberToken: string, playUri: string | null): Promise<AdminApiData> {
if (!ADMIN_API_URL) {
return Promise.reject(new Error("No admin backoffice set!"));
}
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
const res = await Axios.get(ADMIN_API_URL + "/api/login-url/" + organizationMemberToken, {
params: { playUri },
headers: { Authorization: `${ADMIN_API_TOKEN}` },
});
if (!isAdminApiData(res.data)) {

View File

@ -38,6 +38,7 @@ import {
ErrorMessage,
WorldFullMessage,
PlayerDetailsUpdatedMessage,
LockGroupPromptMessage,
InvalidTextureMessage,
} from "../Messages/generated/messages_pb";
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
@ -297,6 +298,12 @@ export class SocketManager implements ZoneEventListener {
client.backConnection.write(pusherToBackMessage);
}
handleLockGroup(client: ExSocketInterface, message: LockGroupPromptMessage): void {
const pusherToBackMessage = new PusherToBackMessage();
pusherToBackMessage.setLockgrouppromptmessage(message);
client.backConnection.write(pusherToBackMessage);
}
onEmote(emoteMessage: EmoteEventMessage, listener: ExSocketInterface): void {
const subMessage = new SubMessage();
subMessage.setEmoteeventmessage(emoteMessage);

View File

@ -174,9 +174,9 @@ ansi-escapes@^4.2.1:
type-fest "^0.11.0"
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
ansi-regex@^5.0.0:
version "5.0.0"