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

This commit is contained in:
David Négrier 2021-07-21 15:37:53 +02:00
commit f435cecfdc
22 changed files with 258 additions and 199 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

View file

@ -30,12 +30,10 @@
<aside class="chatWindow" transition:fly="{{ x: -1000, duration: 500 }}"> <aside class="chatWindow" transition:fly="{{ x: -1000, duration: 500 }}">
<section class="chatWindowTitle"> <p class="close-icon" on:click={closeChat}>&times</p>
<h1>Your chat history <span class="float-right" on:click={closeChat}>&times</span></h1>
</section>
<section class="messagesList" bind:this={listDom}> <section class="messagesList" bind:this={listDom}>
<ul> <ul>
<li><p class="system-text">Here is your chat history: </p></li>
{#each $chatMessagesStore as message, i} {#each $chatMessagesStore as message, i}
<li><ChatElement message={message} line={i}></ChatElement></li> <li><ChatElement message={message} line={i}></ChatElement></li>
{/each} {/each}
@ -47,16 +45,23 @@
</aside> </aside>
<style lang="scss"> <style lang="scss">
h1 { p.close-icon {
font-family: Lato; position: absolute;
padding: 4px;
right: 12px;
font-size: 30px;
line-height: 25px;
cursor: pointer;
}
span.float-right { p.system-text {
font-size: 30px; border-radius: 8px;
line-height: 25px; margin-bottom: 10px;
font-weight: bold; padding:6px;
float: right; overflow-wrap: break-word;
cursor: pointer; max-width: 100%;
} background: gray;
display: inline-block;
} }
aside.chatWindow { aside.chatWindow {
@ -78,16 +83,8 @@
border-bottom-right-radius: 16px; border-bottom-right-radius: 16px;
border-top-right-radius: 16px; border-top-right-radius: 16px;
h1 {
background-color: #5f5f5f;
border-radius: 8px;
padding: 2px;
}
.chatWindowTitle {
flex: 0 100px;
}
.messagesList { .messagesList {
margin-top: 35px;
overflow-y: auto; overflow-y: auto;
flex: auto; flex: auto;
@ -98,7 +95,7 @@
} }
.messageForm { .messageForm {
flex: 0 70px; flex: 0 70px;
padding-top: 20px; padding-top: 15px;
} }
} }
</style> </style>

View file

@ -32,7 +32,7 @@
input { input {
flex: auto; flex: auto;
background-color: #42464d; background-color: #254560;
color: white; color: white;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
border-top-left-radius: 4px; border-top-left-radius: 4px;
@ -45,11 +45,11 @@
} }
button { button {
background-color: #42464d; background-color: #254560;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
border-top-right-radius: 4px; border-top-right-radius: 4px;
border: none; border: none;
border-left: solid black 1px; border-left: solid white 1px;
font-size: 16px; font-size: 16px;
} }
} }

View file

@ -169,6 +169,7 @@ export class Room {
*/ */
public get key(): string { public get key(): string {
const newUrl = new URL(this.roomUrl.toString()); const newUrl = new URL(this.roomUrl.toString());
newUrl.search = "";
newUrl.hash = ""; newUrl.hash = "";
return newUrl.toString(); return newUrl.toString();
} }

View file

@ -1721,7 +1721,7 @@ ${escapedMessage}
this.scene.start(ErrorSceneName, { this.scene.start(ErrorSceneName, {
title: "Banned", title: "Banned",
subTitle: "You were banned from WorkAdventure", subTitle: "You were banned from WorkAdventure",
message: "If you want more information, you may contact us at: workadventure@thecodingmachine.com", message: "If you want more information, you may contact us at: hello@workadventu.re",
}); });
} }
@ -1736,14 +1736,14 @@ ${escapedMessage}
this.scene.start(ErrorSceneName, { this.scene.start(ErrorSceneName, {
title: "Connection rejected", title: "Connection rejected",
subTitle: "The world you are trying to join is full. Try again later.", subTitle: "The world you are trying to join is full. Try again later.",
message: "If you want more information, you may contact us at: workadventure@thecodingmachine.com", message: "If you want more information, you may contact us at: hello@workadventu.re",
}); });
} else { } else {
this.scene.start(ErrorSceneName, { this.scene.start(ErrorSceneName, {
title: "Connection rejected", title: "Connection rejected",
subTitle: "You cannot join the World. Try again later. \n\r \n\r Error: " + message + ".", subTitle: "You cannot join the World. Try again later. \n\r \n\r Error: " + message + ".",
message: message:
"If you want more information, you may contact administrator or contact us at: workadventure@thecodingmachine.com", "If you want more information, you may contact administrator or contact us at: hello@workadventu.re",
}); });
} }
} }

View file

@ -1,8 +1,8 @@
import {gameManager} from "../Game/GameManager"; import { gameManager } from "../Game/GameManager";
import {Scene} from "phaser"; import { Scene } from "phaser";
import {ErrorScene} from "../Reconnecting/ErrorScene"; import { ErrorScene } from "../Reconnecting/ErrorScene";
import {WAError} from "../Reconnecting/WAError"; import { WAError } from "../Reconnecting/WAError";
import {waScaleManager} from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
export const EntrySceneName = "EntryScene"; export const EntrySceneName = "EntryScene";
@ -13,26 +13,32 @@ export const EntrySceneName = "EntryScene";
export class EntryScene extends Scene { export class EntryScene extends Scene {
constructor() { constructor() {
super({ super({
key: EntrySceneName key: EntrySceneName,
}); });
} }
create() { create() {
gameManager
gameManager.init(this.scene).then((nextSceneName) => { .init(this.scene)
// Let's rescale before starting the game .then((nextSceneName) => {
// We can do it at this stage. // Let's rescale before starting the game
waScaleManager.applyNewSize(); // We can do it at this stage.
this.scene.start(nextSceneName); waScaleManager.applyNewSize();
}).catch((err) => { this.scene.start(nextSceneName);
if (err.response && err.response.status == 404) { })
ErrorScene.showError(new WAError( .catch((err) => {
'Access link incorrect', if (err.response && err.response.status == 404) {
'Could not find map. Please check your access link.', ErrorScene.showError(
'If you want more information, you may contact administrator or contact us at: workadventure@thecodingmachine.com'), this.scene); new WAError(
} else { "Access link incorrect",
ErrorScene.showError(err, this.scene); "Could not find map. Please check your access link.",
} "If you want more information, you may contact administrator or contact us at: hello@workadventu.re"
}); ),
this.scene
);
} else {
ErrorScene.showError(err, this.scene);
}
});
} }
} }

View file

@ -1,25 +1,25 @@
import {gameManager} from "../Game/GameManager"; import { gameManager } from "../Game/GameManager";
import Rectangle = Phaser.GameObjects.Rectangle; import Rectangle = Phaser.GameObjects.Rectangle;
import {EnableCameraSceneName} from "./EnableCameraScene"; import { EnableCameraSceneName } from "./EnableCameraScene";
import {CustomizeSceneName} from "./CustomizeScene"; import { CustomizeSceneName } from "./CustomizeScene";
import {localUserStore} from "../../Connexion/LocalUserStore"; import { localUserStore } from "../../Connexion/LocalUserStore";
import {loadAllDefaultModels} from "../Entity/PlayerTexturesLoadingManager"; import { loadAllDefaultModels } from "../Entity/PlayerTexturesLoadingManager";
import {addLoader} from "../Components/Loader"; import { addLoader } from "../Components/Loader";
import type {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures"; import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
import {AbstractCharacterScene} from "./AbstractCharacterScene"; import { AbstractCharacterScene } from "./AbstractCharacterScene";
import {areCharacterLayersValid} from "../../Connexion/LocalUser"; import { areCharacterLayersValid } from "../../Connexion/LocalUser";
import {touchScreenManager} from "../../Touch/TouchScreenManager"; import { touchScreenManager } from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager"; import { PinchManager } from "../UserInput/PinchManager";
import {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore"; import { selectCharacterSceneVisibleStore } from "../../Stores/SelectCharacterStore";
import {waScaleManager} from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import {isMobile} from "../../Enum/EnvironmentVariable"; import { isMobile } from "../../Enum/EnvironmentVariable";
//todo: put this constants in a dedicated file //todo: put this constants in a dedicated file
export const SelectCharacterSceneName = "SelectCharacterScene"; export const SelectCharacterSceneName = "SelectCharacterScene";
export class SelectCharacterScene extends AbstractCharacterScene { export class SelectCharacterScene extends AbstractCharacterScene {
protected readonly nbCharactersPerRow = 6; protected readonly nbCharactersPerRow = 6;
protected selectedPlayer!: Phaser.Physics.Arcade.Sprite|null; // null if we are selecting the "customize" option protected selectedPlayer!: Phaser.Physics.Arcade.Sprite | null; // null if we are selecting the "customize" option
protected players: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>(); protected players: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>();
protected playerModels!: BodyResourceDescriptionInterface[]; protected playerModels!: BodyResourceDescriptionInterface[];
@ -38,7 +38,6 @@ export class SelectCharacterScene extends AbstractCharacterScene {
} }
preload() { preload() {
this.loadSelectSceneCharacters().then((bodyResourceDescriptions) => { this.loadSelectSceneCharacters().then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => { bodyResourceDescriptions.forEach((bodyResourceDescription) => {
this.playerModels.push(bodyResourceDescription); this.playerModels.push(bodyResourceDescription);
@ -54,7 +53,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
create() { create() {
selectCharacterSceneVisibleStore.set(true); selectCharacterSceneVisibleStore.set(true);
this.events.addListener('wake', () => { this.events.addListener("wake", () => {
waScaleManager.saveZoom(); waScaleManager.saveZoom();
waScaleManager.zoomModifier = isMobile() ? 2 : 1; waScaleManager.zoomModifier = isMobile() ? 2 : 1;
selectCharacterSceneVisibleStore.set(true); selectCharacterSceneVisibleStore.set(true);
@ -68,26 +67,26 @@ export class SelectCharacterScene extends AbstractCharacterScene {
waScaleManager.zoomModifier = isMobile() ? 2 : 1; waScaleManager.zoomModifier = isMobile() ? 2 : 1;
const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16; const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16;
this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xFFFFFF); this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xffffff);
this.selectedRectangle.setDepth(2); this.selectedRectangle.setDepth(2);
/*create user*/ /*create user*/
this.createCurrentPlayer(); this.createCurrentPlayer();
this.input.keyboard.on('keyup-ENTER', () => { this.input.keyboard.on("keyup-ENTER", () => {
return this.nextSceneToCameraScene(); return this.nextSceneToCameraScene();
}); });
this.input.keyboard.on('keydown-RIGHT', () => { this.input.keyboard.on("keydown-RIGHT", () => {
this.moveToRight(); this.moveToRight();
}); });
this.input.keyboard.on('keydown-LEFT', () => { this.input.keyboard.on("keydown-LEFT", () => {
this.moveToLeft(); this.moveToLeft();
}); });
this.input.keyboard.on('keydown-UP', () => { this.input.keyboard.on("keydown-UP", () => {
this.moveToUp(); this.moveToUp();
}); });
this.input.keyboard.on('keydown-DOWN', () => { this.input.keyboard.on("keydown-DOWN", () => {
this.moveToDown(); this.moveToDown();
}); });
} }
@ -96,7 +95,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) { if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
return; return;
} }
if(!this.selectedPlayer){ if (!this.selectedPlayer) {
return; return;
} }
this.scene.stop(SelectCharacterSceneName); this.scene.stop(SelectCharacterSceneName);
@ -105,7 +104,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
gameManager.tryResumingGame(this, EnableCameraSceneName); gameManager.tryResumingGame(this, EnableCameraSceneName);
this.players = []; this.players = [];
selectCharacterSceneVisibleStore.set(false); selectCharacterSceneVisibleStore.set(false);
this.events.removeListener('wake'); this.events.removeListener("wake");
} }
public nextSceneToCustomizeScene(): void { public nextSceneToCustomizeScene(): void {
@ -119,11 +118,11 @@ export class SelectCharacterScene extends AbstractCharacterScene {
} }
createCurrentPlayer(): void { createCurrentPlayer(): void {
for (let i = 0; i <this.playerModels.length; i++) { for (let i = 0; i < this.playerModels.length; i++) {
const playerResource = this.playerModels[i]; const playerResource = this.playerModels[i];
//check already exist texture //check already exist texture
if(this.players.find((c) => c.texture.key === playerResource.name)){ if (this.players.find((c) => c.texture.key === playerResource.name)) {
continue; continue;
} }
@ -132,9 +131,9 @@ export class SelectCharacterScene extends AbstractCharacterScene {
this.setUpPlayer(player, i); this.setUpPlayer(player, i);
this.anims.create({ this.anims.create({
key: playerResource.name, key: playerResource.name,
frames: this.anims.generateFrameNumbers(playerResource.name, {start: 0, end: 11}), frames: this.anims.generateFrameNumbers(playerResource.name, { start: 0, end: 11 }),
frameRate: 8, frameRate: 8,
repeat: -1 repeat: -1,
}); });
player.setInteractive().on("pointerdown", () => { player.setInteractive().on("pointerdown", () => {
if (this.pointerClicked) { if (this.pointerClicked) {
@ -153,77 +152,79 @@ export class SelectCharacterScene extends AbstractCharacterScene {
}); });
this.players.push(player); this.players.push(player);
} }
if (this.currentSelectUser >= this.players.length) {
this.currentSelectUser = 0;
}
this.selectedPlayer = this.players[this.currentSelectUser]; this.selectedPlayer = this.players[this.currentSelectUser];
this.selectedPlayer.play(this.playerModels[this.currentSelectUser].name); this.selectedPlayer.play(this.playerModels[this.currentSelectUser].name);
} }
protected moveUser(){ protected moveUser() {
for(let i = 0; i < this.players.length; i++){ for (let i = 0; i < this.players.length; i++) {
const player = this.players[i]; const player = this.players[i];
this.setUpPlayer(player, i); this.setUpPlayer(player, i);
} }
this.updateSelectedPlayer(); this.updateSelectedPlayer();
} }
public moveToLeft(){ public moveToLeft() {
if(this.currentSelectUser === 0){ if (this.currentSelectUser === 0) {
return; return;
} }
this.currentSelectUser -= 1; this.currentSelectUser -= 1;
this.moveUser(); this.moveUser();
} }
public moveToRight(){ public moveToRight() {
if(this.currentSelectUser === (this.players.length - 1)){ if (this.currentSelectUser === this.players.length - 1) {
return; return;
} }
this.currentSelectUser += 1; this.currentSelectUser += 1;
this.moveUser(); this.moveUser();
} }
protected moveToUp(){ protected moveToUp() {
if(this.currentSelectUser < this.nbCharactersPerRow){ if (this.currentSelectUser < this.nbCharactersPerRow) {
return; return;
} }
this.currentSelectUser -= this.nbCharactersPerRow; this.currentSelectUser -= this.nbCharactersPerRow;
this.moveUser(); this.moveUser();
} }
protected moveToDown(){ protected moveToDown() {
if((this.currentSelectUser + this.nbCharactersPerRow) > (this.players.length - 1)){ if (this.currentSelectUser + this.nbCharactersPerRow > this.players.length - 1) {
return; return;
} }
this.currentSelectUser += this.nbCharactersPerRow; this.currentSelectUser += this.nbCharactersPerRow;
this.moveUser(); this.moveUser();
} }
protected defineSetupPlayer(num: number){ protected defineSetupPlayer(num: number) {
const deltaX = 32; const deltaX = 32;
const deltaY = 32; const deltaY = 32;
let [playerX, playerY] = this.getCharacterPosition(); // player X and player y are middle of the let [playerX, playerY] = this.getCharacterPosition(); // player X and player y are middle of the
playerX = ( (playerX - (deltaX * 2.5)) + ((deltaX) * (num % this.nbCharactersPerRow)) ); // calcul position on line users playerX = playerX - deltaX * 2.5 + deltaX * (num % this.nbCharactersPerRow); // calcul position on line users
playerY = ( (playerY - (deltaY * 2)) + ((deltaY) * ( Math.floor(num / this.nbCharactersPerRow) )) ); // calcul position on column users playerY = playerY - deltaY * 2 + deltaY * Math.floor(num / this.nbCharactersPerRow); // calcul position on column users
const playerVisible = true; const playerVisible = true;
const playerScale = 1; const playerScale = 1;
const playerOpacity = 1; const playerOpacity = 1;
// if selected // if selected
if( num === this.currentSelectUser ){ if (num === this.currentSelectUser) {
this.selectedRectangle.setX(playerX); this.selectedRectangle.setX(playerX);
this.selectedRectangle.setY(playerY); this.selectedRectangle.setY(playerY);
} }
return {playerX, playerY, playerScale, playerOpacity, playerVisible} return { playerX, playerY, playerScale, playerOpacity, playerVisible };
} }
protected setUpPlayer(player: Phaser.Physics.Arcade.Sprite, num: number){ protected setUpPlayer(player: Phaser.Physics.Arcade.Sprite, num: number) {
const { playerX, playerY, playerScale, playerOpacity, playerVisible } = this.defineSetupPlayer(num);
const {playerX, playerY, playerScale, playerOpacity, playerVisible} = this.defineSetupPlayer(num);
player.setBounce(0.2); player.setBounce(0.2);
player.setCollideWorldBounds(false); player.setCollideWorldBounds(false);
player.setVisible( playerVisible ); player.setVisible(playerVisible);
player.setScale(playerScale, playerScale); player.setScale(playerScale, playerScale);
player.setAlpha(playerOpacity); player.setAlpha(playerOpacity);
player.setX(playerX); player.setX(playerX);
@ -234,10 +235,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
* Returns pixel position by on column and row number * Returns pixel position by on column and row number
*/ */
protected getCharacterPosition(): [number, number] { protected getCharacterPosition(): [number, number] {
return [ return [this.game.renderer.width / 2, this.game.renderer.height / 2.5];
this.game.renderer.width / 2,
this.game.renderer.height / 2.5
];
} }
protected updateSelectedPlayer(): void { protected updateSelectedPlayer(): void {
@ -256,7 +254,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
this.pointerClicked = false; this.pointerClicked = false;
} }
if(this.lazyloadingAttempt){ if (this.lazyloadingAttempt) {
//re-render players list //re-render players list
this.createCurrentPlayer(); this.createCurrentPlayer();
this.moveUser(); this.moveUser();

View file

@ -20,6 +20,7 @@ import { consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlo
import { get } from "svelte/store"; import { get } from "svelte/store";
import { playersStore } from "../../Stores/PlayersStore"; import { playersStore } from "../../Stores/PlayersStore";
import { mediaManager } from "../../WebRtc/MediaManager"; import { mediaManager } from "../../WebRtc/MediaManager";
import { chatVisibilityStore } from "../../Stores/ChatStore";
export const MenuSceneName = "MenuScene"; export const MenuSceneName = "MenuScene";
const gameMenuKey = "gameMenu"; const gameMenuKey = "gameMenu";
@ -147,6 +148,9 @@ export class MenuScene extends Phaser.Scene {
this.menuElement.on("click", this.onMenuClick.bind(this)); this.menuElement.on("click", this.onMenuClick.bind(this));
worldFullWarningStream.stream.subscribe(() => this.showWorldCapacityWarning()); worldFullWarningStream.stream.subscribe(() => this.showWorldCapacityWarning());
chatVisibilityStore.subscribe((v) => {
this.menuButton.setVisible(!v);
});
} }
//todo put this method in a parent menuElement class //todo put this method in a parent menuElement class

View file

@ -1,14 +1,14 @@
import {TextField} from "../Components/TextField"; import { TextField } from "../Components/TextField";
import Image = Phaser.GameObjects.Image; import Image = Phaser.GameObjects.Image;
import Sprite = Phaser.GameObjects.Sprite; import Sprite = Phaser.GameObjects.Sprite;
import Text = Phaser.GameObjects.Text; import Text = Phaser.GameObjects.Text;
import ScenePlugin = Phaser.Scenes.ScenePlugin; import ScenePlugin = Phaser.Scenes.ScenePlugin;
import {WAError} from "./WAError"; import { WAError } from "./WAError";
export const ErrorSceneName = "ErrorScene"; export const ErrorSceneName = "ErrorScene";
enum Textures { enum Textures {
icon = "icon", icon = "icon",
mainFont = "main_font" mainFont = "main_font",
} }
export class ErrorScene extends Phaser.Scene { export class ErrorScene extends Phaser.Scene {
@ -23,25 +23,21 @@ export class ErrorScene extends Phaser.Scene {
constructor() { constructor() {
super({ super({
key: ErrorSceneName key: ErrorSceneName,
}); });
} }
init({title, subTitle, message}: { title?: string, subTitle?: string, message?: string }) { init({ title, subTitle, message }: { title?: string; subTitle?: string; message?: string }) {
this.title = title ? title : ''; this.title = title ? title : "";
this.subTitle = subTitle ? subTitle : ''; this.subTitle = subTitle ? subTitle : "";
this.message = message ? message : ''; this.message = message ? message : "";
} }
preload() { preload() {
this.load.image(Textures.icon, "resources/logos/tcm_full.png"); this.load.image(Textures.icon, "static/images/favicons/favicon-32x32.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap // Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(Textures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); this.load.bitmapFont(Textures.mainFont, "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
this.load.spritesheet( this.load.spritesheet("cat", "resources/characters/pipoya/Cat 01-1.png", { frameWidth: 32, frameHeight: 32 });
'cat',
'resources/characters/pipoya/Cat 01-1.png',
{frameWidth: 32, frameHeight: 32}
);
} }
create() { create() {
@ -50,15 +46,25 @@ export class ErrorScene extends Phaser.Scene {
this.titleField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height / 2, this.title); this.titleField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height / 2, this.title);
this.subTitleField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height / 2 + 24, this.subTitle); this.subTitleField = new TextField(
this,
this.game.renderer.width / 2,
this.game.renderer.height / 2 + 24,
this.subTitle
);
this.messageField = this.add.text(this.game.renderer.width / 2, this.game.renderer.height / 2 + 48, this.message, { this.messageField = this.add.text(
fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif', this.game.renderer.width / 2,
fontSize: '10px' this.game.renderer.height / 2 + 48,
}); this.message,
{
fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif',
fontSize: "10px",
}
);
this.messageField.setOrigin(0.5, 0.5); this.messageField.setOrigin(0.5, 0.5);
this.cat = this.physics.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, 'cat', 6); this.cat = this.physics.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, "cat", 6);
this.cat.flipY = true; this.cat.flipY = true;
} }
@ -69,38 +75,38 @@ export class ErrorScene extends Phaser.Scene {
public static showError(error: any, scene: ScenePlugin): void { public static showError(error: any, scene: ScenePlugin): void {
console.error(error); console.error(error);
if (typeof error === 'string' || error instanceof String) { if (typeof error === "string" || error instanceof String) {
scene.start(ErrorSceneName, { scene.start(ErrorSceneName, {
title: 'An error occurred', title: "An error occurred",
subTitle: error subTitle: error,
}); });
} else if (error instanceof WAError) { } else if (error instanceof WAError) {
scene.start(ErrorSceneName, { scene.start(ErrorSceneName, {
title: error.title, title: error.title,
subTitle: error.subTitle, subTitle: error.subTitle,
message: error.details message: error.details,
}); });
} else if (error.response) { } else if (error.response) {
// Axios HTTP error // Axios HTTP error
// client received an error response (5xx, 4xx) // client received an error response (5xx, 4xx)
scene.start(ErrorSceneName, { scene.start(ErrorSceneName, {
title: 'HTTP ' + error.response.status + ' - ' + error.response.statusText, title: "HTTP " + error.response.status + " - " + error.response.statusText,
subTitle: 'An error occurred while accessing URL:', subTitle: "An error occurred while accessing URL:",
message: error.response.config.url message: error.response.config.url,
}); });
} else if (error.request) { } else if (error.request) {
// Axios HTTP error // Axios HTTP error
// client never received a response, or request never left // client never received a response, or request never left
scene.start(ErrorSceneName, { scene.start(ErrorSceneName, {
title: 'Network error', title: "Network error",
subTitle: error.message subTitle: error.message,
}); });
} else if (error instanceof Error) { } else if (error instanceof Error) {
// Error // Error
scene.start(ErrorSceneName, { scene.start(ErrorSceneName, {
title: 'An error occurred', title: "An error occurred",
subTitle: error.name, subTitle: error.name,
message: error.message message: error.message,
}); });
} else { } else {
throw error; throw error;
@ -114,7 +120,7 @@ export class ErrorScene extends Phaser.Scene {
scene.start(ErrorSceneName, { scene.start(ErrorSceneName, {
title, title,
subTitle, subTitle,
message message,
}); });
} }
} }

View file

@ -1,11 +1,11 @@
import {TextField} from "../Components/TextField"; import { TextField } from "../Components/TextField";
import Image = Phaser.GameObjects.Image; import Image = Phaser.GameObjects.Image;
import Sprite = Phaser.GameObjects.Sprite; import Sprite = Phaser.GameObjects.Sprite;
export const ReconnectingSceneName = "ReconnectingScene"; export const ReconnectingSceneName = "ReconnectingScene";
enum ReconnectingTextures { enum ReconnectingTextures {
icon = "icon", icon = "icon",
mainFont = "main_font" mainFont = "main_font",
} }
export class ReconnectingScene extends Phaser.Scene { export class ReconnectingScene extends Phaser.Scene {
@ -14,35 +14,40 @@ export class ReconnectingScene extends Phaser.Scene {
constructor() { constructor() {
super({ super({
key: ReconnectingSceneName key: ReconnectingSceneName,
}); });
} }
preload() { preload() {
this.load.image(ReconnectingTextures.icon, "resources/logos/tcm_full.png"); this.load.image(ReconnectingTextures.icon, "static/images/favicons/favicon-32x32.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap // Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(ReconnectingTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); this.load.bitmapFont(ReconnectingTextures.mainFont, "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
this.load.spritesheet( this.load.spritesheet("cat", "resources/characters/pipoya/Cat 01-1.png", { frameWidth: 32, frameHeight: 32 });
'cat',
'resources/characters/pipoya/Cat 01-1.png',
{frameWidth: 32, frameHeight: 32}
);
} }
create() { create() {
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, ReconnectingTextures.icon); this.logo = new Image(
this,
this.game.renderer.width - 30,
this.game.renderer.height - 20,
ReconnectingTextures.icon
);
this.add.existing(this.logo); this.add.existing(this.logo);
this.reconnectingField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height / 2, "Connection lost. Reconnecting..."); this.reconnectingField = new TextField(
this,
this.game.renderer.width / 2,
this.game.renderer.height / 2,
"Connection lost. Reconnecting..."
);
const cat = this.physics.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, 'cat'); const cat = this.physics.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, "cat");
this.anims.create({ this.anims.create({
key: 'right', key: "right",
frames: this.anims.generateFrameNumbers('cat', { start: 6, end: 8 }), frames: this.anims.generateFrameNumbers("cat", { start: 6, end: 8 }),
frameRate: 10, frameRate: 10,
repeat: -1 repeat: -1,
}); });
cat.play('right'); cat.play("right");
} }
} }

View file

@ -96,6 +96,7 @@ function createChatMessagesStore() {
} }
return list; return list;
}); });
chatVisibilityStore.set(true);
}, },
}; };
} }

View file

@ -3,6 +3,8 @@ import type { PlayerInterface } from "../Phaser/Game/PlayerInterface";
import type { RoomConnection } from "../Connexion/RoomConnection"; import type { RoomConnection } from "../Connexion/RoomConnection";
import { getRandomColor } from "../WebRtc/ColorGenerator"; import { getRandomColor } from "../WebRtc/ColorGenerator";
let idCount = 0;
/** /**
* A store that contains the list of players currently known. * A store that contains the list of players currently known.
*/ */
@ -40,6 +42,27 @@ function createPlayersStore() {
getPlayerById(userId: number): PlayerInterface | undefined { getPlayerById(userId: number): PlayerInterface | undefined {
return players.get(userId); return players.get(userId);
}, },
addFacticePlayer(name: string): number {
let userId: number | null = null;
players.forEach((p) => {
if (p.name === name) userId = p.userId;
});
if (userId) return userId;
const newUserId = idCount--;
update((users) => {
users.set(newUserId, {
userId: newUserId,
name,
characterLayers: [],
visitCardUrl: null,
companion: null,
userUuid: "dummy",
color: getRandomColor(),
});
return users;
});
return newUserId;
},
}; };
} }

View file

@ -1,11 +1,12 @@
import { iframeListener } from "../Api/IframeListener"; import { iframeListener } from "../Api/IframeListener";
import { chatMessagesStore, chatVisibilityStore } from "../Stores/ChatStore"; import { chatMessagesStore } from "../Stores/ChatStore";
import { playersStore } from "../Stores/PlayersStore";
export class DiscussionManager { export class DiscussionManager {
constructor() { constructor() {
iframeListener.chatStream.subscribe((chatEvent) => { iframeListener.chatStream.subscribe((chatEvent) => {
chatMessagesStore.addExternalMessage(parseInt(chatEvent.author), chatEvent.message); const userId = playersStore.addFacticePlayer(chatEvent.author);
chatVisibilityStore.set(true); chatMessagesStore.addExternalMessage(userId, chatEvent.message);
}); });
} }
} }

View file

@ -170,7 +170,6 @@ export class VideoPeer extends Peer {
} else if (message.type === MESSAGE_TYPE_MESSAGE) { } else if (message.type === MESSAGE_TYPE_MESSAGE) {
if (!blackListManager.isBlackListed(this.userUuid)) { if (!blackListManager.isBlackListed(this.userUuid)) {
chatMessagesStore.addExternalMessage(this.userId, message.message); chatMessagesStore.addExternalMessage(this.userId, message.message);
chatVisibilityStore.set(true);
} }
} else if (message.type === MESSAGE_TYPE_BLOCKED) { } else if (message.type === MESSAGE_TYPE_BLOCKED) {
//FIXME when A blacklists B, the output stream from A is muted in B's js client. This is insecure since B can manipulate the code to unmute A stream. //FIXME when A blacklists B, the output stream from A is muted in B's js client. This is insecure since B can manipulate the code to unmute A stream.

View file

@ -8,7 +8,7 @@ GNU GPL 3.0:
- http://www.gnu.org/licenses/gpl-3.0.html - http://www.gnu.org/licenses/gpl-3.0.html
- See the file: gpl-3.0.txt - See the file: gpl-3.0.txt
Assets from: workadventure@thecodingmachine.com Assets from: hello@workadventu.re
BASE assets: BASE assets:
------------ ------------

View file

@ -8,7 +8,7 @@ GNU GPL 3.0:
- http://www.gnu.org/licenses/gpl-3.0.html - http://www.gnu.org/licenses/gpl-3.0.html
- See the file: gpl-3.0.txt - See the file: gpl-3.0.txt
Assets from: workadventure@thecodingmachine.com Assets from: hello@workadventu.re
BASE assets: BASE assets:
------------ ------------

View file

@ -1,13 +1,20 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<script src="http://play.workadventure.localhost/iframe_api.js"></script> <script>
</head> var script = document.createElement('script');
<body> // Don't do this at home kids! The "document.referrer" part is actually inserting a XSS security.
<script> // We are OK in this precise case because the HTML page is hosted on the "maps" domain that contains only static files.
WA.ui.registerMenuCommand("test", () => { script.setAttribute('src', document.referrer + 'iframe_api.js');
WA.chat.sendChatMessage("test clicked", "menu cmd") document.head.appendChild(script);
window.addEventListener('load', () => {
WA.ui.registerMenuCommand("test", () => {
WA.chat.sendChatMessage("test clicked", "menu cmd")
})
}) })
</script> </script>
</head>
<body>
<p>Add a custom menu</p>
</body> </body>
</html> </html>

View file

@ -1,12 +1,18 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<script src="http://play.workadventure.localhost/iframe_api.js"></script> <script>
var script = document.createElement('script');
// Don't do this at home kids! The "document.referrer" part is actually inserting a XSS security.
// We are OK in this precise case because the HTML page is hosted on the "maps" domain that contains only static files.
script.setAttribute('src', document.referrer + 'iframe_api.js');
document.head.appendChild(script);
window.addEventListener('load', () => {
WA.player.onPlayerMove(console.log);
})
</script>
</head> </head>
<body> <body>
<div id="playerMovement"></div> <p>Log in the console the movement of the current player in the zone of the iframe</p>
<script>
WA.player.onPlayerMove(console.log);
</script>
</body> </body>
</html> </html>

View file

@ -1,12 +1,19 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<script src="http://play.workadventure.localhost/iframe_api.js"></script> <script>
var script = document.createElement('script');
// Don't do this at home kids! The "document.referrer" part is actually inserting a XSS security.
// We are OK in this precise case because the HTML page is hosted on the "maps" domain that contains only static files.
script.setAttribute('src', document.referrer + 'iframe_api.js');
document.head.appendChild(script);
window.addEventListener('load', () => {
WA.room.setProperty('iframeTest', 'openWebsite', 'https://www.wikipedia.org/');
WA.room.setProperty('metadata', 'openWebsite', 'https://www.wikipedia.org/');
})
</script>
</head> </head>
<body> <body>
<script> <p>Change the url of this iframe and add the 'openWebsite' property to the red tile layer</p>
WA.room.setProperty('iframeTest', 'openWebsite', 'https://www.wikipedia.org/');
WA.room.setProperty('metadata', 'openWebsite', 'https://www.wikipedia.org/');
</script>
</body> </body>
</html> </html>

View file

@ -1,21 +1,27 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<script src="http://play.workadventure.localhost/iframe_api.js"></script> <script>
var script = document.createElement('script');
// Don't do this at home kids! The "document.referrer" part is actually inserting a XSS security.
// We are OK in this precise case because the HTML page is hosted on the "maps" domain that contains only static files.
script.setAttribute('src', document.referrer + 'iframe_api.js');
document.head.appendChild(script);
window.addEventListener('load', () => {
document.getElementById('show/hideLayer').onclick = () => {
if (document.getElementById('show/hideLayer').checked) {
WA.room.showLayer('crystal');
}
else {
WA.room.hideLayer('crystal');
}
}
})
</script>
</head> </head>
<body> <body>
<div> <div>
<label for="show/hideLayer">Crysal Layer : </label><input type="checkbox" id="show/hideLayer" name="visible" value="show" checked> <label for="show/hideLayer">Crysal Layer : </label><input type="checkbox" id="show/hideLayer" name="visible" value="show" checked>
</div> </div>
<script>
document.getElementById('show/hideLayer').onclick = () => {
if (document.getElementById('show/hideLayer').checked) {
WA.room.showLayer('crystal');
}
else {
WA.room.hideLayer('crystal');
}
}
</script>
</body> </body>
</html> </html>

View file

@ -124,10 +124,10 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<input type="radio" name="test-getCurrentRoom"> Success <input type="radio" name="test-getCurrentRoom"> Failure <input type="radio" name="test-getCurrentRoom" checked> Pending <input type="radio" name="test-getCurrentUser"> Success <input type="radio" name="test-getCurrentUser"> Failure <input type="radio" name="test-getCurrentUser" checked> Pending
</td> </td>
<td> <td>
<a href="#" class="testLink" data-testmap="Metadata/getCurrentRoom.json" target="_blank">Testing room/player attributes in Scripting API + WA.onInit</a> <a href="#" class="testLink" data-testmap="Metadata/getCurrentRoom.json" target="_blank">Testing return current player attributes in Scripting API + WA.onInit</a>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -178,14 +178,6 @@
<a href="#" class="testLink" data-testmap="start-tile.json#S2" target="_blank">Test start tile (S2)</a> <a href="#" class="testLink" data-testmap="start-tile.json#S2" target="_blank">Test start tile (S2)</a>
</td> </td>
</tr> </tr>
<tr>
<td>
<input type="radio" name="test-cowebsite-allowAPI"> Success <input type="radio" name="test-cowebsite-allowAPI"> Failure <input type="radio" name="test-cowebsite-allowAPI" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="Metadata/cowebsiteAllowApi.json" target="_blank">Test cowebsite opened by script is allowed to use IFrame API</a>
</td>
</tr>
<tr> <tr>
<td> <td>
<input type="radio" name="test-set-tiles"> Success <input type="radio" name="test-set-tiles"> Failure <input type="radio" name="test-set-tiles" checked> Pending <input type="radio" name="test-set-tiles"> Success <input type="radio" name="test-set-tiles"> Failure <input type="radio" name="test-set-tiles" checked> Pending