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

This commit is contained in:
GRL 2021-07-30 09:38:28 +02:00
commit bd96a32d5b
32 changed files with 419 additions and 189 deletions

View file

@ -34,6 +34,7 @@
<title>WorkAdventure</title>
</head>
<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">

View file

@ -0,0 +1,62 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- TRACK CODE -->
<!-- END TRACK CODE -->
<link rel="apple-touch-icon" sizes="57x57" href="/static/images/favicons/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/static/images/favicons/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/static/images/favicons/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/static/images/favicons/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/static/images/favicons/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/static/images/favicons/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/static/images/favicons/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/static/images/favicons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/static/images/favicons/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/static/images/favicons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/images/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/static/images/favicons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicons/favicon-16x16.png">
<meta name="msapplication-TileColor" content="#000000">
<meta name="msapplication-TileImage" content="/static/images/favicons/ms-icon-144x144.png">
<meta name="theme-color" content="#000000">
<title>WorkAdventure PWA</title>
<style>
body{
font-family: Whitney, Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
body img{
position: absolute;
top: calc( 50% - 25px);
height: 59px;
width: 307px;
left: calc( 50% - 150px);
}
body p{
position: absolute;
text-align: center;
top: calc( 50% + 50px);
left: calc( 50% - 150px);
height: 59px;
width: 307px;
font-size: 20px;
}
</style>
</head>
<body>
<img src="/static/images/logo.png" alt="WorkAdventure logo"/>
<p>Charging your workspace ...</p>
<script>
setTimeout(() => {
window.location = localStorage.getItem('lastRoomUrl');
}, 4000);
</script>
</body>
</html>

View file

@ -48,6 +48,14 @@ self.addEventListener('fetch', function(event) {
);
});
self.addEventListener('activate', function(event) {
//TODO activate service worker
self.addEventListener('wait', function(event) {
//TODO wait
});
self.addEventListener('update', function(event) {
//TODO update
});
self.addEventListener('beforeinstallprompt', (e) => {
//TODO change prompt
});

View file

@ -128,11 +128,12 @@
"type": "image\/png"
}
],
"start_url": "/",
"start_url": "/resources/service-worker.html",
"background_color": "#000000",
"display_override": ["window-control-overlay", "minimal-ui"],
"display": "standalone",
"scope": "/",
"orientation": "portrait-primary",
"scope": "/resources/",
"lang": "en",
"theme_color": "#000000",
"shortcuts": [

View file

@ -3,9 +3,12 @@
import { chatMessagesStore, chatVisibilityStore } from "../../Stores/ChatStore";
import ChatMessageForm from './ChatMessageForm.svelte';
import ChatElement from './ChatElement.svelte';
import { afterUpdate, beforeUpdate } from "svelte";
import {afterUpdate, beforeUpdate} from "svelte";
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
let listDom: HTMLElement;
let chatWindowElement: HTMLElement;
let handleFormBlur: { blur():void };
let autoscroll: boolean;
beforeUpdate(() => {
@ -16,6 +19,12 @@
if (autoscroll) listDom.scrollTo(0, listDom.scrollHeight);
});
function onClick(event: MouseEvent) {
if (HtmlUtils.isClickedOutside(event, chatWindowElement)) {
handleFormBlur.blur();
}
}
function closeChat() {
chatVisibilityStore.set(false);
}
@ -26,10 +35,10 @@
}
</script>
<svelte:window on:keydown={onKeyDown}/>
<svelte:window on:keydown={onKeyDown} on:click={onClick}/>
<aside class="chatWindow" transition:fly="{{ x: -1000, duration: 500 }}">
<aside class="chatWindow" transition:fly="{{ x: -1000, duration: 500 }}" bind:this={chatWindowElement}>
<p class="close-icon" on:click={closeChat}>&times</p>
<section class="messagesList" bind:this={listDom}>
<ul>
@ -40,7 +49,7 @@
</ul>
</section>
<section class="messageForm">
<ChatMessageForm></ChatMessageForm>
<ChatMessageForm bind:handleForm={handleFormBlur}></ChatMessageForm>
</section>
</aside>

View file

@ -7,13 +7,14 @@
export let message: ChatMessage;
export let line: number;
const chatStyleLink = "color: white; text-decoration: underline;";
$: author = message.author as PlayerInterface;
$: targets = message.targets || [];
$: texts = message.text || [];
function urlifyText(text: string): string {
return HtmlUtils.urlify(text)
return HtmlUtils.urlify(text, chatStyleLink);
}
function renderDate(date: Date) {
return date.toLocaleTimeString(navigator.language, {

View file

@ -1,6 +1,12 @@
<script lang="ts">
import {chatMessagesStore, chatInputFocusStore} from "../../Stores/ChatStore";
export const handleForm = {
blur() {
inputElement.blur();
}
}
let inputElement: HTMLElement;
let newMessageText = '';
function onFocus() {
@ -18,7 +24,7 @@
</script>
<form on:submit|preventDefault={saveMessage}>
<input type="text" bind:value={newMessageText} placeholder="Enter your message..." on:focus={onFocus} on:blur={onBlur} >
<input type="text" bind:value={newMessageText} placeholder="Enter your message..." on:focus={onFocus} on:blur={onBlur} bind:this={inputElement}>
<button type="submit">
<img src="/static/images/send.png" alt="Send" width="20">
</button>

View file

@ -6,6 +6,7 @@ import { GameConnexionTypes, urlManager } from "../Url/UrlManager";
import { localUserStore } from "./LocalUserStore";
import { CharacterTexture, LocalUser } from "./LocalUser";
import { Room } from "./Room";
import { _ServiceWorker } from "../Network/ServiceWorker";
class ConnectionManager {
private localUser!: LocalUser;
@ -14,6 +15,8 @@ class ConnectionManager {
private reconnectingTimeout: NodeJS.Timeout | null = null;
private _unloading: boolean = false;
private serviceWorker?: _ServiceWorker;
get unloading() {
return this._unloading;
}
@ -30,6 +33,8 @@ class ConnectionManager {
public async initGameConnexion(): Promise<Room> {
const connexionType = urlManager.getGameConnexionType();
this.connexionType = connexionType;
let room: Room | null = null;
if (connexionType === GameConnexionTypes.register) {
const organizationMemberToken = urlManager.getOrganizationToken();
const data = await Axios.post(`${PUSHER_URL}/register`, { organizationMemberToken }).then(
@ -40,7 +45,7 @@ class ConnectionManager {
const roomUrl = data.roomUrl;
const room = await Room.createRoom(
room = await Room.createRoom(
new URL(
window.location.protocol +
"//" +
@ -51,7 +56,6 @@ class ConnectionManager {
)
);
urlManager.pushRoomIdToUrl(room);
return Promise.resolve(room);
} else if (
connexionType === GameConnexionTypes.organization ||
connexionType === GameConnexionTypes.anonymous ||
@ -90,7 +94,7 @@ class ConnectionManager {
}
//get detail map for anonymous login and set texture in local storage
const room = await Room.createRoom(new URL(roomPath));
room = await Room.createRoom(new URL(roomPath));
if (room.textures != undefined && room.textures.length > 0) {
//check if texture was changed
if (localUser.textures.length === 0) {
@ -107,10 +111,13 @@ class ConnectionManager {
this.localUser = localUser;
localUserStore.saveUser(localUser);
}
return Promise.resolve(room);
}
if (room == undefined) {
return Promise.reject(new Error("Invalid URL"));
}
return Promise.reject(new Error("Invalid URL"));
this.serviceWorker = new _ServiceWorker();
return Promise.resolve(room);
}
private async verifyToken(token: string): Promise<void> {
@ -148,6 +155,7 @@ class ConnectionManager {
viewport,
companion
);
connection.onConnectError((error: object) => {
console.log("An error occurred while connecting to socket server. Retrying");
reject(error);
@ -166,6 +174,9 @@ class ConnectionManager {
});
connection.onConnect((connect: OnConnectInterface) => {
//save last room url connected
localUserStore.setLastRoomUrl(roomUrl);
resolve(connect);
});
}).catch((err) => {

View file

@ -1,60 +1,61 @@
import {areCharacterLayersValid, isUserNameValid, LocalUser} from "./LocalUser";
import { areCharacterLayersValid, isUserNameValid, LocalUser } from "./LocalUser";
const playerNameKey = 'playerName';
const selectedPlayerKey = 'selectedPlayer';
const customCursorPositionKey = 'customCursorPosition';
const characterLayersKey = 'characterLayers';
const companionKey = 'companion';
const gameQualityKey = 'gameQuality';
const videoQualityKey = 'videoQuality';
const audioPlayerVolumeKey = 'audioVolume';
const audioPlayerMuteKey = 'audioMute';
const helpCameraSettingsShown = 'helpCameraSettingsShown';
const fullscreenKey = 'fullscreen';
const playerNameKey = "playerName";
const selectedPlayerKey = "selectedPlayer";
const customCursorPositionKey = "customCursorPosition";
const characterLayersKey = "characterLayers";
const companionKey = "companion";
const gameQualityKey = "gameQuality";
const videoQualityKey = "videoQuality";
const audioPlayerVolumeKey = "audioVolume";
const audioPlayerMuteKey = "audioMute";
const helpCameraSettingsShown = "helpCameraSettingsShown";
const fullscreenKey = "fullscreen";
const lastRoomUrl = "lastRoomUrl";
class LocalUserStore {
saveUser(localUser: LocalUser) {
localStorage.setItem('localUser', JSON.stringify(localUser));
localStorage.setItem("localUser", JSON.stringify(localUser));
}
getLocalUser(): LocalUser|null {
const data = localStorage.getItem('localUser');
getLocalUser(): LocalUser | null {
const data = localStorage.getItem("localUser");
return data ? JSON.parse(data) : null;
}
setName(name:string): void {
setName(name: string): void {
localStorage.setItem(playerNameKey, name);
}
getName(): string|null {
const value = localStorage.getItem(playerNameKey) || '';
getName(): string | null {
const value = localStorage.getItem(playerNameKey) || "";
return isUserNameValid(value) ? value : null;
}
setPlayerCharacterIndex(playerCharacterIndex: number): void {
localStorage.setItem(selectedPlayerKey, ''+playerCharacterIndex);
localStorage.setItem(selectedPlayerKey, "" + playerCharacterIndex);
}
getPlayerCharacterIndex(): number {
return parseInt(localStorage.getItem(selectedPlayerKey) || '');
return parseInt(localStorage.getItem(selectedPlayerKey) || "");
}
setCustomCursorPosition(activeRow:number, selectedLayers: number[]): void {
localStorage.setItem(customCursorPositionKey, JSON.stringify({activeRow, selectedLayers}));
setCustomCursorPosition(activeRow: number, selectedLayers: number[]): void {
localStorage.setItem(customCursorPositionKey, JSON.stringify({ activeRow, selectedLayers }));
}
getCustomCursorPosition(): {activeRow:number, selectedLayers:number[]}|null {
getCustomCursorPosition(): { activeRow: number; selectedLayers: number[] } | null {
return JSON.parse(localStorage.getItem(customCursorPositionKey) || "null");
}
setCharacterLayers(layers: string[]): void {
localStorage.setItem(characterLayersKey, JSON.stringify(layers));
}
getCharacterLayers(): string[]|null {
getCharacterLayers(): string[] | null {
const value = JSON.parse(localStorage.getItem(characterLayersKey) || "null");
return areCharacterLayersValid(value) ? value : null;
}
setCompanion(companion: string|null): void {
setCompanion(companion: string | null): void {
return localStorage.setItem(companionKey, JSON.stringify(companion));
}
getCompanion(): string|null {
getCompanion(): string | null {
const companion = JSON.parse(localStorage.getItem(companionKey) || "null");
if (typeof companion !== "string" || companion === "") {
@ -68,45 +69,52 @@ class LocalUserStore {
}
setGameQualityValue(value: number): void {
localStorage.setItem(gameQualityKey, '' + value);
localStorage.setItem(gameQualityKey, "" + value);
}
getGameQualityValue(): number {
return parseInt(localStorage.getItem(gameQualityKey) || '60');
return parseInt(localStorage.getItem(gameQualityKey) || "60");
}
setVideoQualityValue(value: number): void {
localStorage.setItem(videoQualityKey, '' + value);
localStorage.setItem(videoQualityKey, "" + value);
}
getVideoQualityValue(): number {
return parseInt(localStorage.getItem(videoQualityKey) || '20');
return parseInt(localStorage.getItem(videoQualityKey) || "20");
}
setAudioPlayerVolume(value: number): void {
localStorage.setItem(audioPlayerVolumeKey, '' + value);
localStorage.setItem(audioPlayerVolumeKey, "" + value);
}
getAudioPlayerVolume(): number {
return parseFloat(localStorage.getItem(audioPlayerVolumeKey) || '1');
return parseFloat(localStorage.getItem(audioPlayerVolumeKey) || "1");
}
setAudioPlayerMuted(value: boolean): void {
localStorage.setItem(audioPlayerMuteKey, value.toString());
}
getAudioPlayerMuted(): boolean {
return localStorage.getItem(audioPlayerMuteKey) === 'true';
return localStorage.getItem(audioPlayerMuteKey) === "true";
}
setHelpCameraSettingsShown(): void {
localStorage.setItem(helpCameraSettingsShown, '1');
localStorage.setItem(helpCameraSettingsShown, "1");
}
getHelpCameraSettingsShown(): boolean {
return localStorage.getItem(helpCameraSettingsShown) === '1';
return localStorage.getItem(helpCameraSettingsShown) === "1";
}
setFullscreen(value: boolean): void {
localStorage.setItem(fullscreenKey, value.toString());
}
getFullscreen(): boolean {
return localStorage.getItem(fullscreenKey) === 'true';
return localStorage.getItem(fullscreenKey) === "true";
}
setLastRoomUrl(roomUrl: string): void {
localStorage.setItem(lastRoomUrl, roomUrl.toString());
}
getLastRoomUrl(): string {
return localStorage.getItem(lastRoomUrl) ?? "";
}
}

View file

@ -0,0 +1,20 @@
export class _ServiceWorker {
constructor() {
if ("serviceWorker" in navigator) {
this.init();
}
}
init() {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/resources/service-worker.js")
.then((serviceWorker) => {
console.info("Service Worker registered: ", serviceWorker);
})
.catch((error) => {
console.error("Error registering the Service Worker: ", error);
});
});
}
}

View file

@ -1,35 +1,43 @@
import type {ITiledMapObject} from "../Map/ITiledMap";
import type {GameScene} from "../Game/GameScene";
import type { ITiledMapObject } from "../Map/ITiledMap";
import type { GameScene } from "../Game/GameScene";
import { type } from "os";
export class TextUtils {
public static createTextFromITiledMapObject(scene: GameScene, object: ITiledMapObject): void {
if (object.text === undefined) {
throw new Error('This object has not textual representation.');
throw new Error("This object has not textual representation.");
}
const options: {
fontStyle?: string,
fontSize?: string,
fontFamily?: string,
color?: string,
align?: string,
fontStyle?: string;
fontSize?: string;
fontFamily?: string;
color?: string;
align?: string;
wordWrap?: {
width: number,
useAdvancedWrap?: boolean
}
width: number;
useAdvancedWrap?: boolean;
};
} = {};
if (object.text.italic) {
options.fontStyle = 'italic';
options.fontStyle = "italic";
}
// Note: there is no support for "strikeout" and "underline"
let fontSize: number = 16;
if (object.text.pixelsize) {
fontSize = object.text.pixelsize;
}
options.fontSize = fontSize + 'px';
options.fontSize = fontSize + "px";
if (object.text.fontfamily) {
options.fontFamily = '"'+object.text.fontfamily+'"';
options.fontFamily = '"' + object.text.fontfamily + '"';
}
let color = '#000000';
if (object.properties !== undefined) {
for (const property of object.properties) {
if (property.name === "font-family" && typeof property.value === "string") {
options.fontFamily = property.value;
}
}
}
let color = "#000000";
if (object.text.color !== undefined) {
color = object.text.color;
}
@ -38,7 +46,7 @@ export class TextUtils {
options.wordWrap = {
width: object.width,
//useAdvancedWrap: true
}
};
}
if (object.text.halign !== undefined) {
options.align = object.text.halign;

View file

@ -107,7 +107,7 @@ export const createLoadingPromise = (
loadPlugin.spritesheet(playerResourceDescriptor.name, playerResourceDescriptor.img, frameConfig);
const errorCallback = (file: { src: string }) => {
if (file.src !== playerResourceDescriptor.img) return;
console.error("failed loading player ressource: ", playerResourceDescriptor);
console.error("failed loading player resource: ", playerResourceDescriptor);
rej(playerResourceDescriptor);
loadPlugin.off("filecomplete-spritesheet-" + playerResourceDescriptor.name, successCallback);
loadPlugin.off("loaderror", errorCallback);

View file

@ -192,7 +192,7 @@ export class GameScene extends DirtyScene {
private popUpElements: Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>();
private originalMapUrl: string | undefined;
private pinchManager: PinchManager | undefined;
private mapTransitioning: boolean = false; //used to prevent transitions happenning at the same time.
private mapTransitioning: boolean = false; //used to prevent transitions happening at the same time.
private emoteManager!: EmoteManager;
private preloading: boolean = true;
private startPositionCalculator!: StartPositionCalculator;
@ -434,7 +434,7 @@ export class GameScene extends DirtyScene {
this.characterLayers = gameManager.getCharacterLayers();
this.companion = gameManager.getCompanion();
//initalise map
//initialise map
this.Map = this.add.tilemap(this.MapUrlFile);
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/"));
this.mapFile.tilesets.forEach((tileset: ITiledTileSet) => {

View file

@ -45,7 +45,7 @@ export class StartPositionCalculator {
/**
*
* @param selectedLayer this is always the layer that is selected with the hash in the url
* @param selectedOrDefaultLayer this can also be the {defaultStartLayerName} if the {selectedLayer} didnt yield any start points
* @param selectedOrDefaultLayer this can also be the {defaultStartLayerName} if the {selectedLayer} did not yield any start points
*/
public initPositionFromLayerName(selectedOrDefaultLayer: string | null, selectedLayer: string | null) {
if (!selectedOrDefaultLayer) {
@ -73,7 +73,7 @@ export class StartPositionCalculator {
/**
*
* @param selectedLayer this is always the layer that is selected with the hash in the url
* @param selectedOrDefaultLayer this can also be the default layer if the {selectedLayer} didnt yield any start points
* @param selectedOrDefaultLayer this can also be the default layer if the {selectedLayer} did not yield any start points
*/
private startUser(selectedOrDefaultLayer: ITiledMapTileLayer, selectedLayer: string | null): PositionInterface {
const tiles = selectedOrDefaultLayer.data;

View file

@ -244,6 +244,7 @@ export class CustomizeScene extends AbstractCharacterScene {
update(time: number, delta: number): void {
if (this.lazyloadingAttempt) {
this.moveLayers();
this.doMoveCursorHorizontally(this.moveHorizontally);
this.lazyloadingAttempt = false;
}

View file

@ -1,12 +1,12 @@
import type { Direction } from "../../types";
import type {GameScene} from "../Game/GameScene";
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {MobileJoystick} from "../Components/MobileJoystick";
import {enableUserInputsStore} from "../../Stores/UserInputStore";
import type { GameScene } from "../Game/GameScene";
import { touchScreenManager } from "../../Touch/TouchScreenManager";
import { MobileJoystick } from "../Components/MobileJoystick";
import { enableUserInputsStore } from "../../Stores/UserInputStore";
interface UserInputManagerDatum {
keyInstance: Phaser.Input.Keyboard.Key;
event: UserInputEvent
event: UserInputEvent;
}
export enum UserInputEvent {
@ -20,10 +20,9 @@ export enum UserInputEvent {
JoystickMove,
}
//we cannot use a map structure so we have to create a replacment
//we cannot use a map structure so we have to create a replacement
export class ActiveEventList {
private eventMap : Map<UserInputEvent, boolean> = new Map<UserInputEvent, boolean>();
private eventMap: Map<UserInputEvent, boolean> = new Map<UserInputEvent, boolean>();
get(event: UserInputEvent): boolean {
return this.eventMap.get(event) || false;
@ -43,7 +42,7 @@ export class ActiveEventList {
export class UserInputManager {
private KeysCode!: UserInputManagerDatum[];
private Scene: GameScene;
private isInputDisabled : boolean;
private isInputDisabled: boolean;
private joystick!: MobileJoystick;
private joystickEvents = new ActiveEventList();
@ -61,8 +60,8 @@ export class UserInputManager {
}
enableUserInputsStore.subscribe((enable) => {
enable ? this.restoreControls() : this.disableControls()
})
enable ? this.restoreControls() : this.disableControls();
});
}
initVirtualJoystick() {
@ -91,39 +90,81 @@ export class UserInputManager {
});
}
initKeyBoardEvent(){
initKeyBoardEvent() {
this.KeysCode = [
{event: UserInputEvent.MoveUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z, false) },
{event: UserInputEvent.MoveUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W, false) },
{event: UserInputEvent.MoveLeft, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q, false) },
{event: UserInputEvent.MoveLeft, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A, false) },
{event: UserInputEvent.MoveDown, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S, false) },
{event: UserInputEvent.MoveRight, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D, false) },
{
event: UserInputEvent.MoveUp,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z, false),
},
{
event: UserInputEvent.MoveUp,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W, false),
},
{
event: UserInputEvent.MoveLeft,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q, false),
},
{
event: UserInputEvent.MoveLeft,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A, false),
},
{
event: UserInputEvent.MoveDown,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S, false),
},
{
event: UserInputEvent.MoveRight,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D, false),
},
{event: UserInputEvent.MoveUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP, false) },
{event: UserInputEvent.MoveLeft, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT, false) },
{event: UserInputEvent.MoveDown, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN, false) },
{event: UserInputEvent.MoveRight, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT, false) },
{
event: UserInputEvent.MoveUp,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP, false),
},
{
event: UserInputEvent.MoveLeft,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT, false),
},
{
event: UserInputEvent.MoveDown,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN, false),
},
{
event: UserInputEvent.MoveRight,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT, false),
},
{event: UserInputEvent.SpeedUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT, false) },
{
event: UserInputEvent.SpeedUp,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT, false),
},
{event: UserInputEvent.Interact, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E, false) },
{event: UserInputEvent.Interact, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE, false) },
{event: UserInputEvent.Shout, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F, false) },
{
event: UserInputEvent.Interact,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E, false),
},
{
event: UserInputEvent.Interact,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE, false),
},
{
event: UserInputEvent.Shout,
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F, false),
},
];
}
clearAllListeners(){
clearAllListeners() {
this.Scene.input.keyboard.removeAllListeners();
}
//todo: should we also disable the joystick?
disableControls(){
disableControls() {
this.Scene.input.keyboard.removeAllKeys();
this.isInputDisabled = true;
}
restoreControls(){
restoreControls() {
this.initKeyBoardEvent();
this.isInputDisabled = false;
}
@ -135,27 +176,27 @@ export class UserInputManager {
this.joystickEvents.forEach((value, key) => {
if (value) {
switch (key) {
case UserInputEvent.MoveUp:
case UserInputEvent.MoveDown:
this.joystickForceAccuY += this.joystick.forceY;
if (Math.abs(this.joystickForceAccuY) > this.joystickForceThreshold) {
eventsMap.set(key, value);
this.joystickForceAccuY = 0;
}
break;
case UserInputEvent.MoveLeft:
case UserInputEvent.MoveRight:
this.joystickForceAccuX += this.joystick.forceX;
if (Math.abs(this.joystickForceAccuX) > this.joystickForceThreshold) {
eventsMap.set(key, value);
this.joystickForceAccuX = 0;
}
break;
case UserInputEvent.MoveUp:
case UserInputEvent.MoveDown:
this.joystickForceAccuY += this.joystick.forceY;
if (Math.abs(this.joystickForceAccuY) > this.joystickForceThreshold) {
eventsMap.set(key, value);
this.joystickForceAccuY = 0;
}
break;
case UserInputEvent.MoveLeft:
case UserInputEvent.MoveRight:
this.joystickForceAccuX += this.joystick.forceX;
if (Math.abs(this.joystickForceAccuX) > this.joystickForceThreshold) {
eventsMap.set(key, value);
this.joystickForceAccuX = 0;
}
break;
}
}
});
eventsMap.set(UserInputEvent.JoystickMove, this.joystickEvents.any());
this.KeysCode.forEach(d => {
this.KeysCode.forEach((d) => {
if (d.keyInstance.isDown) {
eventsMap.set(d.event, true);
}
@ -163,18 +204,18 @@ export class UserInputManager {
return eventsMap;
}
spaceEvent(callback : Function){
this.Scene.input.keyboard.on('keyup-SPACE', (event: Event) => {
spaceEvent(callback: Function) {
this.Scene.input.keyboard.on("keyup-SPACE", (event: Event) => {
callback();
return event;
});
}
addSpaceEventListner(callback : Function){
this.Scene.input.keyboard.addListener('keyup-SPACE', callback);
addSpaceEventListner(callback: Function) {
this.Scene.input.keyboard.addListener("keyup-SPACE", callback);
}
removeSpaceEventListner(callback : Function){
this.Scene.input.keyboard.removeListener('keyup-SPACE', callback);
removeSpaceEventListner(callback: Function) {
this.Scene.input.keyboard.removeListener("keyup-SPACE", callback);
}
destroy(): void {
@ -182,8 +223,11 @@ export class UserInputManager {
}
private initMouseWheel() {
this.Scene.input.on('wheel', (pointer: unknown, gameObjects: unknown, deltaX: number, deltaY: number, deltaZ: number) => {
this.Scene.zoomByFactor(1 - deltaY / 53 * 0.1);
});
this.Scene.input.on(
"wheel",
(pointer: unknown, gameObjects: unknown, deltaX: number, deltaY: number, deltaZ: number) => {
this.Scene.zoomByFactor(1 - (deltaY / 53) * 0.1);
}
);
}
}

View file

@ -274,12 +274,12 @@ export const mediaStreamConstraintsStore = derived(
currentAudioConstraint = false;
}
// Disable webcam for privacy reasons (the game is not visible and we were talking to noone)
// Disable webcam for privacy reasons (the game is not visible and we were talking to no one)
if ($privacyShutdownStore === true) {
currentVideoConstraint = false;
}
// Disable webcam for energy reasons (the user is not moving and we are talking to noone)
// Disable webcam for energy reasons (the user is not moving and we are talking to no one)
if ($cameraEnergySavingStore === true) {
currentVideoConstraint = false;
currentAudioConstraint = false;

View file

@ -31,7 +31,7 @@ export class HtmlUtils {
return p.innerHTML;
}
public static urlify(text: string): string {
public static urlify(text: string, style: string = ""): string {
const urlRegex = /(https?:\/\/[^\s]+)/g;
text = HtmlUtils.escapeHtml(text);
return text.replace(urlRegex, (url: string) => {
@ -40,10 +40,19 @@ export class HtmlUtils {
link.target = "_blank";
const text = document.createTextNode(url);
link.appendChild(text);
link.setAttribute("style", style);
return link.outerHTML;
});
}
public static isClickedInside(event: MouseEvent, target: HTMLElement): boolean {
return !!event.composedPath().find((et) => et === target);
}
public static isClickedOutside(event: MouseEvent, target: HTMLElement): boolean {
return !this.isClickedInside(event, target);
}
private static isHtmlElement<T extends HTMLElement>(elem: HTMLElement | null): elem is T {
return elem !== null;
}

View file

@ -295,7 +295,7 @@ export class SimplePeer {
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
peer.destroy();
//Comment this peer connexion because if we delete and try to reshare screen, the RTCPeerConnection send renegociate event. This array will be remove when user left circle discussion
//Comment this peer connection because if we delete and try to reshare screen, the RTCPeerConnection send renegotiate event. This array will be remove when user left circle discussion
/*if(!this.PeerScreenSharingConnectionArray.delete(userId)){
throw 'Couln\'t delete peer screen sharing connexion';
}*/
@ -370,14 +370,14 @@ export class SimplePeer {
console.error(
'Could not find peer whose ID is "' + data.userId + '" in receiveWebrtcScreenSharingSignal'
);
console.info("Attempt to create new peer connexion");
console.info("Attempt to create new peer connection");
if (stream) {
this.sendLocalScreenSharingStreamToUser(data.userId, stream);
}
}
} catch (e) {
console.error(`receiveWebrtcSignal => ${data.userId}`, e);
//Comment this peer connexion because if we delete and try to reshare screen, the RTCPeerConnection send renegociate event. This array will be remove when user left circle discussion
//Comment this peer connection because if we delete and try to reshare screen, the RTCPeerConnection send renegotiate event. This array will be remove when user left circle discussion
//this.PeerScreenSharingConnectionArray.delete(data.userId);
this.receiveWebrtcScreenSharingSignal(data);
}
@ -485,7 +485,7 @@ export class SimplePeer {
if (!PeerConnectionScreenSharing.isReceivingScreenSharingStream()) {
PeerConnectionScreenSharing.destroy();
//Comment this peer connexion because if we delete and try to reshare screen, the RTCPeerConnection send renegociate event. This array will be remove when user left circle discussion
//Comment this peer connection because if we delete and try to reshare screen, the RTCPeerConnection send renegotiate event. This array will be remove when user left circle discussion
//this.PeerScreenSharingConnectionArray.delete(userId);
}
}

View file

@ -162,16 +162,3 @@ const app = new App({
});
export default app;
if ("serviceWorker" in navigator) {
window.addEventListener("load", function () {
navigator.serviceWorker
.register("/resources/service-worker.js")
.then((serviceWorker) => {
console.log("Service Worker registered: ", serviceWorker);
})
.catch((error) => {
console.error("Error registering the Service Worker: ", error);
});
});
}

View file

@ -1,28 +1,28 @@
import "jasmine";
import {getRessourceDescriptor} from "../../../src/Phaser/Entity/PlayerTexturesLoadingManager";
import { getRessourceDescriptor } from "../../../src/Phaser/Entity/PlayerTexturesLoadingManager";
describe("getRessourceDescriptor()", () => {
it(", if given a valid descriptor as parameter, should return it", () => {
const desc = getRessourceDescriptor({name: 'name', img: 'url'});
expect(desc.name).toEqual('name');
expect(desc.img).toEqual('url');
const desc = getRessourceDescriptor({ name: "name", img: "url" });
expect(desc.name).toEqual("name");
expect(desc.img).toEqual("url");
});
it(", if given a string as parameter, should search trough hardcoded values", () => {
const desc = getRessourceDescriptor('male1');
expect(desc.name).toEqual('male1');
it(", if given a string as parameter, should search through hardcoded values", () => {
const desc = getRessourceDescriptor("male1");
expect(desc.name).toEqual("male1");
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
});
it(", if given a string as parameter, should search trough hardcoded values (bis)", () => {
const desc = getRessourceDescriptor('color_2');
expect(desc.name).toEqual('color_2');
it(", if given a string as parameter, should search through hardcoded values (bis)", () => {
const desc = getRessourceDescriptor("color_2");
expect(desc.name).toEqual("color_2");
expect(desc.img).toEqual("resources/customisation/character_color/character_color1.png");
});
it(", if given a descriptor without url as parameter, should search trough hardcoded values", () => {
const desc = getRessourceDescriptor({name: 'male1', img: ''});
expect(desc.name).toEqual('male1');
it(", if given a descriptor without url as parameter, should search through hardcoded values", () => {
const desc = getRessourceDescriptor({ name: "male1", img: "" });
expect(desc.name).toEqual("male1");
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
});
});
});