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

This commit is contained in:
GRL 2021-05-26 17:22:37 +02:00
commit 5565ddd3f4
42 changed files with 1422 additions and 460 deletions

View file

@ -12,6 +12,7 @@ export abstract class DirtyScene extends ResizableScene {
private isAlreadyTracking: boolean = false;
protected dirty:boolean = true;
private objectListChanged:boolean = true;
private physicsEnabled: boolean = false;
/**
* Track all objects added to the scene and adds a callback each time an animation is added.
@ -38,6 +39,27 @@ export abstract class DirtyScene extends ResizableScene {
this.objectListChanged = false;
this.dirty = false;
});
this.physics.disableUpdate();
this.events.on(Events.POST_UPDATE, () => {
let objectMoving = false;
for (const body of this.physics.world.bodies.entries) {
if (body.velocity.x !== 0 || body.velocity.y !== 0) {
this.objectListChanged = true;
objectMoving = true;
if (!this.physicsEnabled) {
this.physics.enableUpdate();
this.physicsEnabled = true;
}
break;
}
}
if (!objectMoving && this.physicsEnabled) {
this.physics.disableUpdate();
this.physicsEnabled = false;
}
});
}
private trackAnimation(): void {

View file

@ -52,6 +52,7 @@ import { mediaManager } from "../../WebRtc/MediaManager";
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
import type { ActionableItem } from "../Items/ActionableItem";
import { UserInputManager } from "../UserInput/UserInputManager";
import {soundManager} from "./SoundManager";
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
import { connectionManager } from "../../Connexion/ConnectionManager";
@ -92,7 +93,8 @@ import { PinchManager } from "../UserInput/PinchManager";
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
import { waScaleManager } from "../Services/WaScaleManager";
import { EmoteManager } from "./EmoteManager";
import { peerStore} from "../../Stores/PeerStore";
import {EmoteManager } from "./EmoteManager";
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
import { MenuScene, MenuSceneName } from '../Menu/MenuScene';
@ -189,9 +191,7 @@ export class GameScene extends DirtyScene implements CenterListener {
private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>();
private originalMapUrl: string | undefined;
private pinchManager: PinchManager | undefined;
private physicsEnabled: boolean = true;
private mapTransitioning: boolean = false; //used to prevent transitions happenning at the same time.
private onVisibilityChangeCallback: () => void;
private emoteManager!: EmoteManager;
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
@ -212,7 +212,6 @@ export class GameScene extends DirtyScene implements CenterListener {
this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => {
this.connectionAnswerPromiseResolve = resolve;
});
this.onVisibilityChangeCallback = this.onVisibilityChange.bind(this);
}
//hook preload scene
@ -507,8 +506,6 @@ export class GameScene extends DirtyScene implements CenterListener {
if (!this.room.isDisconnected()) {
this.connect();
}
console.log('display');
document.addEventListener('visibilitychange', this.onVisibilityChangeCallback);
this.emoteManager = new EmoteManager(this);
}
@ -615,6 +612,7 @@ export class GameScene extends DirtyScene implements CenterListener {
// When connection is performed, let's connect SimplePeer
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
peerStore.connectToSimplePeer(this.simplePeer);
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
@ -632,7 +630,6 @@ export class GameScene extends DirtyScene implements CenterListener {
self.chatModeSprite.setVisible(false);
self.openChatIcon.setVisible(false);
audioManager.restoreVolume();
self.onVisibilityChange();
}
}
})
@ -870,6 +867,24 @@ ${escapedMessage}
this.userInputManager.disableControls();
}));
this.iframeSubscriptionList.push(iframeListener.playSoundStream.subscribe((playSoundEvent)=>
{
const url = new URL(playSoundEvent.url, this.MapUrlFile);
soundManager.playSound(this.load,this.sound,url.toString(),playSoundEvent.config);
}))
this.iframeSubscriptionList.push(iframeListener.stopSoundStream.subscribe((stopSoundEvent)=>
{
const url = new URL(stopSoundEvent.url, this.MapUrlFile);
soundManager.stopSound(this.sound,url.toString());
}))
this.iframeSubscriptionList.push(iframeListener.loadSoundStream.subscribe((loadSoundEvent)=>
{
const url = new URL(loadSoundEvent.url, this.MapUrlFile);
soundManager.loadSound(this.load,this.sound,url.toString());
}))
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(() => {
this.userInputManager.restoreControls();
}));
@ -1000,8 +1015,6 @@ ${escapedMessage}
for (const iframeEvents of this.iframeSubscriptionList) {
iframeEvents.unsubscribe();
}
document.removeEventListener('visibilitychange', this.onVisibilityChangeCallback);
}
private removeAllRemotePlayers(): void {
@ -1150,8 +1163,6 @@ ${escapedMessage}
}
createCollisionWithPlayer() {
this.physics.disableUpdate();
this.physicsEnabled = false;
//add collision layer
for (const phaserLayer of this.gameMap.phaserLayers) {
if (phaserLayer.type == "tilelayer") {
@ -1294,20 +1305,7 @@ ${escapedMessage}
update(time: number, delta: number): void {
mediaManager.updateScene();
this.currentTick = time;
if (this.CurrentPlayer.isMoving()) {
this.dirty = true;
}
this.CurrentPlayer.moveUser(delta);
if (this.CurrentPlayer.isMoving()) {
this.dirty = true;
if (!this.physicsEnabled) {
this.physics.enableUpdate();
this.physicsEnabled = true;
}
} else if (this.physicsEnabled) {
this.physics.disableUpdate();
this.physicsEnabled = false;
}
// Let's handle all events
while (this.pendingEvents.length !== 0) {
@ -1575,8 +1573,6 @@ ${escapedMessage}
mediaManager.addTriggerCloseJitsiFrameButton('close-jisi', () => {
this.stopJitsi();
});
this.onVisibilityChange();
}
public stopJitsi(): void {
@ -1585,7 +1581,6 @@ ${escapedMessage}
mediaManager.showGameOverlay();
mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi');
this.onVisibilityChange();
}
//todo: put this into an 'orchestrator' scene (EntryScene?)
@ -1625,20 +1620,4 @@ ${escapedMessage}
waScaleManager.zoomModifier *= zoomFactor;
this.updateCameraOffset();
}
private onVisibilityChange(): void {
// If the overlay is not displayed, we are in Jitsi. We don't need the webcam.
if (!mediaManager.isGameOverlayVisible()) {
mediaManager.blurCamera();
return;
}
if (document.visibilityState === 'visible') {
mediaManager.focusCamera();
} else {
if (this.simplePeer.getNbConnections() === 0) {
mediaManager.blurCamera();
}
}
}
}

View file

@ -0,0 +1,37 @@
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
import BaseSoundManager = Phaser.Sound.BaseSoundManager;
import BaseSound = Phaser.Sound.BaseSound;
import SoundConfig = Phaser.Types.Sound.SoundConfig;
class SoundManager {
private soundPromises : Map<string,Promise<BaseSound>> = new Map<string, Promise<Phaser.Sound.BaseSound>>();
public loadSound (loadPlugin: LoaderPlugin, soundManager : BaseSoundManager, soundUrl: string) : Promise<BaseSound> {
let soundPromise = this.soundPromises.get(soundUrl);
if (soundPromise !== undefined) {
return soundPromise;
}
soundPromise = new Promise<BaseSound>((res) => {
const sound = soundManager.get(soundUrl);
if (sound !== null) {
return res(sound);
}
loadPlugin.audio(soundUrl, soundUrl);
loadPlugin.once('filecomplete-audio-' + soundUrl, () => res(soundManager.add(soundUrl)));
loadPlugin.start();
});
this.soundPromises.set(soundUrl,soundPromise);
return soundPromise;
}
public async playSound(loadPlugin: LoaderPlugin, soundManager : BaseSoundManager, soundUrl: string, config: SoundConfig|undefined) : Promise<void> {
const sound = await this.loadSound(loadPlugin,soundManager,soundUrl);
if (config === undefined) sound.play();
else sound.play(config);
}
public stopSound(soundManager : BaseSoundManager,soundUrl : string){
soundManager.get(soundUrl).stop();
}
}
export const soundManager = new SoundManager();

View file

@ -10,6 +10,14 @@ import {PinchManager} from "../UserInput/PinchManager";
import Zone = Phaser.GameObjects.Zone;
import { MenuScene } from "../Menu/MenuScene";
import {ResizableScene} from "./ResizableScene";
import {
audioConstraintStore,
enableCameraSceneVisibilityStore,
localStreamStore,
mediaStreamConstraintsStore,
videoConstraintStore
} from "../../Stores/MediaStore";
import type {Unsubscriber} from "svelte/store";
export const EnableCameraSceneName = "EnableCameraScene";
enum LoginTextures {
@ -40,6 +48,7 @@ export class EnableCameraScene extends ResizableScene {
private enableCameraSceneElement!: Phaser.GameObjects.DOMElement;
private mobileTapZone!: Zone;
private localStreamStoreUnsubscriber!: Unsubscriber;
constructor() {
super({
@ -119,9 +128,20 @@ export class EnableCameraScene extends ResizableScene {
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').classList.add('active');
const mediaPromise = mediaManager.getCamera();
this.localStreamStoreUnsubscriber = localStreamStore.subscribe((result) => {
if (result.type === 'error') {
// TODO: proper handling of the error
throw result.error;
}
this.getDevices();
if (result.stream !== null) {
this.setupStream(result.stream);
}
});
/*const mediaPromise = mediaManager.getCamera();
mediaPromise.then(this.getDevices.bind(this));
mediaPromise.then(this.setupStream.bind(this));
mediaPromise.then(this.setupStream.bind(this));*/
this.input.keyboard.on('keydown-RIGHT', this.nextCam.bind(this));
this.input.keyboard.on('keydown-LEFT', this.previousCam.bind(this));
@ -133,6 +153,8 @@ export class EnableCameraScene extends ResizableScene {
this.add.existing(this.soundMeterSprite);
this.onResize();
enableCameraSceneVisibilityStore.showEnableCameraScene();
}
private previousCam(): void {
@ -140,7 +162,9 @@ export class EnableCameraScene extends ResizableScene {
return;
}
this.cameraSelected--;
mediaManager.setCamera(this.camerasList[this.cameraSelected].deviceId).then(this.setupStream.bind(this));
videoConstraintStore.setDeviceId(this.camerasList[this.cameraSelected].deviceId);
//mediaManager.setCamera(this.camerasList[this.cameraSelected].deviceId).then(this.setupStream.bind(this));
}
private nextCam(): void {
@ -148,8 +172,10 @@ export class EnableCameraScene extends ResizableScene {
return;
}
this.cameraSelected++;
videoConstraintStore.setDeviceId(this.camerasList[this.cameraSelected].deviceId);
// TODO: the change of camera should be OBSERVED (reactive)
mediaManager.setCamera(this.camerasList[this.cameraSelected].deviceId).then(this.setupStream.bind(this));
//mediaManager.setCamera(this.camerasList[this.cameraSelected].deviceId).then(this.setupStream.bind(this));
}
private previousMic(): void {
@ -157,7 +183,8 @@ export class EnableCameraScene extends ResizableScene {
return;
}
this.microphoneSelected--;
mediaManager.setMicrophone(this.microphonesList[this.microphoneSelected].deviceId).then(this.setupStream.bind(this));
audioConstraintStore.setDeviceId(this.microphonesList[this.microphoneSelected].deviceId);
//mediaManager.setMicrophone(this.microphonesList[this.microphoneSelected].deviceId).then(this.setupStream.bind(this));
}
private nextMic(): void {
@ -165,8 +192,9 @@ export class EnableCameraScene extends ResizableScene {
return;
}
this.microphoneSelected++;
audioConstraintStore.setDeviceId(this.microphonesList[this.microphoneSelected].deviceId);
// TODO: the change of camera should be OBSERVED (reactive)
mediaManager.setMicrophone(this.microphonesList[this.microphoneSelected].deviceId).then(this.setupStream.bind(this));
//mediaManager.setMicrophone(this.microphonesList[this.microphoneSelected].deviceId).then(this.setupStream.bind(this));
}
/**
@ -260,15 +288,20 @@ export class EnableCameraScene extends ResizableScene {
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
this.soundMeter.stop();
mediaManager.stopCamera();
mediaManager.stopMicrophone();
enableCameraSceneVisibilityStore.hideEnableCameraScene();
this.localStreamStoreUnsubscriber();
//mediaManager.stopCamera();
//mediaManager.stopMicrophone();
this.scene.sleep(EnableCameraSceneName)
this.scene.sleep(EnableCameraSceneName);
gameManager.goToStartingMap(this.scene);
}
private async getDevices() {
// TODO: switch this in a store.
const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices();
this.microphonesList = [];
this.camerasList = [];
for (const mediaDeviceInfo of mediaDeviceInfos) {
if (mediaDeviceInfo.kind === 'audioinput') {
this.microphonesList.push(mediaDeviceInfo);

View file

@ -2,6 +2,8 @@ import {mediaManager} from "../../WebRtc/MediaManager";
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
import {localUserStore} from "../../Connexion/LocalUserStore";
import {DirtyScene} from "../Game/DirtyScene";
import {get} from "svelte/store";
import {requestedCameraState, requestedMicrophoneState} from "../../Stores/MediaStore";
export const HelpCameraSettingsSceneName = 'HelpCameraSettingsScene';
const helpCameraSettings = 'helpCameraSettings';
@ -41,7 +43,7 @@ export class HelpCameraSettingsScene extends DirtyScene {
}
});
if(!localUserStore.getHelpCameraSettingsShown() && (!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video)){
if(!localUserStore.getHelpCameraSettingsShown() && (!get(requestedMicrophoneState) || !get(requestedCameraState))){
this.openHelpCameraSettingsOpened();
localUserStore.setHelpCameraSettingsShown();
}

View file

@ -13,6 +13,7 @@ import {menuIconVisible} from "../../Stores/MenuStore";
import { HtmlUtils } from '../../WebRtc/HtmlUtils';
import { iframeListener } from '../../Api/IframeListener';
import { Subscription } from 'rxjs';
import { videoConstraintStore } from "../../Stores/MediaStore";
export const MenuSceneName = 'MenuScene';
const gameMenuKey = 'gameMenu';
@ -356,7 +357,7 @@ export class MenuScene extends Phaser.Scene {
if (valueVideo !== this.videoQualityValue) {
this.videoQualityValue = valueVideo;
localUserStore.setVideoQualityValue(valueVideo);
mediaManager.updateCameraQuality(valueVideo);
videoConstraintStore.setFrameRate(valueVideo);
}
this.closeGameQualityMenu();
}

View file

@ -2,6 +2,7 @@ import {PlayerAnimationDirections} from "./Animation";
import type {GameScene} from "../Game/GameScene";
import {UserInputEvent, UserInputManager} from "../UserInput/UserInputManager";
import {Character} from "../Entity/Character";
import {userMovingStore} from "../../Stores/GameStore";
import {RadialMenu, RadialMenuClickEvent, RadialMenuItem} from "../Components/RadialMenu";
export const hasMovedEventName = "hasMoved";
@ -86,6 +87,7 @@ export class Player extends Character {
this.previousDirection = direction;
}
this.wasMoving = moving;
userMovingStore.set(moving);
}
public isMoving(): boolean {
@ -99,7 +101,7 @@ export class Player extends Character {
this.openEmoteMenu(emotes);
}
}
isClickable(): boolean {
return true;
}
@ -113,13 +115,13 @@ export class Player extends Character {
this.playEmote(item.name);
});
}
closeEmoteMenu(): void {
if (!this.emoteMenu) return;
this.emoteMenu.destroy();
this.emoteMenu = null;
}
destroy() {
this.scene.events.removeListener('postupdate', this.updateListener);
super.destroy();