Merge branch 'develop' of github.com:thecodingmachine/workadventure into develop

This commit is contained in:
_Bastler
2022-05-11 11:51:32 +02:00
22 changed files with 327 additions and 144 deletions
@@ -118,7 +118,7 @@
/>
</div>
{#if coWebsite.getHint() && $state === "asleep" }
{#if !isMain && !isHighlight }
<div class="cowebsite-thumbnail-hint nes-balloon from-left">
<p>{@html sanitize(i18n(coWebsite.getHint()))}</p>
</div>
+14 -5
View File
@@ -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<OnConnectInterface> {
return new Promise<OnConnectInterface>((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));
});
});
+2 -2
View File
@@ -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;
+9 -5
View File
@@ -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,
@@ -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, { filling: number; outline: number }> = {
[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);
}
+2 -2
View File
@@ -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<string>): void {
+100 -95
View File
@@ -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<void>;
private iframeSubscriptionList!: Array<Subscription>;
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<unknown>,
...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);
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ export interface PlayerInterface {
visitCardUrl: string | null;
companion: string | null;
userUuid: string;
status: AvailabilityStatus;
availabilityStatus: AvailabilityStatus;
color?: string;
outlineColor?: number;
}
@@ -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 {
+2 -2
View File
@@ -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(),
});