Merge pull request #579 from thecodingmachine/develop

merge develop into master 8/01/2021
This commit is contained in:
David Négrier 2021-01-11 23:45:12 +01:00 committed by GitHub
commit fc50a64301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 503 additions and 139 deletions

View File

@ -37,7 +37,7 @@
},
"homepage": "https://github.com/thecodingmachine/workadventure#readme",
"dependencies": {
"axios": "^0.20.0",
"axios": "^0.21.1",
"body-parser": "^1.19.0",
"busboy": "^0.3.1",
"circular-json": "^0.5.9",
@ -52,7 +52,7 @@
"multer": "^1.4.2",
"prom-client": "^12.0.0",
"query-string": "^6.13.3",
"systeminformation": "^4.30.5",
"systeminformation": "^4.31.1",
"ts-node-dev": "^1.0.0-pre.44",
"typescript": "^3.8.3",
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",

View File

@ -335,10 +335,10 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
@ -2723,10 +2723,10 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
systeminformation@^4.30.5:
version "4.30.5"
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.30.5.tgz#2219c305c8be56a2cfa527a5519c45bc81d4916c"
integrity sha512-aYWs8yttl8ePpr6VOQ/Ak8cznuc9L/NQODVhbOKhInX73ZMLvV2BS86Mzr7LLfmUteVFR36CTDNQgiJgRqq+SQ==
systeminformation@^4.31.1:
version "4.31.1"
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.31.1.tgz#2e02c26987494d4b6a4d2d83138724593bc98d50"
integrity sha512-dVCDWNMN8ncMZo5vbMCA5dpAdMgzafK2ucuJy5LFmGtp1cG6farnPg8QNvoOSky9SkFoEX1Aw0XhcOFV6TnLYA==
table@^5.2.3:
version "5.4.6"

58
front/dist/index.html vendored
View File

@ -39,7 +39,7 @@
<link rel="stylesheet" href="/resources/style/style.css">
<title>WorkAdventure</title>
</head>
<body id="body" style="margin: 0">
<body id="body" style="margin: 0; background-color: #000">
<div class="main-container" id="main-container">
<!-- Create the editor container -->
<div id="game" class="game">
@ -81,6 +81,62 @@
<img src="/resources/logos/megaphone.svg"/>
</div>
</div>
<div id="audioplayerctrl" class="hidden">
<div class="audioplayer">
<button type="button" id="audioplayer_mute" class="fa fa-volump-up">
<svg
width="1em"
height="1em"
viewBox="0 0 16 16"
class="bi bi-volume-up"
fill="white"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z"
/>
<g id="audioplayer_volume_icon_playing">
<path
d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z"
/>
<path
d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z"
/>
<path
d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z"
/>
</g>
</svg>
</button>
<div class="audioplayer">
<input
type="range"
id="audioplayer_volume"
min="0"
max="1"
step="0.05"
value="1"
/>
</div>
</div>
<div class="audioplayer">
<label
id="label-audioplayer_decrease_while_talking"
for="audiooplayer_decrease_while_talking"
title="decrease background volume by 50% when entering conversations"
>
autoreduce
<input type="checkbox" id="audioplayer_decrease_while_talking" checked />
</label>
<div id="audioplayer" style="visibility: hidden"></div>
</div>
</div>
<div class="audio-playing">
<img src="/resources/logos/megaphone.svg" />
</div>
</div>
<!--
<div id="webRtc" class="webrtc">
<div id="activeCam" class="activeCam">

View File

@ -362,6 +362,148 @@ body {
height: 100%;
}
.audioplayer:first-child {
display: grid;
grid: 2rem / 4rem 10rem;
}
.audioplayer > button, .audioplayer > div, .audioplayer > label {
background-color: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
}
#audioplayerctrl {
position: fixed;
top: 0;
right: 50%;
padding: 0.3rem 0.5rem;
color: white;
transition: transform 0.5s;
}
#audioplayer_mute {
max-width: 5rem;
border: none;
}
#audioplayer_mute:focus, #audioplayer_mute:active {
outline: none;
}
#audioplayer_mute > svg {
width: 100%;
height: 100%;
pointer-events: none;
}
#audioplayer_volume_icon_playing.muted {
visibility: hidden;
display: none;
}
#audioplayerctrl > #audioplayer_volume {
width: 100%;
background-color: rgba(0,0,0,0.5);
}
/*
* sollte eigentlich in den aspect-ratio teil ..
*/
#audioplayerctrl.loading {
transform: translateY(-90%);
}
#audioplayerctrl.hidden {
transform: translateY(-100%);
}
/*
* Style Input Range
* https://www.cssportal.com/style-input-range/
*/
input[type=range] {
height: 28px;
-webkit-appearance: none;
margin: 10px 0;
width: 100%;
background-color: transparent;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 5px;
animate: 0.2s;
box-shadow: 1px 1px 1px #000000;
background: #FFFFFF;
border-radius: 5px;
border: 1px solid #000000;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 1px 1px 1px #000000;
border: 1px solid #000000;
height: 20px;
width: 10px;
border-radius: 5px;
background: #FFFFFF;
-webkit-appearance: none;
margin-top: -8.5px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #FFFFFF;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 5px;
animate: 0.2s;
box-shadow: 1px 1px 1px #000000;
background: #FFFFFF;
border-radius: 5px;
border: 1px solid #000000;
}
input[type=range]::-moz-range-thumb {
box-shadow: 1px 1px 1px #000000;
border: 1px solid #000000;
height: 20px;
width: 10px;
border-radius: 5px;
background: #FFFFFF;
}
input[type=range]::-ms-track {
width: 100%;
height: 5px;
animate: 0.2s;
background: transparent;
border-color: transparent;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #FFFFFF;
border: 1px solid #000000;
border-radius: 10px;
box-shadow: 1px 1px 1px #000000;
}
input[type=range]::-ms-fill-upper {
background: #FFFFFF;
border: 1px solid #000000;
border-radius: 10px;
box-shadow: 1px 1px 1px #000000;
}
input[type=range]::-ms-thumb {
margin-top: 1px;
box-shadow: 1px 1px 1px #000000;
border: 1px solid #000000;
height: 20px;
width: 10px;
border-radius: 5px;
background: #FFFFFF;
}
input[type=range]:focus::-ms-fill-lower {
background: #FFFFFF;
}
input[type=range]:focus::-ms-fill-upper {
background: #FFFFFF;
}
.game-overlay {
display: none;
position: absolute;
@ -992,4 +1134,4 @@ div.action p.action-body{
0% {bottom: 40px;}
50% {bottom: 30px;}
100% {bottom: 40px;}
}
}

View File

@ -23,7 +23,7 @@
"dependencies": {
"@types/simple-peer": "^9.6.0",
"@types/socket.io-client": "^1.4.32",
"axios": "^0.20.0",
"axios": "^0.21.1",
"generic-type-guard": "^3.2.0",
"google-protobuf": "^3.13.0",
"phaser": "^3.22.0",

View File

@ -59,6 +59,7 @@ export abstract class Character extends Container {
frame?: string | number
) {
super(scene, x, y/*, texture, frame*/);
this.PlayerValue = name;
this.sprites = new Map<string, Sprite>();
@ -73,10 +74,9 @@ export abstract class Character extends Container {
});
this.add(this.teleportation);*/
this.PlayerValue = name;
this.playerName = new BitmapText(scene, x, y - 25, 'main_font', name, 7);
this.playerName = new BitmapText(scene, 0, - 25, 'main_font', name, 7);
this.playerName.setOrigin(0.5).setCenterAlign().setDepth(99999);
scene.add.existing(this.playerName);
this.add(this.playerName);
scene.add.existing(this);
@ -88,8 +88,6 @@ export abstract class Character extends Container {
this.getBody().setOffset(0, 8);
this.setDepth(-1);
this.scene.events.on('postupdate', this.postupdate.bind(this));
this.playAnimation(direction, moving);
}
@ -181,35 +179,21 @@ export abstract class Character extends Container {
if (body.velocity.y < 0) { //moving up
this.lastDirection = PlayerAnimationNames.WalkUp;
this.playAnimation(PlayerAnimationNames.WalkUp, true);
//this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkUp}`, true);
} else if (body.velocity.y > 0) { //moving down
this.lastDirection = PlayerAnimationNames.WalkDown;
this.playAnimation(PlayerAnimationNames.WalkDown, true);
//this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkDown}`, true);
} else if (body.velocity.x > 0) { //moving right
this.lastDirection = PlayerAnimationNames.WalkRight;
this.playAnimation(PlayerAnimationNames.WalkRight, true);
//this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkRight}`, true);
} else if (body.velocity.x < 0) { //moving left
this.lastDirection = PlayerAnimationNames.WalkLeft;
this.playAnimation(PlayerAnimationNames.WalkLeft, true);
//this.anims.playReverse(`${this.PlayerTexture}-${PlayerAnimationNames.WalkLeft}`, true);
}
//todo:remove this, use a container tech to move the bubble instead
if (this.bubble) {
this.bubble.moveBubble(this.x, this.y);
}
//update depth user
this.setDepth(this.y);
}
postupdate(time: number, delta: number) {
//super.update(delta);
this.playerName.setPosition(this.x, this.y - 25);
}
stop(){
this.getBody().setVelocity(0, 0);
this.playAnimation(this.lastDirection, false);
@ -218,7 +202,6 @@ export abstract class Character extends Container {
say(text: string) {
if (this.bubble) return;
this.bubble = new SpeechBubble(this.scene, this, text)
//todo make the bubble destroy on player movement?
setTimeout(() => {
if (this.bubble !== null) {
this.bubble.destroy();
@ -227,16 +210,13 @@ export abstract class Character extends Container {
}, 3000)
}
destroy(fromScene?: boolean): void {
if (this.scene) {
this.scene.events.removeListener('postupdate', this.postupdate.bind(this));
}
destroy(): void {
for (const sprite of this.sprites.values()) {
if(this.scene) {
this.scene.sys.updateList.remove(sprite);
}
}
super.destroy(fromScene);
super.destroy();
this.playerName.destroy();
}
}

View File

@ -29,6 +29,7 @@ export class RemotePlayer extends Character {
this.playAnimation(position.direction, position.moving);
this.setX(position.x);
this.setY(position.y);
this.setDepth(position.y);
this.setDepth(position.y); //this is to make sure the perspective (player models closer the bottom of the screen will appear in front of models nearer the top of the screen).
}
}

View File

@ -1,16 +1,12 @@
import Scene = Phaser.Scene;
import {Character} from "./Character";
//todo: improve this WIP
export class SpeechBubble {
private bubble: Phaser.GameObjects.Graphics;
private content: Phaser.GameObjects.Text;
/**
*
* @param scene
* @param player
* @param text
*/
constructor(scene: Scene, player: Character, text: string = "") {
const bubbleHeight = 50;
@ -19,6 +15,7 @@ export class SpeechBubble {
const arrowHeight = bubbleHeight / 4;
this.bubble = scene.add.graphics({ x: player.x + 16, y: player.y - 80 });
player.add(this.bubble);
// Bubble shadow
this.bubble.fillStyle(0x222222, 0.5);
@ -52,31 +49,13 @@ export class SpeechBubble {
this.bubble.lineBetween(point2X, point2Y, point3X, point3Y);
this.bubble.lineBetween(point1X, point1Y, point3X, point3Y);
this.content = scene.add.text(0, 0, text, { fontFamily: 'Arial', fontSize: 20, color: '#000000', align: 'center', wordWrap: { width: bubbleWidth - (bubblePadding * 2) } });
this.content = scene.add.text(0, 0, text, { fontFamily: 'Arial', fontSize: '20', color: '#000000', align: 'center', wordWrap: { width: bubbleWidth - (bubblePadding * 2) } });
player.add(this.content);
const bounds = this.content.getBounds();
this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2));
}
/**
*
* @param x
* @param y
*/
moveBubble(x : number, y : number) {
if (this.bubble) {
this.bubble.setPosition((x + 16), (y - 80));
}
if (this.content) {
const bubbleHeight = 50;
const bubblePadding = 10;
const bubbleWidth = bubblePadding * 2 + this.content.text.length * 10;
const bounds = this.content.getBounds();
//this.content.setPosition(x, y);
this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2));
}
}
destroy(): void {
this.bubble.setVisible(false) //todo find a better way
this.bubble.destroy();

View File

@ -60,11 +60,13 @@ import {ResizableScene} from "../Login/ResizableScene";
import {Room} from "../../Connexion/Room";
import {jitsiFactory} from "../../WebRtc/JitsiFactory";
import {urlManager} from "../../Url/UrlManager";
import {audioManager} from "../../WebRtc/AudioManager";
import {PresentationModeIcon} from "../Components/PresentationModeIcon";
import {ChatModeIcon} from "../Components/ChatModeIcon";
import {OpenChatIcon, openChatIconName} from "../Components/OpenChatIcon";
import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCharacterScene";
import {TextureError} from "../../Exception/TextureError";
import {TextField} from "../Components/TextField";
export interface GameSceneInitInterface {
initPosition: PointInterface|null,
@ -109,7 +111,7 @@ export class GameScene extends ResizableScene implements CenterListener {
MapPlayers!: Phaser.Physics.Arcade.Group;
MapPlayersByKey : Map<number, RemotePlayer> = new Map<number, RemotePlayer>();
Map!: Phaser.Tilemaps.Tilemap;
Layers!: Array<Phaser.Tilemaps.StaticTilemapLayer>;
Layers!: Array<Phaser.Tilemaps.TilemapLayer>;
Objects!: Array<Phaser.Physics.Arcade.Sprite>;
mapFile!: ITiledMap;
groups: Map<number, Sprite>;
@ -179,6 +181,8 @@ export class GameScene extends ResizableScene implements CenterListener {
//hook preload scene
preload(): void {
this.initProgressBar();
this.load.image(openChatIconName, 'resources/objects/talk.png');
this.load.on(FILE_LOAD_ERROR, (file: {src: string}) => {
this.scene.start(FourOFourSceneName, {
@ -205,6 +209,20 @@ export class GameScene extends ResizableScene implements CenterListener {
this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
}
private initProgressBar(): void {
const loadingText = this.add.text(this.game.renderer.width / 2, 200, 'Loading');
const progress = this.add.graphics();
this.load.on('progress', (value: number) => {
progress.clear();
progress.fillStyle(0xffffff, 1);
progress.fillRect(0, 270, 800 * value, 60);
});
this.load.on('complete', () => {
loadingText.destroy();
progress.destroy();
});
}
// FIXME: we need to put a "unknown" instead of a "any" and validate the structure of the JSON we are receiving.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async onMapLoad(data: any): Promise<void> {
@ -341,11 +359,11 @@ export class GameScene extends ResizableScene implements CenterListener {
this.physics.world.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels);
//add layer on map
this.Layers = new Array<Phaser.Tilemaps.StaticTilemapLayer>();
this.Layers = new Array<Phaser.Tilemaps.TilemapLayer>();
let depth = -2;
for (const layer of this.mapFile.layers) {
if (layer.type === 'tilelayer') {
this.addLayer(this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
this.addLayer(this.Map.createLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
const exitSceneUrl = this.getExitSceneUrl(layer);
if (exitSceneUrl !== undefined) {
@ -378,40 +396,11 @@ export class GameScene extends ResizableScene implements CenterListener {
//notify game manager can to create currentUser in map
this.createCurrentPlayer();
//initialise camera
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
this.initCamera();
// Let's generate the circle for the group delimiter
let circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-white');
if (circleElement) {
this.textures.remove('circleSprite-white');
}
circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-red');
if (circleElement) {
this.textures.remove('circleSprite-red');
}
//create white circle canvas use to create sprite
this.circleTexture = this.textures.createCanvas('circleSprite-white', 96, 96);
const context = this.circleTexture.context;
context.beginPath();
context.arc(48, 48, 48, 0, 2 * Math.PI, false);
// context.lineWidth = 5;
context.strokeStyle = '#ffffff';
context.stroke();
this.circleTexture.refresh();
//create red circle canvas use to create sprite
this.circleRedTexture = this.textures.createCanvas('circleSprite-red', 96, 96);
const contextRed = this.circleRedTexture.context;
contextRed.beginPath();
contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false);
// context.lineWidth = 5;
contextRed.strokeStyle = '#ff0000';
contextRed.stroke();
this.circleRedTexture.refresh();
this.initCirclesCanvas();
// Let's pause the scene if the connection is not established yet
if (this.isReconnecting) {
@ -499,11 +488,13 @@ export class GameScene extends ResizableScene implements CenterListener {
});
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
audioManager.decreaseVolume();
this.shareGroupPosition(groupPositionMessage);
this.openChatIcon.setVisible(true);
})
this.connection.onGroupDeleted((groupId: number) => {
audioManager.restoreVolume();
try {
this.deleteGroup(groupId);
this.openChatIcon.setVisible(false);
@ -591,6 +582,54 @@ export class GameScene extends ResizableScene implements CenterListener {
});
}
//todo: into dedicated classes
private initCirclesCanvas(): void {
// Let's generate the circle for the group delimiter
let circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-white');
if (circleElement) {
this.textures.remove('circleSprite-white');
}
circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-red');
if (circleElement) {
this.textures.remove('circleSprite-red');
}
//create white circle canvas use to create sprite
this.circleTexture = this.textures.createCanvas('circleSprite-white', 96, 96);
const context = this.circleTexture.context;
context.beginPath();
context.arc(48, 48, 48, 0, 2 * Math.PI, false);
// context.lineWidth = 5;
context.strokeStyle = '#ffffff';
context.stroke();
this.circleTexture.refresh();
//create red circle canvas use to create sprite
this.circleRedTexture = this.textures.createCanvas('circleSprite-red', 96, 96);
const contextRed = this.circleRedTexture.context;
contextRed.beginPath();
contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false);
// context.lineWidth = 5;
contextRed.strokeStyle = '#ff0000';
contextRed.stroke();
this.circleRedTexture.refresh();
}
private playAudio(url: string|number|boolean|undefined, loop=false): void {
if (url === undefined) {
audioManager.unloadAudio();
} else {
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
const realAudioPath = mapDirUrl + '/' + url;
audioManager.loadAudio(realAudioPath);
if (loop) {
audioManager.loop();
}
}
}
private triggerOnMapLayerPropertyChange(){
this.gameMap.onPropertyChange('exitSceneUrl', (newValue, oldValue) => {
if (newValue) this.onMapExit(newValue as string);
@ -651,6 +690,14 @@ export class GameScene extends ResizableScene implements CenterListener {
this.connection.setSilent(true);
}
});
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => {
this.playAudio(newValue);
});
this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => {
this.playAudio(newValue, true);
});
}
private onMapExit(exitKey: string) {
@ -680,6 +727,14 @@ export class GameScene extends ResizableScene implements CenterListener {
}
}
private removeAllRemotePlayers(): void {
this.MapPlayersByKey.forEach((player: RemotePlayer) => {
player.destroy();
this.MapPlayers.remove(player);
});
this.MapPlayersByKey = new Map<number, RemotePlayer>();
}
private switchLayoutMode(): void {
//if discussion is activated, this layout cannot be activated
if(mediaManager.activatedDiscussion){
@ -799,13 +854,13 @@ export class GameScene extends ResizableScene implements CenterListener {
this.cameras.main.setZoom(ZOOM_LEVEL);
}
addLayer(Layer : Phaser.Tilemaps.StaticTilemapLayer){
addLayer(Layer : Phaser.Tilemaps.TilemapLayer){
this.Layers.push(Layer);
}
createCollisionWithPlayer() {
//add collision layer
this.Layers.forEach((Layer: Phaser.Tilemaps.StaticTilemapLayer) => {
this.Layers.forEach((Layer: Phaser.Tilemaps.TilemapLayer) => {
this.physics.add.collider(this.CurrentPlayer, Layer, (object1: GameObject, object2: GameObject) => {
//this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name)
});
@ -987,14 +1042,7 @@ export class GameScene extends ResizableScene implements CenterListener {
*/
private doInitUsersPosition(usersPosition: MessageUserPositionInterface[]): void {
const currentPlayerId = this.connection.getUserId();
// clean map
this.MapPlayersByKey.forEach((player: RemotePlayer) => {
player.destroy();
this.MapPlayers.remove(player);
});
this.MapPlayersByKey = new Map<number, RemotePlayer>();
this.removeAllRemotePlayers();
// load map
usersPosition.forEach((userPosition : MessageUserPositionInterface) => {
if(userPosition.userId === currentPlayerId){
@ -1187,9 +1235,7 @@ export class GameScene extends ResizableScene implements CenterListener {
// Let's put this in Game coordinates by applying the zoom level:
xCenter /= ZOOM_LEVEL * RESOLUTION;
yCenter /= ZOOM_LEVEL * RESOLUTION;
//console.log("updateCameraOffset", array, xCenter, yCenter, this.game.renderer.width, this.game.renderer.height);
this.cameras.main.startFollow(this.CurrentPlayer, true, 1, 1, xCenter - this.game.renderer.width / 2, yCenter - this.game.renderer.height / 2);
}

View File

@ -43,8 +43,7 @@ export class ActionableItem {
}
this.isSelectable = true;
this.sprite.setPipeline(OutlinePipeline.KEY);
this.sprite.pipeline.setFloat2('uTextureSize',
this.sprite.texture.getSourceImage().width, this.sprite.texture.getSourceImage().height);
this.sprite.pipeline.set2f('uTextureSize', this.sprite.texture.getSourceImage().width, this.sprite.texture.getSourceImage().height);
}
/**

View File

@ -1,5 +1,4 @@
export class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline
{
export class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline {
// the unique id of this pipeline
public static readonly KEY = 'Outline';
@ -11,7 +10,6 @@ export class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.TextureTint
{
super({
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;

View File

@ -0,0 +1,160 @@
import {HtmlUtils} from "./HtmlUtils";
import {isUndefined} from "generic-type-guard";
enum audioStates {
closed = 0,
loading = 1,
playing = 2
}
const audioPlayerDivId = "audioplayer";
const audioPlayerCtrlId = "audioplayerctrl";
const animationTime = 500;
class AudioManager {
private opened = audioStates.closed;
private audioPlayerDiv: HTMLDivElement;
private audioPlayerCtrl: HTMLDivElement;
private audioPlayerElem: HTMLAudioElement | undefined;
private volume = 1;
private muted = false;
private decreaseWhileTalking = true;
private volumeReduced = false;
constructor() {
this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerDivId);
this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerCtrlId);
const storedVolume = localStorage.getItem('volume')
if (storedVolume === null) {
this.setVolume(1);
} else {
this.volume = parseFloat(storedVolume);
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = storedVolume;
}
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume;
}
private close(): void {
this.audioPlayerCtrl.classList.remove('loading');
this.audioPlayerCtrl.classList.add('hidden');
this.opened = audioStates.closed;
}
private load(): void {
this.audioPlayerCtrl.classList.remove('hidden');
this.audioPlayerCtrl.classList.add('loading');
this.opened = audioStates.loading;
}
private open(): void {
this.audioPlayerCtrl.classList.remove('hidden', 'loading');
this.opened = audioStates.playing;
}
private changeVolume(talking = false): void {
if (!isUndefined(this.audioPlayerElem)) {
this.audioPlayerElem.volume = this.naturalVolume(talking && this.decreaseWhileTalking);
this.audioPlayerElem.muted = this.muted;
}
}
private naturalVolume(makeSofter: boolean = false): number {
const volume = this.volume
const retVol = makeSofter && !this.volumeReduced ? Math.pow(volume * 0.5, 3) : volume
this.volumeReduced = makeSofter
return retVol;
}
private setVolume(volume: number): void {
this.volume = volume;
localStorage.setItem('volume', '' + volume);
}
public loadAudio(url: string): void {
this.load();
/* Solution 1, remove whole audio player */
this.audioPlayerDiv.innerHTML = ''; // necessary, if switching from one audio context to another! (else both streams would play simultaneously)
this.audioPlayerElem = document.createElement('audio');
this.audioPlayerElem.id = 'audioplayerelem';
this.audioPlayerElem.controls = false;
this.audioPlayerElem.preload = 'none';
const srcElem = document.createElement('source');
srcElem.type = "audio/mp3";
srcElem.src = url;
this.audioPlayerElem.append(srcElem);
this.audioPlayerDiv.append(this.audioPlayerElem);
this.changeVolume();
this.audioPlayerElem.play();
const muteElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_mute');
muteElem.onclick = (ev: Event)=> {
this.muted = !this.muted;
this.changeVolume();
if (this.muted) {
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume_icon_playing').classList.add('muted');
} else {
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume_icon_playing').classList.remove('muted');
}
}
const volumeElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume');
volumeElem.oninput = (ev: Event)=> {
this.setVolume(parseFloat((<HTMLInputElement>ev.currentTarget).value));
this.changeVolume();
(<HTMLInputElement>ev.currentTarget).blur();
}
const decreaseElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_decrease_while_talking');
decreaseElem.oninput = (ev: Event)=> {
this.decreaseWhileTalking = (<HTMLInputElement>ev.currentTarget).checked;
this.changeVolume();
}
this.open();
}
public loop(): void {
if (this.audioPlayerElem !== undefined) {
this.audioPlayerElem.loop = true;
}
}
public unloadAudio(): void {
try {
const audioElem = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('audioplayerelem');
this.volume = audioElem.volume;
this.muted = audioElem.muted;
audioElem.pause();
audioElem.loop = false;
audioElem.src = "";
audioElem.innerHTML = "";
audioElem.load();
} catch (e) {
console.log('No audio element loaded to unload');
}
this.close();
}
public decreaseVolume(): void {
this.changeVolume(true);
}
public restoreVolume(): void {
this.changeVolume(false);
}
}
export const audioManager = new AudioManager();

View File

@ -75,7 +75,7 @@ const config: GameConfig = {
postBoot: game => {
// FIXME: we should fore WebGL in the config.
const renderer = game.renderer as WebGLRenderer;
renderer.addPipeline(OutlinePipeline.KEY, new OutlinePipeline(game));
renderer.pipelines.add(OutlinePipeline.KEY, new OutlinePipeline(game));
}
}
};

View File

@ -563,10 +563,10 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
@ -1771,7 +1771,7 @@ eventemitter3@^2.0.3:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=
eventemitter3@^4.0.0, eventemitter3@^4.0.4:
eventemitter3@^4.0.0, eventemitter3@^4.0.7:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
@ -1829,7 +1829,7 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
exports-loader@^1.1.0:
exports-loader@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-1.1.1.tgz#88c9a6877ee6a5519d7c41a016bdd99148421e69"
integrity sha512-CmyhIR2sJ3KOfVsHjsR0Yvo+0lhRhRMAevCbB8dhTVLHsZPs0lCQTvRmR9YNvBXDBxUuhmCE2f54KqEjZUaFrg==
@ -2528,7 +2528,7 @@ import-local@^2.0.0:
pkg-dir "^3.0.0"
resolve-cwd "^2.0.0"
imports-loader@^1.1.0:
imports-loader@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-1.2.0.tgz#b06823d0bb42e6f5ff89bc893829000eda46693f"
integrity sha512-zPvangKEgrrPeqeUqH0Uhc59YqK07JqZBi9a9cQ3v/EKUIqrbJHY4CvUrDus2lgQa5AmPyXuGrWP8JJTqzE5RQ==
@ -3664,13 +3664,13 @@ pbkdf2@^3.0.3:
sha.js "^2.4.8"
phaser@^3.22.0:
version "3.24.1"
resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.24.1.tgz#376e0c965d2a35af37c06ee78627dafbde5be017"
integrity sha512-WbrRMkbpEzarkfrq83akeauc6b8xNxsOTpDygyW7wrU2G2ne6kOYu3hji4UAaGnZaOLrVuj8ycYPjX9P1LxcDw==
version "3.51.0"
resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.51.0.tgz#b0c7ee2b21e795830d74f476dd30816a42b023bd"
integrity sha512-Z7XNToZWO60Zx/YetaoeGSeELy5ND45TPPfYB9HtQU2692ACXc/nioQaWp20NzTMgeBsgl6vYf3CI82y/DzSyg==
dependencies:
eventemitter3 "^4.0.4"
exports-loader "^1.1.0"
imports-loader "^1.1.0"
eventemitter3 "^4.0.7"
exports-loader "^1.1.1"
imports-loader "^1.2.0"
path "^0.12.7"
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:

View File

@ -37,7 +37,7 @@
},
"homepage": "https://github.com/thecodingmachine/workadventure#readme",
"dependencies": {
"axios": "^0.20.0",
"axios": "^0.21.1",
"body-parser": "^1.19.0",
"busboy": "^0.3.1",
"circular-json": "^0.5.9",

View File

@ -1,3 +1,4 @@
// lib/server.ts
import App from "./src/App";
App.listen(8080, () => console.log(`WorkAdventure starting on port 8080!`))
import { PUSHER_HTTP_PORT } from "./src/Enum/EnvironmentVariable";
App.listen(PUSHER_HTTP_PORT, () => console.log(`WorkAdventure starting on port ${PUSHER_HTTP_PORT}!`))

View File

@ -11,6 +11,7 @@ const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
const JITSI_URL : string|undefined = (process.env.JITSI_URL === '') ? undefined : process.env.JITSI_URL;
const JITSI_ISS = process.env.JITSI_ISS || '';
const SECRET_JITSI_KEY = process.env.SECRET_JITSI_KEY || '';
const PUSHER_HTTP_PORT = parseInt(process.env.PUSHER_HTTP_PORT || '8080') || 8080
export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as string) || 30; // maximum time (in second) without activity before a socket is closed
export {
@ -26,5 +27,6 @@ export {
CPU_OVERHEAT_THRESHOLD,
JITSI_URL,
JITSI_ISS,
SECRET_JITSI_KEY
SECRET_JITSI_KEY,
PUSHER_HTTP_PORT
}

View File

@ -335,10 +335,10 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"