Merge branch 'develop' of github.com:thecodingmachine/workadventure into GlobalMessageToWorld
This commit is contained in:
commit
bd96a32d5b
@ -33,7 +33,7 @@
|
||||
- Use `WA.state.[any variable]: unknown` to access directly any variable (this is a shortcut to using `WA.state.loadVariable` and `WA.state.saveVariable`)
|
||||
- Users blocking now relies on UUID rather than ID. A blocked user that leaves a room and comes back will stay blocked.
|
||||
- The text chat was redesigned to be prettier and to use more features :
|
||||
- The chat is now persistent bewteen discussions and always accesible
|
||||
- The chat is now persistent between discussions and always accessible
|
||||
- The chat now tracks incoming and outcoming users in your conversation
|
||||
- The chat allows your to see the visit card of users
|
||||
- You can close the chat window with the escape key
|
||||
|
@ -104,6 +104,15 @@ export class GameRoom {
|
||||
public getUserById(id: number): User | undefined {
|
||||
return this.users.get(id);
|
||||
}
|
||||
public getUsersByUuid(uuid: string): User[] {
|
||||
const userList: User[] = [];
|
||||
for (const user of this.users.values()) {
|
||||
if (user.uuid === uuid) {
|
||||
userList.push(user);
|
||||
}
|
||||
}
|
||||
return userList;
|
||||
}
|
||||
|
||||
public join(socket: UserSocket, joinRoomMessage: JoinRoomMessage): User {
|
||||
const positionMessage = joinRoomMessage.getPositionmessage();
|
||||
|
@ -21,7 +21,7 @@ interface ZoneDescriptor {
|
||||
}
|
||||
|
||||
export class PositionNotifier {
|
||||
// TODO: we need a way to clean the zones if noone is in the zone and noone listening (to free memory!)
|
||||
// TODO: we need a way to clean the zones if no one is in the zone and no one listening (to free memory!)
|
||||
|
||||
private zones: Zone[][] = [];
|
||||
|
||||
|
@ -57,7 +57,7 @@ const roomManager: IRoomManagerServer = {
|
||||
room = gameRoom;
|
||||
user = myUser;
|
||||
} else {
|
||||
//Connexion may have been closed before the init was finished, so we have to manually disconnect the user.
|
||||
//Connection may have been closed before the init was finished, so we have to manually disconnect the user.
|
||||
socketManager.leaveRoom(gameRoom, myUser);
|
||||
}
|
||||
})
|
||||
|
@ -701,8 +701,8 @@ export class SocketManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const recipient = room.getUserByUuid(recipientUuid);
|
||||
if (recipient === undefined) {
|
||||
const recipients = room.getUsersByUuid(recipientUuid);
|
||||
if (recipients.length === 0) {
|
||||
console.error(
|
||||
"In sendAdminMessage, could not find user with id '" +
|
||||
recipientUuid +
|
||||
@ -711,14 +711,16 @@ export class SocketManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const sendUserMessage = new SendUserMessage();
|
||||
sendUserMessage.setMessage(message);
|
||||
sendUserMessage.setType("ban"); //todo: is the type correct?
|
||||
for (const recipient of recipients) {
|
||||
const sendUserMessage = new SendUserMessage();
|
||||
sendUserMessage.setMessage(message);
|
||||
sendUserMessage.setType("ban"); //todo: is the type correct?
|
||||
|
||||
const serverToClientMessage = new ServerToClientMessage();
|
||||
serverToClientMessage.setSendusermessage(sendUserMessage);
|
||||
const serverToClientMessage = new ServerToClientMessage();
|
||||
serverToClientMessage.setSendusermessage(sendUserMessage);
|
||||
|
||||
recipient.socket.write(serverToClientMessage);
|
||||
recipient.socket.write(serverToClientMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public async banUser(roomId: string, recipientUuid: string, message: string): Promise<void> {
|
||||
@ -732,8 +734,8 @@ export class SocketManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const recipient = room.getUserByUuid(recipientUuid);
|
||||
if (recipient === undefined) {
|
||||
const recipients = room.getUsersByUuid(recipientUuid);
|
||||
if (recipients.length === 0) {
|
||||
console.error(
|
||||
"In banUser, could not find user with id '" +
|
||||
recipientUuid +
|
||||
@ -742,19 +744,21 @@ export class SocketManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's leave the room now.
|
||||
room.leave(recipient);
|
||||
for (const recipient of recipients) {
|
||||
// Let's leave the room now.
|
||||
room.leave(recipient);
|
||||
|
||||
const banUserMessage = new BanUserMessage();
|
||||
banUserMessage.setMessage(message);
|
||||
banUserMessage.setType("banned");
|
||||
const banUserMessage = new BanUserMessage();
|
||||
banUserMessage.setMessage(message);
|
||||
banUserMessage.setType("banned");
|
||||
|
||||
const serverToClientMessage = new ServerToClientMessage();
|
||||
serverToClientMessage.setBanusermessage(banUserMessage);
|
||||
const serverToClientMessage = new ServerToClientMessage();
|
||||
serverToClientMessage.setBanusermessage(banUserMessage);
|
||||
|
||||
// Let's close the connection when the user is banned.
|
||||
recipient.socket.write(serverToClientMessage);
|
||||
recipient.socket.end();
|
||||
// Let's close the connection when the user is banned.
|
||||
recipient.socket.write(serverToClientMessage);
|
||||
recipient.socket.end();
|
||||
}
|
||||
}
|
||||
|
||||
async sendAdminRoomMessage(roomId: string, message: string, type: string) {
|
||||
|
35
docs/maps/text.md
Normal file
35
docs/maps/text.md
Normal file
@ -0,0 +1,35 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Writing text on a map
|
||||
|
||||
## Solution 1: design a specific tileset (recommended)
|
||||
|
||||
If you want to write some text on a map, our recommendation is to create a tileset that contains
|
||||
your text. You will obtain the most pleasant graphical result with this result, since you will be able
|
||||
to control the fonts you use, and you will be able to disable the antialiasing of the font to get a
|
||||
"crispy" result easily.
|
||||
|
||||
## Solution 2: using a "text" object in Tiled
|
||||
|
||||
On "object" layers, Tiled has support for "Text" objects. You can use these objects to add some
|
||||
text on your map.
|
||||
|
||||
WorkAdventure will do its best to display the text properly. However, you need to know that:
|
||||
|
||||
- Tiled displays your system fonts.
|
||||
- Computers have different sets of fonts. Therefore, browsers never rely on system fonts
|
||||
- Which means if you select a font in Tiled, it is quite unlikely it will render properly in WorkAdventure
|
||||
|
||||
To circumvent this problem, in your text object in Tiled, you can add an additional property: `font-family`.
|
||||
|
||||
The `font-family` property can contain any "web-font" that can be loaded by your browser.
|
||||
|
||||
{.alert.alert-info}
|
||||
**Pro-tip:** By default, WorkAdventure uses the **'"Press Start 2P"'** font, which is a great pixelated
|
||||
font that has support for a variety of accents. It renders great when used at *8px* size.
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="https://workadventu.re/img/docs/text-object.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">The "font-family" property</figcaption>
|
||||
</figure>
|
||||
</div>
|
@ -56,7 +56,7 @@ A few things to notice:
|
||||
|
||||
## Building walls and "collidable" areas
|
||||
|
||||
By default, the characters can traverse any tiles. If you want to prevent your characeter from going through a tile (like a wall or a desktop), you must make this tile "collidable". You can do this by settings the `collides` property on a given tile.
|
||||
By default, the characters can traverse any tiles. If you want to prevent your character from going through a tile (like a wall or a desktop), you must make this tile "collidable". You can do this by settings the `collides` property on a given tile.
|
||||
|
||||
To make a tile "collidable", you should:
|
||||
|
||||
|
1
front/dist/index.tmpl.html
vendored
1
front/dist/index.tmpl.html
vendored
@ -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">
|
||||
|
62
front/dist/resources/service-worker.html
vendored
Normal file
62
front/dist/resources/service-worker.html
vendored
Normal 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>
|
12
front/dist/resources/service-worker.js
vendored
12
front/dist/resources/service-worker.js
vendored
@ -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
|
||||
});
|
@ -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": [
|
||||
|
@ -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}>×</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>
|
||||
|
||||
|
@ -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, {
|
||||
|
@ -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>
|
||||
|
@ -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) => {
|
||||
|
@ -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) ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
|
20
front/src/Network/ServiceWorker.ts
Normal file
20
front/src/Network/ServiceWorker.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -176,7 +176,7 @@ Tuomo Untinen CC-BY-3.0
|
||||
|
||||
Casper Nilsson
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- Asain themed shrine including red lantern
|
||||
- Asian themed shrine including red lantern
|
||||
- foodog statue
|
||||
- Toro
|
||||
- Cherry blossom tree
|
||||
|
@ -58,11 +58,17 @@
|
||||
"height":94.6489098314831,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"properties":[
|
||||
{
|
||||
"name":"font-family",
|
||||
"type":"string",
|
||||
"value":"\"Press Start 2P\""
|
||||
}],
|
||||
"rotation":0,
|
||||
"text":
|
||||
{
|
||||
"fontfamily":"Sans Serif",
|
||||
"pixelsize":11,
|
||||
"pixelsize":8,
|
||||
"text":"Test:\nWalk on the carpet and press space\nResult:\nJitsi opens on meet.jit.si (check this in the network tab). Note: this test only makes sense if the default configured Jitsi instance is NOT meet.jit.si (check your .env file)",
|
||||
"wrap":true
|
||||
},
|
||||
|
@ -21,7 +21,7 @@ interface ZoneDescriptor {
|
||||
}
|
||||
|
||||
export class PositionDispatcher {
|
||||
// TODO: we need a way to clean the zones if noone is in the zone and noone listening (to free memory!)
|
||||
// TODO: we need a way to clean the zones if no one is in the zone and no one listening (to free memory!)
|
||||
|
||||
private zones: Zone[][] = [];
|
||||
|
||||
|
@ -452,7 +452,7 @@ export class SocketManager implements ZoneEventListener {
|
||||
|
||||
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||
} catch (e) {
|
||||
console.error("An error occured while generating the Jitsi JWT token: ", e);
|
||||
console.error("An error occurred while generating the Jitsi JWT token: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user