diff --git a/back/src/Model/GameRoom.ts b/back/src/Model/GameRoom.ts index b964477d..14ec328a 100644 --- a/back/src/Model/GameRoom.ts +++ b/back/src/Model/GameRoom.ts @@ -145,7 +145,7 @@ export class GameRoom { joinRoomMessage.getIpaddress(), position, this.positionNotifier, - joinRoomMessage.getStatus(), + joinRoomMessage.getAvailabilitystatus(), socket, joinRoomMessage.getTagList(), joinRoomMessage.getVisitcardurl(), diff --git a/back/src/Model/Group.ts b/back/src/Model/Group.ts index 2ed6c695..5fc86443 100644 --- a/back/src/Model/Group.ts +++ b/back/src/Model/Group.ts @@ -128,7 +128,7 @@ export class Group implements Movable { for (const user of this.positionNotifier.getAllUsersInSquareAroundZone(this.currentZone)) { // Todo: Merge two groups with a leader - if (user.group || this.isFull()) return; //we ignore users that are already in a group. + if (user.silent || user.group || this.isFull()) return; //we ignore users that are already in a group. const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), this.getPosition()); if (distance < this.groupRadius) { this.join(user); diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index d9ed323f..e6f4d39e 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -32,7 +32,7 @@ export class User implements Movable { public readonly IPAddress: string, private position: PointInterface, private positionNotifier: PositionNotifier, - private status: AvailabilityStatus, + private availabilityStatus: AvailabilityStatus, public readonly socket: UserSocket, public readonly tags: string[], public readonly visitCardUrl: string | null, @@ -90,12 +90,15 @@ export class User implements Movable { return this.outlineColor; } - public getStatus(): AvailabilityStatus { - return this.status; + public getAvailabilityStatus(): AvailabilityStatus { + return this.availabilityStatus; } public get silent(): boolean { - return this.status === AvailabilityStatus.SILENT || this.status === AvailabilityStatus.JITSI; + return ( + this.availabilityStatus === AvailabilityStatus.SILENT || + this.availabilityStatus === AvailabilityStatus.JITSI + ); } get following(): User | undefined { @@ -138,10 +141,10 @@ export class User implements Movable { } this.voiceIndicatorShown = details.getShowvoiceindicator()?.getValue(); - const status = details.getStatus(); + const availabilityStatus = details.getAvailabilitystatus(); let sendStatusUpdate = false; - if (status && status !== this.status) { - this.status = status; + if (availabilityStatus && availabilityStatus !== this.availabilityStatus) { + this.availabilityStatus = availabilityStatus; sendStatusUpdate = true; } @@ -157,7 +160,7 @@ export class User implements Movable { playerDetails.setShowvoiceindicator(new BoolValue().setValue(this.voiceIndicatorShown)); } if (sendStatusUpdate) { - playerDetails.setStatus(details.getStatus()); + playerDetails.setAvailabilitystatus(details.getAvailabilitystatus()); } this.positionNotifier.updatePlayerDetails(this, playerDetails); diff --git a/back/src/Services/SocketManager.ts b/back/src/Services/SocketManager.ts index 5af1096f..5dce5d3b 100644 --- a/back/src/Services/SocketManager.ts +++ b/back/src/Services/SocketManager.ts @@ -323,7 +323,7 @@ export class SocketManager { userJoinedZoneMessage.setUserid(thing.id); userJoinedZoneMessage.setUseruuid(thing.uuid); userJoinedZoneMessage.setName(thing.name); - userJoinedZoneMessage.setStatus(thing.getStatus()); + userJoinedZoneMessage.setAvailabilitystatus(thing.getAvailabilityStatus()); userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); userJoinedZoneMessage.setFromzone(this.toProtoZone(fromZone)); @@ -651,7 +651,7 @@ export class SocketManager { userJoinedMessage.setUserid(thing.id); userJoinedMessage.setUseruuid(thing.uuid); userJoinedMessage.setName(thing.name); - userJoinedMessage.setStatus(thing.getStatus()); + userJoinedMessage.setAvailabilitystatus(thing.getAvailabilityStatus()); userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); if (thing.visitCardUrl) { diff --git a/benchmark/index.ts b/benchmark/index.ts index 36d2c6f4..eee0faa5 100644 --- a/benchmark/index.ts +++ b/benchmark/index.ts @@ -1,6 +1,7 @@ import {RoomConnection} from "../front/src/Connexion/RoomConnection"; import {connectionManager} from "../front/src/Connexion/ConnectionManager"; import * as WebSocket from "ws" +import { AvailabilityStatus } from '../front/src/Messages/ts-proto-generated/protos/messages'; let userMovedCount = 0; @@ -22,7 +23,9 @@ async function startOneUser(): Promise { bottom: 200, left: 500, right: 800 - }, null); + }, + null, + AvailabilityStatus.ONLINE); const connection = onConnect.connection; diff --git a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte index 940268d6..ec8ef85d 100644 --- a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte +++ b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte @@ -118,7 +118,7 @@ /> - {#if coWebsite.getHint() && $state === "asleep" } + {#if !isMain && !isHighlight }

{@html sanitize(i18n(coWebsite.getHint()))}

diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 4ab1b350..51b8f904 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -20,6 +20,7 @@ import { locales } from "../i18n/i18n-util"; import type { Locales } from "../i18n/i18n-types"; import { setCurrentLocale } from "../i18n/locales"; import type { World } from "./World"; +import { AvailabilityStatus } from "../Messages/ts-proto-generated/protos/messages"; class ConnectionManager { private localUser!: LocalUser; @@ -277,7 +278,8 @@ class ConnectionManager { characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, - companion: string | null + companion: string | null, + availabilityStatus: AvailabilityStatus ): Promise { return new Promise((resolve, reject) => { const connection = new RoomConnection( @@ -287,7 +289,8 @@ class ConnectionManager { characterLayers, position, viewport, - companion + companion, + availabilityStatus ); connection.onConnectError((error: object) => { @@ -341,9 +344,15 @@ class ConnectionManager { this.reconnectingTimeout = setTimeout(() => { //todo: allow a way to break recursion? //todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely. - void this.connectToRoomSocket(roomUrl, name, characterLayers, position, viewport, companion).then( - (connection) => resolve(connection) - ); + void this.connectToRoomSocket( + roomUrl, + name, + characterLayers, + position, + viewport, + companion, + availabilityStatus + ).then((connection) => resolve(connection)); }, 4000 + Math.floor(Math.random() * 2000)); }); }); diff --git a/front/src/Connexion/ConnexionModels.ts b/front/src/Connexion/ConnexionModels.ts index d3909f55..aed8dcc7 100644 --- a/front/src/Connexion/ConnexionModels.ts +++ b/front/src/Connexion/ConnexionModels.ts @@ -15,7 +15,7 @@ export interface MessageUserPositionInterface { name: string; characterLayers: BodyResourceDescriptionInterface[]; position: PointInterface; - status: AvailabilityStatus; + availabilityStatus: AvailabilityStatus; visitCardUrl: string | null; companion: string | null; userUuid: string; @@ -31,7 +31,7 @@ export interface MessageUserJoined { name: string; characterLayers: BodyResourceDescriptionInterface[]; position: PointInterface; - status: AvailabilityStatus; + availabilityStatus: AvailabilityStatus; visitCardUrl: string | null; companion: string | null; userUuid: string; diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index b220cd16..c0747ed8 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -154,6 +154,7 @@ export class RoomConnection implements RoomConnection { * @param position * @param viewport * @param companion + * @param availabilityStatus */ public constructor( token: string | null, @@ -162,7 +163,8 @@ export class RoomConnection implements RoomConnection { characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, - companion: string | null + companion: string | null, + availabilityStatus: AvailabilityStatus ) { let url = new URL(PUSHER_URL, window.location.toString()).toString(); url = url.replace("http://", "ws://").replace("https://", "wss://"); @@ -185,6 +187,9 @@ export class RoomConnection implements RoomConnection { if (typeof companion === "string") { url += "&companion=" + encodeURIComponent(companion); } + if (typeof availabilityStatus === "number") { + url += "&availabilityStatus=" + availabilityStatus; + } if (RoomConnection.websocketFactory) { this.socket = RoomConnection.websocketFactory(url); @@ -537,9 +542,9 @@ export class RoomConnection implements RoomConnection { this.socket.send(bytes); } - public emitPlayerStatusChange(status: AvailabilityStatus): void { + public emitPlayerStatusChange(availabilityStatus: AvailabilityStatus): void { const message = SetPlayerDetailsMessageTsProto.fromPartial({ - status, + availabilityStatus, }); const bytes = ClientToServerMessageTsProto.encode({ message: { @@ -562,7 +567,6 @@ export class RoomConnection implements RoomConnection { outlineColor: color, }); } - const bytes = ClientToServerMessageTsProto.encode({ message: { $case: "setPlayerDetailsMessage", @@ -674,7 +678,7 @@ export class RoomConnection implements RoomConnection { characterLayers, visitCardUrl: message.visitCardUrl, position: ProtobufClientUtils.toPointInterface(position), - status: message.status, + availabilityStatus: message.availabilityStatus, companion: companion ? companion.name : null, userUuid: message.userUuid, outlineColor: message.hasOutline ? message.outlineColor : undefined, diff --git a/front/src/Phaser/Components/PlayerStatusDot.ts b/front/src/Phaser/Components/PlayerStatusDot.ts index d85cce86..75292aee 100644 --- a/front/src/Phaser/Components/PlayerStatusDot.ts +++ b/front/src/Phaser/Components/PlayerStatusDot.ts @@ -5,7 +5,7 @@ export class PlayerStatusDot extends Phaser.GameObjects.Container { private statusImage: Phaser.GameObjects.Image; private statusImageOutline: Phaser.GameObjects.Image; - private status: AvailabilityStatus; + private availabilityStatus: AvailabilityStatus; private readonly COLORS: Record = { [AvailabilityStatus.AWAY]: { filling: 0xf5931e, outline: 0x875d13 }, @@ -19,7 +19,7 @@ export class PlayerStatusDot extends Phaser.GameObjects.Container { constructor(scene: Phaser.Scene, x: number, y: number) { super(scene, x, y); - this.status = AvailabilityStatus.ONLINE; + this.availabilityStatus = AvailabilityStatus.ONLINE; this.statusImage = this.scene.add.image(0, 0, "iconStatusIndicatorInside"); this.statusImageOutline = this.scene.add.image(0, 0, "iconStatusIndicatorOutline"); @@ -31,11 +31,11 @@ export class PlayerStatusDot extends Phaser.GameObjects.Container { this.scene.add.existing(this); } - public setStatus(status: AvailabilityStatus, instant: boolean = false): void { - if (this.status === status || status === AvailabilityStatus.UNCHANGED) { + public setAvailabilityStatus(availabilityStatus: AvailabilityStatus, instant: boolean = false): void { + if (this.availabilityStatus === availabilityStatus || availabilityStatus === AvailabilityStatus.UNCHANGED) { return; } - this.status = status; + this.availabilityStatus = availabilityStatus; if (instant) { this.redraw(); } else { @@ -61,7 +61,7 @@ export class PlayerStatusDot extends Phaser.GameObjects.Container { } private redraw(): void { - const colors = this.COLORS[this.status]; + const colors = this.COLORS[this.availabilityStatus]; this.statusImage.setTintFill(colors.filling); this.statusImageOutline.setTintFill(colors.outline); } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 1cbd85f4..a45eeaa4 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -236,8 +236,8 @@ export abstract class Character extends Container implements OutlineableInterfac this.talkIcon.show(show, forceClose); } - public setStatus(status: AvailabilityStatus, instant: boolean = false): void { - this.statusDot.setStatus(status, instant); + public setAvailabilityStatus(availabilityStatus: AvailabilityStatus, instant: boolean = false): void { + this.statusDot.setAvailabilityStatus(availabilityStatus, instant); } public addCompanion(name: string, texturePromise?: CancelablePromise): void { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 2f8ca376..23a628bd 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -174,17 +174,17 @@ export class GameScene extends DirtyScene { // A promise that will resolve when the "create" method is called (signaling loading is ended) private createPromiseDeferred: Deferred; private iframeSubscriptionList!: Array; - private peerStoreUnsubscribe!: Unsubscriber; - private emoteUnsubscribe!: Unsubscriber; - private emoteMenuUnsubscribe!: Unsubscriber; + private peerStoreUnsubscriber!: Unsubscriber; + private emoteUnsubscriber!: Unsubscriber; + private emoteMenuUnsubscriber!: Unsubscriber; private localVolumeStoreUnsubscriber: Unsubscriber | undefined; - private followUsersColorStoreUnsubscribe!: Unsubscriber; + private followUsersColorStoreUnsubscriber!: Unsubscriber; private userIsJitsiDominantSpeakerStoreUnsubscriber!: Unsubscriber; private jitsiParticipantsCountStoreUnsubscriber!: Unsubscriber; private availabilityStatusStoreUnsubscriber!: Unsubscriber; - private biggestAvailableAreaStoreUnsubscribe!: () => void; + private biggestAvailableAreaStoreUnsubscriber!: () => void; MapUrlFile: string; roomUrl: string; @@ -660,11 +660,6 @@ export class GameScene extends DirtyScene { this.reposition(); - // From now, this game scene will be notified of reposition events - this.biggestAvailableAreaStoreUnsubscribe = biggestAvailableAreaStore.subscribe((box) => - this.cameraManager.updateCameraOffset(box) - ); - new GameMapPropertiesListener(this, this.gameMap).register(); if (!this.room.isDisconnected()) { @@ -672,80 +667,6 @@ export class GameScene extends DirtyScene { this.connect(); } - const talkIconVolumeTreshold = 10; - let oldPeersNumber = 0; - this.peerStoreUnsubscribe = peerStore.subscribe((peers) => { - const newPeerNumber = peers.size; - if (newPeerNumber > oldPeersNumber) { - this.playSound("audio-webrtc-in"); - } else if (newPeerNumber < oldPeersNumber) { - this.playSound("audio-webrtc-out"); - } - if (newPeerNumber > 0) { - if (!this.localVolumeStoreUnsubscriber) { - this.localVolumeStoreUnsubscriber = localVolumeStore.subscribe((volume) => { - if (volume === undefined) { - return; - } - this.tryChangeShowVoiceIndicatorState(volume > talkIconVolumeTreshold); - }); - } - } else { - this.CurrentPlayer.showTalkIcon(false, true); - this.connection?.emitPlayerShowVoiceIndicator(false); - this.showVoiceIndicatorChangeMessageSent = false; - this.MapPlayersByKey.forEach((remotePlayer) => remotePlayer.showTalkIcon(false, true)); - if (this.localVolumeStoreUnsubscriber) { - this.localVolumeStoreUnsubscriber(); - this.localVolumeStoreUnsubscriber = undefined; - } - } - oldPeersNumber = peers.size; - }); - - this.userIsJitsiDominantSpeakerStoreUnsubscriber = userIsJitsiDominantSpeakerStore.subscribe( - (dominantSpeaker) => { - this.jitsiDominantSpeaker = dominantSpeaker; - this.tryChangeShowVoiceIndicatorState(this.jitsiDominantSpeaker && this.jitsiParticipantsCount > 1); - } - ); - - this.jitsiParticipantsCountStoreUnsubscriber = jitsiParticipantsCountStore.subscribe((participantsCount) => { - this.jitsiParticipantsCount = participantsCount; - this.tryChangeShowVoiceIndicatorState(this.jitsiDominantSpeaker && this.jitsiParticipantsCount > 1); - }); - - this.availabilityStatusStoreUnsubscriber = availabilityStatusStore.subscribe((status) => { - this.connection?.emitPlayerStatusChange(status); - this.CurrentPlayer.setStatus(status); - }); - - this.emoteUnsubscribe = emoteStore.subscribe((emote) => { - if (emote) { - this.CurrentPlayer?.playEmote(emote.unicode); - this.connection?.emitEmoteEvent(emote.unicode); - emoteStore.set(null); - } - }); - - this.emoteMenuUnsubscribe = emoteMenuStore.subscribe((emoteMenu) => { - if (emoteMenu) { - this.userInputManager.disableControls(); - } else { - this.userInputManager.restoreControls(); - } - }); - - this.followUsersColorStoreUnsubscribe = followUsersColorStore.subscribe((color) => { - if (color !== undefined) { - this.CurrentPlayer.setFollowOutlineColor(color); - this.connection?.emitPlayerOutlineColor(color); - } else { - this.CurrentPlayer.removeFollowOutlineColor(); - this.connection?.emitPlayerOutlineColor(null); - } - }); - Promise.all([ this.connectionAnswerPromiseDeferred.promise as Promise, ...scriptPromises, @@ -782,11 +703,14 @@ export class GameScene extends DirtyScene { right: camera.scrollX + camera.width, bottom: camera.scrollY + camera.height, }, - this.companion + this.companion, + get(availabilityStatusStore) ) .then((onConnect: OnConnectInterface) => { this.connection = onConnect.connection; + this.subscribeToStores(); + lazyLoadPlayerCharacterTextures(this.superLoad, onConnect.room.characterLayers) .then((layers) => { this.currentPlayerTexturesResolve(layers); @@ -804,7 +728,7 @@ export class GameScene extends DirtyScene { characterLayers: message.characterLayers, name: message.name, position: message.position, - status: message.status, + availabilityStatus: message.availabilityStatus, visitCardUrl: message.visitCardUrl, companion: message.companion, userUuid: message.userUuid, @@ -969,6 +893,87 @@ export class GameScene extends DirtyScene { .catch((e) => console.error(e)); } + private subscribeToStores(): void { + this.userIsJitsiDominantSpeakerStoreUnsubscriber = userIsJitsiDominantSpeakerStore.subscribe( + (dominantSpeaker) => { + this.jitsiDominantSpeaker = dominantSpeaker; + this.tryChangeShowVoiceIndicatorState(this.jitsiDominantSpeaker && this.jitsiParticipantsCount > 1); + } + ); + + this.jitsiParticipantsCountStoreUnsubscriber = jitsiParticipantsCountStore.subscribe((participantsCount) => { + this.jitsiParticipantsCount = participantsCount; + this.tryChangeShowVoiceIndicatorState(this.jitsiDominantSpeaker && this.jitsiParticipantsCount > 1); + }); + + this.availabilityStatusStoreUnsubscriber = availabilityStatusStore.subscribe((availabilityStatus) => { + this.connection?.emitPlayerStatusChange(availabilityStatus); + this.CurrentPlayer.setAvailabilityStatus(availabilityStatus); + }); + + this.emoteUnsubscriber = emoteStore.subscribe((emote) => { + if (emote) { + this.CurrentPlayer?.playEmote(emote.url); + this.connection?.emitEmoteEvent(emote.url); + emoteStore.set(null); + } + }); + + this.emoteMenuUnsubscriber = emoteMenuStore.subscribe((emoteMenu) => { + if (emoteMenu) { + this.userInputManager.disableControls(); + } else { + this.userInputManager.restoreControls(); + } + }); + + this.followUsersColorStoreUnsubscriber = followUsersColorStore.subscribe((color) => { + if (color !== undefined) { + this.CurrentPlayer.setFollowOutlineColor(color); + this.connection?.emitPlayerOutlineColor(color); + } else { + this.CurrentPlayer.removeFollowOutlineColor(); + this.connection?.emitPlayerOutlineColor(null); + } + }); + + // From now, this game scene will be notified of reposition events + this.biggestAvailableAreaStoreUnsubscriber = biggestAvailableAreaStore.subscribe((box) => + this.cameraManager.updateCameraOffset(box) + ); + + const talkIconVolumeTreshold = 10; + let oldPeersNumber = 0; + this.peerStoreUnsubscriber = peerStore.subscribe((peers) => { + const newPeerNumber = peers.size; + if (newPeerNumber > oldPeersNumber) { + this.playSound("audio-webrtc-in"); + } else if (newPeerNumber < oldPeersNumber) { + this.playSound("audio-webrtc-out"); + } + if (newPeerNumber > 0) { + if (!this.localVolumeStoreUnsubscriber) { + this.localVolumeStoreUnsubscriber = localVolumeStore.subscribe((volume) => { + if (volume === undefined) { + return; + } + this.tryChangeShowVoiceIndicatorState(volume > talkIconVolumeTreshold); + }); + } + } else { + this.CurrentPlayer.showTalkIcon(false, true); + this.connection?.emitPlayerShowVoiceIndicator(false); + this.showVoiceIndicatorChangeMessageSent = false; + this.MapPlayersByKey.forEach((remotePlayer) => remotePlayer.showTalkIcon(false, true)); + if (this.localVolumeStoreUnsubscriber) { + this.localVolumeStoreUnsubscriber(); + this.localVolumeStoreUnsubscriber = undefined; + } + } + oldPeersNumber = peers.size; + }); + } + //todo: into dedicated classes private initCirclesCanvas(): void { // Let's generate the circle for the group delimiter @@ -1643,11 +1648,11 @@ export class GameScene extends DirtyScene { this.pinchManager?.destroy(); this.emoteManager?.destroy(); this.cameraManager.destroy(); - this.peerStoreUnsubscribe(); - this.emoteUnsubscribe(); - this.emoteMenuUnsubscribe(); - this.followUsersColorStoreUnsubscribe(); - this.biggestAvailableAreaStoreUnsubscribe(); + this.peerStoreUnsubscriber(); + this.emoteUnsubscriber(); + this.emoteMenuUnsubscriber(); + this.followUsersColorStoreUnsubscriber(); + this.biggestAvailableAreaStoreUnsubscriber(); this.userIsJitsiDominantSpeakerStoreUnsubscriber(); this.jitsiParticipantsCountStoreUnsubscriber(); this.availabilityStatusStoreUnsubscriber(); @@ -2023,8 +2028,8 @@ export class GameScene extends DirtyScene { if (addPlayerData.outlineColor !== undefined) { player.setApiOutlineColor(addPlayerData.outlineColor); } - if (addPlayerData.status !== undefined) { - player.setStatus(addPlayerData.status, true); + if (addPlayerData.availabilityStatus !== undefined) { + player.setAvailabilityStatus(addPlayerData.availabilityStatus, true); } this.MapPlayers.add(player); this.MapPlayersByKey.set(player.userId, player); @@ -2175,8 +2180,8 @@ export class GameScene extends DirtyScene { if (message.details?.showVoiceIndicator !== undefined) { character.showTalkIcon(message.details?.showVoiceIndicator); } - if (message.details?.status !== undefined) { - character.setStatus(message.details?.status); + if (message.details?.availabilityStatus !== undefined) { + character.setAvailabilityStatus(message.details?.availabilityStatus); } } diff --git a/front/src/Phaser/Game/PlayerInterface.ts b/front/src/Phaser/Game/PlayerInterface.ts index c6ac3420..0f5853a6 100644 --- a/front/src/Phaser/Game/PlayerInterface.ts +++ b/front/src/Phaser/Game/PlayerInterface.ts @@ -8,7 +8,7 @@ export interface PlayerInterface { visitCardUrl: string | null; companion: string | null; userUuid: string; - status: AvailabilityStatus; + availabilityStatus: AvailabilityStatus; color?: string; outlineColor?: number; } diff --git a/front/src/Phaser/Login/SelectCharacterScene.ts b/front/src/Phaser/Login/SelectCharacterScene.ts index 4f1316b0..b6d0b207 100644 --- a/front/src/Phaser/Login/SelectCharacterScene.ts +++ b/front/src/Phaser/Login/SelectCharacterScene.ts @@ -193,7 +193,6 @@ export class SelectCharacterScene extends AbstractCharacterScene { } catch (error) { console.warn(error); } - this.charactersDraggableGrid.setItemsInRow(this.gridRowsCount); this.populateGrid(); } @@ -203,12 +202,20 @@ export class SelectCharacterScene extends AbstractCharacterScene { this.selectedWoka = null; this.charactersDraggableGrid.clearAllItems(); const textures = this.playerTextures.getWokaCollectionTextures(this.getSelectedCollectionName()); + + let currentSelectedItem = null; for (let i = 0; i < textures.length; i += 1) { const slot = new WokaSlot(this, textures[i].id).setDisplaySize(wokaDimension, wokaDimension); + + //ini current Select Item to the first + if (i === 0) currentSelectedItem = slot; + this.charactersDraggableGrid.addItem(slot); } this.charactersDraggableGrid.moveContentToBeginning(); - void this.charactersDraggableGrid.moveContentTo(0.5, textures.length * 50); + + //Select the first Woka + if (currentSelectedItem) this.selectGridItem(currentSelectedItem); } private bindEventHandlers(): void { diff --git a/front/src/Stores/PlayersStore.ts b/front/src/Stores/PlayersStore.ts index be270b5a..21615581 100644 --- a/front/src/Stores/PlayersStore.ts +++ b/front/src/Stores/PlayersStore.ts @@ -29,7 +29,7 @@ function createPlayersStore() { visitCardUrl: message.visitCardUrl, companion: message.companion, userUuid: message.userUuid, - status: message.status, + availabilityStatus: message.availabilityStatus, color: getRandomColor(), }); return users; @@ -59,7 +59,7 @@ function createPlayersStore() { characterLayers: [], visitCardUrl: null, companion: null, - status: AvailabilityStatus.ONLINE, + availabilityStatus: AvailabilityStatus.ONLINE, userUuid: "dummy", color: getRandomColor(), }); diff --git a/maps/tests/Properties/silent_start.json b/maps/tests/Properties/silent_start.json new file mode 100644 index 00000000..7d9ed8f2 --- /dev/null +++ b/maps/tests/Properties/silent_start.json @@ -0,0 +1,133 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":10, + "id":1, + "name":"floor", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 34, 34, 34, 0, 0, 0, 0, + 0, 0, 0, 34, 34, 34, 0, 0, 0, 0, + 0, 0, 0, 34, 34, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":5, + "name":"silent", + "opacity":1, + "properties":[ + { + "name":"silent", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 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], + "height":10, + "id":2, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":3, + "name":"floorLayer", + "objects":[ + { + "height":117.648909831483, + "id":1, + "name":"", + "properties":[ + { + "name":"font-family", + "type":"string", + "value":"\"Press Start 2P\"" + }], + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":8, + "text":"Test:\nConnect with user A, do not move.\n\nResult:\nUser A starts in a silent zone, the status icon is red.\n\nTest:\nConnect with user B, do not move.\n\nResult:\nUser B is NOT connected to user A.\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":317.361946929159, + "x":0.32853056864467, + "y":194.102707451482 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":6, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.8.4", + "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.8", + "width":10 +} \ No newline at end of file diff --git a/maps/tests/index.html b/maps/tests/index.html index 68c03f79..5c849315 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -176,6 +176,14 @@ Test Tiled Objects with properties + + + Success Failure Pending + + + Test start on silent zone + +

Iframe API

diff --git a/messages/protos/messages.proto b/messages/protos/messages.proto index 68099982..d1a3eebf 100644 --- a/messages/protos/messages.proto +++ b/messages/protos/messages.proto @@ -57,7 +57,7 @@ message SetPlayerDetailsMessage { google.protobuf.UInt32Value outlineColor = 3; google.protobuf.BoolValue removeOutlineColor = 4; google.protobuf.BoolValue showVoiceIndicator = 5; - AvailabilityStatus status = 6; + AvailabilityStatus availabilityStatus = 6; } message UserMovesMessage { @@ -210,7 +210,7 @@ message UserJoinedMessage { string userUuid = 7; uint32 outlineColor = 8; bool hasOutline = 9; - AvailabilityStatus status = 10; + AvailabilityStatus availabilityStatus = 10; } message UserLeftMessage { @@ -369,7 +369,7 @@ message JoinRoomMessage { CompanionMessage companion = 8; string visitCardUrl = 9; string userRoomToken = 10; - AvailabilityStatus status = 11; + AvailabilityStatus availabilityStatus = 11; } message UserJoinedZoneMessage { @@ -383,7 +383,7 @@ message UserJoinedZoneMessage { string userUuid = 8; uint32 outlineColor = 9; bool hasOutline = 10; - AvailabilityStatus status = 11; + AvailabilityStatus availabilityStatus = 11; } message UserLeftZoneMessage { diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 27b66ef0..46c5145f 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -20,6 +20,7 @@ import { FollowAbortMessage, VariableMessage, LockGroupPromptMessage, + AvailabilityStatus, } from "../Messages/generated/messages_pb"; import { UserMovesMessage } from "../Messages/generated/messages_pb"; import { parse } from "query-string"; @@ -53,6 +54,7 @@ interface UpgradeData { roomId: string; name: string; companion: CompanionMessage | undefined; + availabilityStatus: AvailabilityStatus; characterLayers: WokaDetail[]; messages: unknown[]; tags: string[]; @@ -259,6 +261,7 @@ export class IoSocketController { const left = Number(query.left); const right = Number(query.right); const name = query.name; + const availabilityStatus = Number(query.availabilityStatus); let companion: CompanionMessage | undefined = undefined; @@ -270,6 +273,9 @@ export class IoSocketController { if (typeof name !== "string") { throw new Error("Expecting name"); } + if (typeof availabilityStatus !== "number") { + throw new Error("Expecting availability status"); + } if (name === "") { throw new Error("No empty name"); } @@ -411,6 +417,7 @@ export class IoSocketController { roomId, name, companion, + availabilityStatus, characterLayers: characterLayerObjs, messages: memberMessages, tags: memberTags, @@ -612,6 +619,7 @@ export class IoSocketController { client.visitCardUrl = ws.visitCardUrl; client.characterLayers = ws.characterLayers; client.companion = ws.companion; + client.availabilityStatus = ws.availabilityStatus; client.roomId = ws.roomId; client.listenedZones = new Set(); return client; diff --git a/pusher/src/Model/Websocket/ExSocketInterface.ts b/pusher/src/Model/Websocket/ExSocketInterface.ts index 53547fdf..d0420906 100644 --- a/pusher/src/Model/Websocket/ExSocketInterface.ts +++ b/pusher/src/Model/Websocket/ExSocketInterface.ts @@ -2,6 +2,7 @@ import { PointInterface } from "./PointInterface"; import { Identificable } from "./Identificable"; import { ViewportInterface } from "../../Model/Websocket/ViewportMessage"; import { + AvailabilityStatus, BatchMessage, CompanionMessage, PusherToBackMessage, @@ -26,6 +27,7 @@ export interface ExSocketInterface extends compressors.WebSocket, Identificable position: PointInterface; viewport: ViewportInterface; companion?: CompanionMessage; + availabilityStatus: AvailabilityStatus; /** * Pushes an event that will be sent in the next batch of events */ diff --git a/pusher/src/Model/Zone.ts b/pusher/src/Model/Zone.ts index c15aeefd..46623565 100644 --- a/pusher/src/Model/Zone.ts +++ b/pusher/src/Model/Zone.ts @@ -50,7 +50,7 @@ export class UserDescriptor { private name: string, private characterLayers: CharacterLayerMessage[], private position: PositionMessage, - private status: AvailabilityStatus, + private availabilityStatus: AvailabilityStatus, private visitCardUrl: string | null, private companion?: CompanionMessage, private outlineColor?: number @@ -71,7 +71,7 @@ export class UserDescriptor { message.getName(), message.getCharacterlayersList(), position, - message.getStatus(), + message.getAvailabilitystatus(), message.getVisitcardurl(), message.getCompanion(), message.getHasoutline() ? message.getOutlinecolor() : undefined @@ -92,9 +92,9 @@ export class UserDescriptor { } else { this.outlineColor = playerDetails.getOutlinecolor()?.getValue(); } - const status = playerDetails.getStatus(); - if (status !== undefined) { - this.status = status; + const availabilityStatus = playerDetails.getAvailabilitystatus(); + if (availabilityStatus !== undefined) { + this.availabilityStatus = availabilityStatus; } } @@ -105,7 +105,7 @@ export class UserDescriptor { userJoinedMessage.setName(this.name); userJoinedMessage.setCharacterlayersList(this.characterLayers); userJoinedMessage.setPosition(this.position); - userJoinedMessage.setStatus(this.status); + userJoinedMessage.setAvailabilitystatus(this.availabilityStatus); if (this.visitCardUrl) { userJoinedMessage.setVisitcardurl(this.visitCardUrl); } diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index cca544c9..08b39e96 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -175,6 +175,7 @@ export class SocketManager implements ZoneEventListener { joinRoomMessage.setIpaddress(client.IPAddress); joinRoomMessage.setRoomid(client.roomId); joinRoomMessage.setName(client.name); + joinRoomMessage.setAvailabilitystatus(client.availabilityStatus); joinRoomMessage.setPositionmessage(ProtobufUtils.toPositionMessage(client.position)); joinRoomMessage.setTagList(client.tags);