Merge pull request #828 from thecodingmachine/develop
Deploy 2021-03-22
This commit is contained in:
commit
f9a2097bc9
57 changed files with 1191 additions and 937 deletions
|
@ -3,6 +3,7 @@ import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
|
|||
import {RoomConnection} from "../Connexion/RoomConnection";
|
||||
import {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
||||
import {ADMIN_URL} from "../Enum/EnvironmentVariable";
|
||||
import {AdminMessageEventTypes} from "../Connexion/AdminMessagesService";
|
||||
|
||||
export const CLASS_CONSOLE_MESSAGE = 'main-console';
|
||||
export const INPUT_CONSOLE_MESSAGE = 'input-send-text';
|
||||
|
@ -10,13 +11,16 @@ export const UPLOAD_CONSOLE_MESSAGE = 'input-upload-music';
|
|||
export const INPUT_TYPE_CONSOLE = 'input-type';
|
||||
export const VIDEO_QUALITY_SELECT = 'select-video-quality';
|
||||
|
||||
export const AUDIO_TYPE = 'audio';
|
||||
export const MESSAGE_TYPE = 'message';
|
||||
export const AUDIO_TYPE = AdminMessageEventTypes.audio;
|
||||
export const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
||||
|
||||
interface EventTargetFiles extends EventTarget {
|
||||
files: Array<File>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export class ConsoleGlobalMessageManager {
|
||||
|
||||
private readonly divMainConsole: HTMLDivElement;
|
||||
|
@ -48,7 +52,7 @@ export class ConsoleGlobalMessageManager {
|
|||
//this.buttonAdminMainConsole = document.createElement('img');
|
||||
this.userInputManager = userInputManager;
|
||||
this.initialise();
|
||||
|
||||
|
||||
}
|
||||
|
||||
initialise() {
|
||||
|
@ -140,7 +144,7 @@ export class ConsoleGlobalMessageManager {
|
|||
const div = document.createElement('div');
|
||||
div.id = INPUT_CONSOLE_MESSAGE
|
||||
const buttonSend = document.createElement('button');
|
||||
buttonSend.innerText = 'Envoyer';
|
||||
buttonSend.innerText = 'Send';
|
||||
buttonSend.classList.add('btn');
|
||||
buttonSend.addEventListener('click', (event: MouseEvent) => {
|
||||
this.sendMessage();
|
||||
|
@ -242,7 +246,7 @@ export class ConsoleGlobalMessageManager {
|
|||
div.appendChild(input);
|
||||
|
||||
const buttonSend = document.createElement('button');
|
||||
buttonSend.innerText = 'Envoyer';
|
||||
buttonSend.innerText = 'Send';
|
||||
buttonSend.classList.add('btn');
|
||||
buttonSend.addEventListener('click', (event: MouseEvent) => {
|
||||
this.sendMessage();
|
||||
|
@ -372,23 +376,6 @@ export class ConsoleGlobalMessageManager {
|
|||
this.buttonSendMainConsole.classList.remove('active');
|
||||
}
|
||||
|
||||
/*activeSettingConsole(){
|
||||
this.activeSetting = true;
|
||||
if(this.activeMessage){
|
||||
this.disabledSettingConsole();
|
||||
}
|
||||
this.active();
|
||||
this.divSettingConsole.classList.add('active');
|
||||
//this.buttonSettingsMainConsole.classList.add('active');
|
||||
}
|
||||
|
||||
disabledSettingConsole(){
|
||||
this.activeSetting = false;
|
||||
this.disabled();
|
||||
this.divSettingConsole.classList.remove('active');
|
||||
//this.buttonSettingsMainConsole.classList.remove('active');
|
||||
}*/
|
||||
|
||||
private getSectionId(id: string) : string {
|
||||
return `section-${id}`;
|
||||
}
|
||||
|
|
|
@ -77,8 +77,10 @@ export class TypeMessageExt implements TypeMessageInterface{
|
|||
}
|
||||
}
|
||||
}
|
||||
export class Ban extends TypeMessageExt {
|
||||
}
|
||||
|
||||
export class Message extends TypeMessageExt {}
|
||||
|
||||
export class Ban extends TypeMessageExt {}
|
||||
|
||||
export class Banned extends TypeMessageExt {
|
||||
showMessage(message: string){
|
||||
|
|
|
@ -1,39 +1,29 @@
|
|||
import {RoomConnection} from "../Connexion/RoomConnection";
|
||||
import * as TypeMessages from "./TypeMessage";
|
||||
import List = Phaser.Structs.List;
|
||||
import {UpdatedLocalStreamCallback} from "../WebRtc/MediaManager";
|
||||
import {Banned} from "./TypeMessage";
|
||||
import {adminMessagesService} from "../Connexion/AdminMessagesService";
|
||||
|
||||
export interface TypeMessageInterface {
|
||||
showMessage(message: string): void;
|
||||
}
|
||||
|
||||
export class UserMessageManager {
|
||||
class UserMessageManager {
|
||||
|
||||
typeMessages: Map<string, TypeMessageInterface> = new Map<string, TypeMessageInterface>();
|
||||
receiveBannedMessageListener: Set<Function> = new Set<UpdatedLocalStreamCallback>();
|
||||
receiveBannedMessageListener!: Function;
|
||||
|
||||
constructor(private Connection: RoomConnection) {
|
||||
constructor() {
|
||||
const valueTypeMessageTab = Object.values(TypeMessages);
|
||||
Object.keys(TypeMessages).forEach((value: string, index: number) => {
|
||||
const typeMessageInstance: TypeMessageInterface = (new valueTypeMessageTab[index]() as TypeMessageInterface);
|
||||
this.typeMessages.set(value.toLowerCase(), typeMessageInstance);
|
||||
});
|
||||
this.initialise();
|
||||
}
|
||||
|
||||
initialise() {
|
||||
//receive signal to show message
|
||||
this.Connection.receiveUserMessage((type: string, message: string) => {
|
||||
const typeMessage = this.showMessage(type, message);
|
||||
|
||||
//listener on banned receive message
|
||||
adminMessagesService.messageStream.subscribe((event) => {
|
||||
const typeMessage = this.showMessage(event.type, event.text);
|
||||
if(typeMessage instanceof Banned) {
|
||||
for (const callback of this.receiveBannedMessageListener) {
|
||||
callback();
|
||||
}
|
||||
this.receiveBannedMessageListener();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
showMessage(type: string, message: string) {
|
||||
|
@ -47,6 +37,7 @@ export class UserMessageManager {
|
|||
}
|
||||
|
||||
setReceiveBanListener(callback: Function){
|
||||
this.receiveBannedMessageListener.add(callback);
|
||||
this.receiveBannedMessageListener = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
export const userMessageManager = new UserMessageManager()
|
34
front/src/Connexion/AdminMessagesService.ts
Normal file
34
front/src/Connexion/AdminMessagesService.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import {Subject} from "rxjs";
|
||||
import {BanUserMessage, SendUserMessage} from "../Messages/generated/messages_pb";
|
||||
|
||||
export enum AdminMessageEventTypes {
|
||||
admin = 'message',
|
||||
audio = 'audio',
|
||||
ban = 'ban',
|
||||
}
|
||||
|
||||
interface AdminMessageEvent {
|
||||
type: AdminMessageEventTypes,
|
||||
text: string;
|
||||
//todo add optional properties for other event types
|
||||
}
|
||||
|
||||
//this class is designed to easily allow communication between the RoomConnection objects (that receive the message)
|
||||
//and the various objects that may render the message on screen
|
||||
class AdminMessagesService {
|
||||
private _messageStream: Subject<AdminMessageEvent> = new Subject();
|
||||
public messageStream = this._messageStream.asObservable();
|
||||
|
||||
constructor() {
|
||||
this.messageStream.subscribe((event) => console.log('message', event))
|
||||
}
|
||||
|
||||
onSendusermessage(message: SendUserMessage|BanUserMessage) {
|
||||
this._messageStream.next({
|
||||
type: message.getType() as unknown as AdminMessageEventTypes,
|
||||
text: message.getMessage(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const adminMessagesService = new AdminMessagesService();
|
|
@ -6,11 +6,22 @@ import {GameConnexionTypes, urlManager} from "../Url/UrlManager";
|
|||
import {localUserStore} from "./LocalUserStore";
|
||||
import {LocalUser} from "./LocalUser";
|
||||
import {Room} from "./Room";
|
||||
import {Subject} from "rxjs";
|
||||
|
||||
export enum ConnexionMessageEventTypes {
|
||||
worldFull = 1,
|
||||
}
|
||||
|
||||
export interface ConnexionMessageEvent {
|
||||
type: ConnexionMessageEventTypes,
|
||||
}
|
||||
|
||||
class ConnectionManager {
|
||||
private localUser!:LocalUser;
|
||||
|
||||
private connexionType?: GameConnexionTypes
|
||||
|
||||
public _connexionMessageStream:Subject<ConnexionMessageEvent> = new Subject();
|
||||
/**
|
||||
* Tries to login to the node server and return the starting map url to be loaded
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {PlayerAnimationNames} from "../Phaser/Player/Animation";
|
||||
import {PlayerAnimationDirections} from "../Phaser/Player/Animation";
|
||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||
import {SignalData} from "simple-peer";
|
||||
import {RoomConnection} from "./RoomConnection";
|
||||
|
@ -42,14 +42,6 @@ export interface PointInterface {
|
|||
moving: boolean;
|
||||
}
|
||||
|
||||
export class Point implements PointInterface{
|
||||
constructor(public x : number, public y : number, public direction : string = PlayerAnimationNames.WalkDown, public moving : boolean = false) {
|
||||
if(x === null || y === null){
|
||||
throw Error("position x and y cannot be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface MessageUserPositionInterface {
|
||||
userId: number;
|
||||
name: string;
|
||||
|
@ -80,20 +72,10 @@ export interface GroupCreatedUpdatedMessageInterface {
|
|||
groupSize: number
|
||||
}
|
||||
|
||||
export interface WebRtcStartMessageInterface {
|
||||
roomId: string,
|
||||
clients: UserSimplePeerInterface[]
|
||||
}
|
||||
|
||||
export interface WebRtcDisconnectMessageInterface {
|
||||
userId: number
|
||||
}
|
||||
|
||||
export interface WebRtcSignalSentMessageInterface {
|
||||
receiverId: number,
|
||||
signal: SignalData
|
||||
}
|
||||
|
||||
export interface WebRtcSignalReceivedMessageInterface {
|
||||
userId: number,
|
||||
signal: SignalData,
|
||||
|
@ -113,11 +95,6 @@ export interface ViewportInterface {
|
|||
bottom: number,
|
||||
}
|
||||
|
||||
export interface BatchedMessageInterface {
|
||||
event: string,
|
||||
payload: unknown
|
||||
}
|
||||
|
||||
export interface ItemEventMessageInterface {
|
||||
itemId: number,
|
||||
event: string,
|
||||
|
|
|
@ -27,7 +27,7 @@ import {
|
|||
SendJitsiJwtMessage,
|
||||
CharacterLayerMessage,
|
||||
PingMessage,
|
||||
SendUserMessage
|
||||
SendUserMessage, BanUserMessage
|
||||
} from "../Messages/generated/messages_pb"
|
||||
|
||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||
|
@ -42,6 +42,8 @@ import {
|
|||
WebRtcSignalReceivedMessageInterface,
|
||||
} from "./ConnexionModels";
|
||||
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
|
||||
import {adminMessagesService} from "./AdminMessagesService";
|
||||
import {connectionManager, ConnexionMessageEventTypes} from "./ConnectionManager";
|
||||
|
||||
const manualPingDelay = 20000;
|
||||
|
||||
|
@ -100,7 +102,7 @@ export class RoomConnection implements RoomConnection {
|
|||
}
|
||||
|
||||
// If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry.
|
||||
if (this.userId === null) {
|
||||
if (this.userId === null && !this.closed) {
|
||||
this.dispatch(EventMessage.CONNECTING_ERROR, event);
|
||||
}
|
||||
});
|
||||
|
@ -140,8 +142,6 @@ export class RoomConnection implements RoomConnection {
|
|||
} else if (message.hasRoomjoinedmessage()) {
|
||||
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
|
||||
|
||||
//const users: Array<MessageUserJoined> = roomJoinedMessage.getUserList().map(this.toMessageUserJoined.bind(this));
|
||||
//const groups: Array<GroupCreatedUpdatedMessageInterface> = roomJoinedMessage.getGroupList().map(this.toGroupCreatedUpdatedMessage.bind(this));
|
||||
const items: { [itemId: number] : unknown } = {};
|
||||
for (const item of roomJoinedMessage.getItemList()) {
|
||||
items[item.getItemid()] = JSON.parse(item.getStatejson());
|
||||
|
@ -150,24 +150,15 @@ export class RoomConnection implements RoomConnection {
|
|||
this.userId = roomJoinedMessage.getCurrentuserid();
|
||||
this.tags = roomJoinedMessage.getTagList();
|
||||
|
||||
//console.log('Dispatching CONNECT')
|
||||
this.dispatch(EventMessage.CONNECT, {
|
||||
connection: this,
|
||||
room: {
|
||||
//users,
|
||||
//groups,
|
||||
items
|
||||
} as RoomJoinedMessageInterface
|
||||
});
|
||||
|
||||
/*console.log('Dispatching START_ROOM')
|
||||
this.dispatch(EventMessage.START_ROOM, {
|
||||
//users,
|
||||
//groups,
|
||||
items
|
||||
});*/
|
||||
} else if (message.hasErrormessage()) {
|
||||
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage());
|
||||
connectionManager._connexionMessageStream.next({type: ConnexionMessageEventTypes.worldFull}); //todo: generalize this behavior to all messages
|
||||
this.closed = true;
|
||||
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
||||
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
|
||||
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
|
||||
|
@ -185,9 +176,9 @@ export class RoomConnection implements RoomConnection {
|
|||
} else if (message.hasSendjitsijwtmessage()) {
|
||||
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
||||
} else if (message.hasSendusermessage()) {
|
||||
this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage());
|
||||
adminMessagesService.onSendusermessage(message.getSendusermessage() as SendUserMessage);
|
||||
} else if (message.hasBanusermessage()) {
|
||||
this.dispatch(EventMessage.USER_MESSAGE, message.getBanusermessage());
|
||||
adminMessagesService.onSendusermessage(message.getSendusermessage() as BanUserMessage);
|
||||
} else {
|
||||
throw new Error('Unknown message received');
|
||||
}
|
||||
|
@ -541,12 +532,6 @@ export class RoomConnection implements RoomConnection {
|
|||
});
|
||||
}
|
||||
|
||||
public receiveUserMessage(callback: (type: string, message: string) => void) {
|
||||
return this.onMessage(EventMessage.USER_MESSAGE, (message: SendUserMessage) => {
|
||||
callback(message.getType(), message.getMessage());
|
||||
});
|
||||
}
|
||||
|
||||
public emitGlobalMessage(message: PlayGlobalMessageInterface){
|
||||
const playGlobalMessage = new PlayGlobalMessage();
|
||||
playGlobalMessage.setId(message.id);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {PlayerAnimationNames} from "../Player/Animation";
|
||||
import {PlayerAnimationDirections, PlayerAnimationTypes} from "../Player/Animation";
|
||||
import {SpeechBubble} from "./SpeechBubble";
|
||||
import BitmapText = Phaser.GameObjects.BitmapText;
|
||||
import Container = Phaser.GameObjects.Container;
|
||||
|
@ -10,8 +10,7 @@ interface AnimationData {
|
|||
frameRate: number;
|
||||
repeat: number;
|
||||
frameModel: string; //todo use an enum
|
||||
frameStart: number;
|
||||
frameEnd: number;
|
||||
frames : number[]
|
||||
}
|
||||
|
||||
export abstract class Character extends Container {
|
||||
|
@ -19,7 +18,7 @@ export abstract class Character extends Container {
|
|||
private readonly playerName: BitmapText;
|
||||
public PlayerValue: string;
|
||||
public sprites: Map<string, Sprite>;
|
||||
private lastDirection: string = PlayerAnimationNames.WalkDown;
|
||||
private lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
||||
//private teleportation: Sprite;
|
||||
private invisible: boolean;
|
||||
|
||||
|
@ -28,7 +27,7 @@ export abstract class Character extends Container {
|
|||
y: number,
|
||||
texturesPromise: Promise<string[]>,
|
||||
name: string,
|
||||
direction: string,
|
||||
direction: PlayerAnimationDirections,
|
||||
moving: boolean,
|
||||
frame?: string | number
|
||||
) {
|
||||
|
@ -81,7 +80,7 @@ export abstract class Character extends Container {
|
|||
this.getPlayerAnimations(texture).forEach(d => {
|
||||
this.scene.anims.create({
|
||||
key: d.key,
|
||||
frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}),
|
||||
frames: this.scene.anims.generateFrameNumbers(d.frameModel, {frames: d.frames}),
|
||||
frameRate: d.frameRate,
|
||||
repeat: d.repeat
|
||||
});
|
||||
|
@ -96,37 +95,57 @@ export abstract class Character extends Container {
|
|||
|
||||
private getPlayerAnimations(name: string): AnimationData[] {
|
||||
return [{
|
||||
key: `${name}-${PlayerAnimationNames.WalkDown}`,
|
||||
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`,
|
||||
frameModel: name,
|
||||
frameStart: 0,
|
||||
frameEnd: 2,
|
||||
frames: [0, 1, 2, 1],
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
}, {
|
||||
key: `${name}-${PlayerAnimationNames.WalkLeft}`,
|
||||
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`,
|
||||
frameModel: name,
|
||||
frameStart: 3,
|
||||
frameEnd: 5,
|
||||
frames: [3, 4, 5, 4],
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
}, {
|
||||
key: `${name}-${PlayerAnimationNames.WalkRight}`,
|
||||
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`,
|
||||
frameModel: name,
|
||||
frameStart: 6,
|
||||
frameEnd: 8,
|
||||
frames: [6, 7, 8, 7],
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
}, {
|
||||
key: `${name}-${PlayerAnimationNames.WalkUp}`,
|
||||
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`,
|
||||
frameModel: name,
|
||||
frameStart: 9,
|
||||
frameEnd: 11,
|
||||
frames: [9, 10, 11, 10],
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
},{
|
||||
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`,
|
||||
frameModel: name,
|
||||
frames: [1],
|
||||
frameRate: 10,
|
||||
repeat: 1
|
||||
}, {
|
||||
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`,
|
||||
frameModel: name,
|
||||
frames: [4],
|
||||
frameRate: 10,
|
||||
repeat: 1
|
||||
}, {
|
||||
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`,
|
||||
frameModel: name,
|
||||
frames: [7],
|
||||
frameRate: 10,
|
||||
repeat: 1
|
||||
}, {
|
||||
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`,
|
||||
frameModel: name,
|
||||
frames: [10],
|
||||
frameRate: 10,
|
||||
repeat: 1
|
||||
}];
|
||||
}
|
||||
|
||||
protected playAnimation(direction : string, moving: boolean): void {
|
||||
protected playAnimation(direction : PlayerAnimationDirections, moving: boolean): void {
|
||||
if (this.invisible) return;
|
||||
for (const [texture, sprite] of this.sprites.entries()) {
|
||||
if (!sprite.anims) {
|
||||
|
@ -134,10 +153,9 @@ export abstract class Character extends Container {
|
|||
return;
|
||||
}
|
||||
if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) {
|
||||
sprite.play(texture+'-'+direction, true);
|
||||
sprite.play(texture+'-'+direction+'-'+PlayerAnimationTypes.Walk, true);
|
||||
} else if (!moving) {
|
||||
sprite.anims.play(texture + '-' + direction, true);
|
||||
sprite.anims.stop();
|
||||
sprite.anims.play(texture + '-' + direction + '-'+PlayerAnimationTypes.Idle, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,17 +175,17 @@ export abstract class Character extends Container {
|
|||
|
||||
// up or down animations are prioritized over left and right
|
||||
if (body.velocity.y < 0) { //moving up
|
||||
this.lastDirection = PlayerAnimationNames.WalkUp;
|
||||
this.playAnimation(PlayerAnimationNames.WalkUp, true);
|
||||
this.lastDirection = PlayerAnimationDirections.Up;
|
||||
this.playAnimation(PlayerAnimationDirections.Up, true);
|
||||
} else if (body.velocity.y > 0) { //moving down
|
||||
this.lastDirection = PlayerAnimationNames.WalkDown;
|
||||
this.playAnimation(PlayerAnimationNames.WalkDown, true);
|
||||
this.lastDirection = PlayerAnimationDirections.Down;
|
||||
this.playAnimation(PlayerAnimationDirections.Down, true);
|
||||
} else if (body.velocity.x > 0) { //moving right
|
||||
this.lastDirection = PlayerAnimationNames.WalkRight;
|
||||
this.playAnimation(PlayerAnimationNames.WalkRight, true);
|
||||
this.lastDirection = PlayerAnimationDirections.Right;
|
||||
this.playAnimation(PlayerAnimationDirections.Right, true);
|
||||
} else if (body.velocity.x < 0) { //moving left
|
||||
this.lastDirection = PlayerAnimationNames.WalkLeft;
|
||||
this.playAnimation(PlayerAnimationNames.WalkLeft, true);
|
||||
this.lastDirection = PlayerAnimationDirections.Left;
|
||||
this.playAnimation(PlayerAnimationDirections.Left, true);
|
||||
}
|
||||
|
||||
this.setDepth(this.y);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {GameScene} from "../Game/GameScene";
|
||||
import {PointInterface} from "../../Connexion/ConnexionModels";
|
||||
import {Character} from "../Entity/Character";
|
||||
import {PlayerAnimationDirections} from "../Player/Animation";
|
||||
|
||||
/**
|
||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||
|
@ -15,22 +16,17 @@ export class RemotePlayer extends Character {
|
|||
y: number,
|
||||
name: string,
|
||||
texturesPromise: Promise<string[]>,
|
||||
direction: string,
|
||||
direction: PlayerAnimationDirections,
|
||||
moving: boolean
|
||||
) {
|
||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1);
|
||||
|
||||
//set data
|
||||
this.userId = userId;
|
||||
|
||||
//todo: implement on click action
|
||||
/*this.playerName.setInteractive();
|
||||
this.playerName.on('pointerup', () => {
|
||||
});*/
|
||||
}
|
||||
|
||||
updatePosition(position: PointInterface): void {
|
||||
this.playAnimation(position.direction, position.moving);
|
||||
this.playAnimation(position.direction as PlayerAnimationDirections, position.moving);
|
||||
this.setX(position.x);
|
||||
this.setY(position.y);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import {GameScene} from "./GameScene";
|
|||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||
import {Room} from "../../Connexion/Room";
|
||||
import {MenuScene, MenuSceneName} from "../Menu/MenuScene";
|
||||
import {HelpCameraSettingsScene, HelpCameraSettingsSceneName} from "../Menu/HelpCameraSettingsScene";
|
||||
import {LoginSceneName} from "../Login/LoginScene";
|
||||
import {SelectCharacterSceneName} from "../Login/SelectCharacterScene";
|
||||
import {EnableCameraSceneName} from "../Login/EnableCameraScene";
|
||||
|
@ -78,6 +79,7 @@ export class GameManager {
|
|||
console.log('starting '+ (this.currentGameSceneName || this.startRoom.id))
|
||||
scenePlugin.start(this.currentGameSceneName || this.startRoom.id);
|
||||
scenePlugin.launch(MenuSceneName);
|
||||
scenePlugin.launch(HelpCameraSettingsSceneName);//700
|
||||
}
|
||||
|
||||
public gameSceneIsCreated(scene: GameScene) {
|
||||
|
|
|
@ -3,27 +3,17 @@ import {
|
|||
GroupCreatedUpdatedMessageInterface,
|
||||
MessageUserJoined,
|
||||
MessageUserMovedInterface,
|
||||
MessageUserPositionInterface, OnConnectInterface,
|
||||
MessageUserPositionInterface,
|
||||
OnConnectInterface,
|
||||
PointInterface,
|
||||
PositionInterface,
|
||||
RoomJoinedMessageInterface
|
||||
} from "../../Connexion/ConnexionModels";
|
||||
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
||||
import {
|
||||
DEBUG_MODE,
|
||||
JITSI_PRIVATE_MODE,
|
||||
POSITION_DELAY,
|
||||
RESOLUTION,
|
||||
ZOOM_LEVEL
|
||||
} from "../../Enum/EnvironmentVariable";
|
||||
import {
|
||||
ITiledMap,
|
||||
ITiledMapLayer,
|
||||
ITiledMapLayerProperty, ITiledMapObject,
|
||||
ITiledTileSet
|
||||
} from "../Map/ITiledMap";
|
||||
import {DEBUG_MODE, JITSI_PRIVATE_MODE, POSITION_DELAY, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
|
||||
import {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapObject, ITiledTileSet} from "../Map/ITiledMap";
|
||||
import {AddPlayerInterface} from "./AddPlayerInterface";
|
||||
import {PlayerAnimationNames} from "../Player/Animation";
|
||||
import {PlayerAnimationDirections} from "../Player/Animation";
|
||||
import {PlayerMovement} from "./PlayerMovement";
|
||||
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
|
||||
import {RemotePlayer} from "../Entity/RemotePlayer";
|
||||
|
@ -41,11 +31,6 @@ import {
|
|||
TRIGGER_WEBSITE_PROPERTIES,
|
||||
WEBSITE_MESSAGE_PROPERTIES
|
||||
} from "../../WebRtc/LayoutManager";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||
import GameObject = Phaser.GameObjects.GameObject;
|
||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||
import {GameMap} from "./GameMap";
|
||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||
|
@ -54,10 +39,10 @@ import {ActionableItem} from "../Items/ActionableItem";
|
|||
import {UserInputManager} from "../UserInput/UserInputManager";
|
||||
import {UserMovedMessage} from "../../Messages/generated/messages_pb";
|
||||
import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
|
||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||
import {connectionManager, ConnexionMessageEvent, ConnexionMessageEventTypes} from "../../Connexion/ConnectionManager";
|
||||
import {RoomConnection} from "../../Connexion/RoomConnection";
|
||||
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
|
||||
import {UserMessageManager} from "../../Administration/UserMessageManager";
|
||||
import {userMessageManager} from "../../Administration/UserMessageManager";
|
||||
import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMessageManager";
|
||||
import {ResizableScene} from "../Login/ResizableScene";
|
||||
import {Room} from "../../Connexion/Room";
|
||||
|
@ -72,7 +57,12 @@ import {TextureError} from "../../Exception/TextureError";
|
|||
import {addLoader} from "../Components/Loader";
|
||||
import {ErrorSceneName} from "../Reconnecting/ErrorScene";
|
||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||
import GameObject = Phaser.GameObjects.GameObject;
|
||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||
import {Subscription} from "rxjs";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface|null,
|
||||
|
@ -131,7 +121,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
public connection!: RoomConnection;
|
||||
private simplePeer!: SimplePeer;
|
||||
private GlobalMessageManager!: GlobalMessageManager;
|
||||
private UserMessageManager!: UserMessageManager;
|
||||
public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
|
||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
||||
private connectionAnswerPromiseResolve!: (value?: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>) => void;
|
||||
|
@ -159,11 +148,12 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
// The item that can be selected by pressing the space key.
|
||||
private outlinedItem: ActionableItem|null = null;
|
||||
public userInputManager!: UserInputManager;
|
||||
private isReconnecting: boolean = false;
|
||||
private isReconnecting: boolean|undefined = undefined;
|
||||
private startLayerName!: string | null;
|
||||
private openChatIcon!: OpenChatIcon;
|
||||
private playerName!: string;
|
||||
private characterLayers!: string[];
|
||||
private messageSubscription: Subscription|null = null;
|
||||
|
||||
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
|
||||
super({
|
||||
|
@ -295,25 +285,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
// import(/* webpackIgnore: true */ scriptUrl).then(result => {
|
||||
//
|
||||
// result.default.preload(this.load);
|
||||
//
|
||||
// this.load.start(); // Let's manually start the loader because the import might be over AFTER the loading ends.
|
||||
// this.load.on('complete', () => {
|
||||
// // FIXME: the factory might fail because the resources might not be loaded yet...
|
||||
// // We would need to add a loader ended event in addition to the createPromise
|
||||
// this.createPromise.then(() => {
|
||||
// result.default.create(this);
|
||||
//
|
||||
// for (let object of objectsOfType) {
|
||||
// // TODO: we should pass here a factory to create sprites (maybe?)
|
||||
// let objectSprite = result.default.factory(this, object);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,6 +303,8 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
gameManager.gameSceneIsCreated(this);
|
||||
urlManager.pushRoomIdToUrl(this.room);
|
||||
this.startLayerName = urlManager.getStartLayerNameFromUrl();
|
||||
|
||||
this.messageSubscription = connectionManager._connexionMessageStream.subscribe((event) => this.onConnexionMessage(event))
|
||||
|
||||
const playerName = gameManager.getPlayerName();
|
||||
if (!playerName) {
|
||||
|
@ -403,13 +376,13 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
this.scene.launch(ReconnectingSceneName);
|
||||
}, 0);
|
||||
} else if (this.connection === undefined) {
|
||||
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking
|
||||
// Let's wait 1 second before printing the "connecting" screen to avoid blinking
|
||||
setTimeout(() => {
|
||||
if (this.connection === undefined) {
|
||||
this.scene.sleep();
|
||||
this.scene.launch(ReconnectingSceneName);
|
||||
}
|
||||
}, 500);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
this.createPromiseResolve();
|
||||
|
@ -537,8 +510,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
// When connection is performed, let's connect SimplePeer
|
||||
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
|
||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
||||
this.UserMessageManager = new UserMessageManager(this.connection);
|
||||
this.UserMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
||||
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
||||
|
||||
const self = this;
|
||||
this.simplePeer.registerPeerConnectionListener({
|
||||
|
@ -572,11 +544,10 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
|
||||
//init user position and play trigger to check layers properties
|
||||
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
||||
|
||||
return this.connection;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//todo: into dedicated classes
|
||||
private initCirclesCanvas(): void {
|
||||
// Let's generate the circle for the group delimiter
|
||||
|
@ -610,30 +581,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
contextRed.stroke();
|
||||
this.circleRedTexture.refresh();
|
||||
}
|
||||
|
||||
private playAudio(url: string|number|boolean|undefined, loop=false): void {
|
||||
if (url === undefined) {
|
||||
audioManager.unloadAudio();
|
||||
} else {
|
||||
const audioPath = url as string;
|
||||
let realAudioPath = '';
|
||||
|
||||
if (audioPath.indexOf('://') > 0) {
|
||||
// remote file or stream
|
||||
realAudioPath = audioPath;
|
||||
} else {
|
||||
// local file, include it relative to map directory
|
||||
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||
realAudioPath = mapDirUrl + '/' + url;
|
||||
}
|
||||
|
||||
audioManager.loadAudio(realAudioPath);
|
||||
|
||||
if (loop) {
|
||||
audioManager.loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private safeParseJSONstring(jsonString: string|undefined, propertyName: string) {
|
||||
try {
|
||||
|
@ -657,7 +605,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
coWebsiteManager.closeCoWebsite();
|
||||
}else{
|
||||
const openWebsiteFunction = () => {
|
||||
coWebsiteManager.loadCoWebsite(newValue as string, allProps.get('openWebsitePolicy') as string | undefined);
|
||||
coWebsiteManager.loadCoWebsite(newValue as string, this.MapUrlFile, allProps.get('openWebsitePolicy') as string | undefined);
|
||||
layoutManager.removeActionButton('openWebsite', this.userInputManager);
|
||||
};
|
||||
|
||||
|
@ -715,15 +663,19 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
}
|
||||
});
|
||||
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => {
|
||||
this.playAudio(newValue);
|
||||
newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
|
||||
});
|
||||
|
||||
this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => {
|
||||
this.playAudio(newValue, true);
|
||||
newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private getMapDirUrl(): string {
|
||||
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||
}
|
||||
|
||||
private onMapExit(exitKey: string) {
|
||||
const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
|
||||
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
|
||||
|
@ -749,14 +701,11 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
// stop playing audio, close any open website, stop any open Jitsi
|
||||
coWebsiteManager.closeCoWebsite();
|
||||
this.stopJitsi();
|
||||
this.playAudio(undefined);
|
||||
audioManager.unloadAudio();
|
||||
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
||||
if(this.connection) {
|
||||
this.connection.closeConnection();
|
||||
}
|
||||
if(this.simplePeer) {
|
||||
this.simplePeer.unregister();
|
||||
}
|
||||
this.connection?.closeConnection();
|
||||
this.simplePeer?.unregister();
|
||||
this.messageSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private removeAllRemotePlayers(): void {
|
||||
|
@ -918,7 +867,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
this.startY,
|
||||
this.playerName,
|
||||
texturesPromise,
|
||||
PlayerAnimationNames.WalkDown,
|
||||
PlayerAnimationDirections.Down,
|
||||
false,
|
||||
this.userInputManager
|
||||
);
|
||||
|
@ -967,16 +916,16 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
let x = event.x;
|
||||
let y = event.y;
|
||||
switch (event.direction) {
|
||||
case PlayerAnimationNames.WalkUp:
|
||||
case PlayerAnimationDirections.Up:
|
||||
y -= 32;
|
||||
break;
|
||||
case PlayerAnimationNames.WalkDown:
|
||||
case PlayerAnimationDirections.Down:
|
||||
y += 32;
|
||||
break;
|
||||
case PlayerAnimationNames.WalkLeft:
|
||||
case PlayerAnimationDirections.Left:
|
||||
x -= 32;
|
||||
break;
|
||||
case PlayerAnimationNames.WalkRight:
|
||||
case PlayerAnimationDirections.Right:
|
||||
x += 32;
|
||||
break;
|
||||
default:
|
||||
|
@ -1047,13 +996,12 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's move all users
|
||||
const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
|
||||
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => {
|
||||
const player : RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
|
||||
const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
|
||||
if (player === undefined) {
|
||||
throw new Error('Cannot find player with ID "' + userId +'"');
|
||||
throw new Error('Cannot find player with ID "' + userId + '"');
|
||||
}
|
||||
player.updatePosition(moveEvent);
|
||||
});
|
||||
|
@ -1112,7 +1060,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
addPlayerData.position.y,
|
||||
addPlayerData.name,
|
||||
texturesPromise,
|
||||
addPlayerData.position.direction,
|
||||
addPlayerData.position.direction as PlayerAnimationDirections,
|
||||
addPlayerData.position.moving
|
||||
);
|
||||
this.MapPlayers.add(player);
|
||||
|
@ -1272,21 +1220,34 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||
}
|
||||
|
||||
public stopJitsi(): void {
|
||||
this.connection.setSilent(false);
|
||||
this.connection?.setSilent(false);
|
||||
jitsiFactory.stop();
|
||||
mediaManager.showGameOverlay();
|
||||
|
||||
mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi');
|
||||
}
|
||||
|
||||
//todo: into onConnexionMessage
|
||||
private bannedUser(){
|
||||
this.cleanupClosingScene();
|
||||
this.userInputManager.clearAllKeys();
|
||||
this.scene.start(ErrorSceneName, {
|
||||
title: 'Banned',
|
||||
subTitle: 'You was banned of WorkAdventure',
|
||||
message: 'If you want more information, you can contact us: workadventure@thecodingmachine.com'
|
||||
subTitle: 'You were banned from WorkAdventure',
|
||||
message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
|
||||
});
|
||||
}
|
||||
|
||||
private onConnexionMessage(event: ConnexionMessageEvent) {
|
||||
if (event.type === ConnexionMessageEventTypes.worldFull) {
|
||||
this.cleanupClosingScene();
|
||||
this.scene.stop(ReconnectingSceneName);
|
||||
this.userInputManager.clearAllKeys();
|
||||
this.scene.start(ErrorSceneName, {
|
||||
title: 'Connection rejected',
|
||||
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'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import {gameManager} from "../Game/GameManager";
|
||||
import {TextField} from "../Components/TextField";
|
||||
import Image = Phaser.GameObjects.Image;
|
||||
import {GameSceneInitInterface} from "../Game/GameScene";
|
||||
import {StartMapInterface} from "../../Connexion/ConnexionModels";
|
||||
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||
import {RESOLUTION} from "../../Enum/EnvironmentVariable";
|
||||
import {SoundMeter} from "../Components/SoundMeter";
|
||||
|
@ -18,6 +16,7 @@ enum LoginTextures {
|
|||
arrowUp = "arrow_up"
|
||||
}
|
||||
|
||||
|
||||
export class EnableCameraScene extends Phaser.Scene {
|
||||
private textField!: TextField;
|
||||
private pressReturnField!: TextField;
|
||||
|
|
93
front/src/Phaser/Menu/HelpCameraSettingsScene.ts
Normal file
93
front/src/Phaser/Menu/HelpCameraSettingsScene.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
|
||||
export const HelpCameraSettingsSceneName = 'HelpCameraSettingsScene';
|
||||
const helpCameraSettings = 'helpCameraSettings';
|
||||
/**
|
||||
* The scene that show how to permit Camera and Microphone access if there are not already allowed
|
||||
*/
|
||||
export class HelpCameraSettingsScene extends Phaser.Scene {
|
||||
private helpCameraSettingsElement!: Phaser.GameObjects.DOMElement;
|
||||
private helpCameraSettingsOpened: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super({key: HelpCameraSettingsSceneName});
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.html(helpCameraSettings, 'resources/html/helpCameraSettings.html');
|
||||
}
|
||||
|
||||
create(){
|
||||
this.createHelpCameraSettings();
|
||||
}
|
||||
|
||||
private createHelpCameraSettings() : void {
|
||||
const middleX = (window.innerWidth / 3) - (370*0.85);
|
||||
this.helpCameraSettingsElement = this.add.dom(middleX, -800, undefined, {overflow: 'scroll'}).createFromCache(helpCameraSettings);
|
||||
this.revealMenusAfterInit(this.helpCameraSettingsElement, helpCameraSettings);
|
||||
this.helpCameraSettingsElement.addListener('click');
|
||||
this.helpCameraSettingsElement.on('click', (event:MouseEvent) => {
|
||||
event.preventDefault();
|
||||
if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormRefresh') {
|
||||
window.location.reload();
|
||||
}else if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormContinue') {
|
||||
this.closeHelpCameraSettingsOpened();
|
||||
}
|
||||
});
|
||||
|
||||
if(!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video){
|
||||
this.openHelpCameraSettingsOpened();
|
||||
}
|
||||
}
|
||||
|
||||
private openHelpCameraSettingsOpened(): void{
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
|
||||
this.helpCameraSettingsOpened = true;
|
||||
let middleY = (window.innerHeight / 3) - (495);
|
||||
if(middleY < 0){
|
||||
middleY = 0;
|
||||
}
|
||||
let middleX = (window.innerWidth / 3) - (370*0.85);
|
||||
if(middleX < 0){
|
||||
middleX = 0;
|
||||
}
|
||||
if(window.navigator.userAgent.includes('Firefox')){
|
||||
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-firefox.png"/>';
|
||||
}else if(window.navigator.userAgent.includes('Chrome')){
|
||||
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-chrome.png"/>';
|
||||
}
|
||||
this.tweens.add({
|
||||
targets: this.helpCameraSettingsElement,
|
||||
y: middleY,
|
||||
x: middleX,
|
||||
duration: 1000,
|
||||
ease: 'Power3',
|
||||
overflow: 'scroll'
|
||||
});
|
||||
}
|
||||
|
||||
private closeHelpCameraSettingsOpened(): void{
|
||||
const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement;
|
||||
helpCameraSettingsInfo.innerText = '';
|
||||
helpCameraSettingsInfo.style.display = 'none';
|
||||
this.helpCameraSettingsOpened = false;
|
||||
this.tweens.add({
|
||||
targets: this.helpCameraSettingsElement,
|
||||
y: -400,
|
||||
duration: 1000,
|
||||
ease: 'Power3',
|
||||
overflow: 'scroll'
|
||||
});
|
||||
}
|
||||
|
||||
private revealMenusAfterInit(menuElement: Phaser.GameObjects.DOMElement, rootDomId: string) {
|
||||
//Dom elements will appear inside the viewer screen when creating before being moved out of it, which create a flicker effect.
|
||||
//To prevent this, we put a 'hidden' attribute on the root element, we remove it only after the init is done.
|
||||
setTimeout(() => {
|
||||
(menuElement.getChildByID(rootDomId) as HTMLElement).hidden = false;
|
||||
}, 250);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
|
||||
export enum PlayerAnimationNames {
|
||||
WalkDown = 'down',
|
||||
WalkLeft = 'left',
|
||||
WalkUp = 'up',
|
||||
WalkRight = 'right',
|
||||
export enum PlayerAnimationDirections {
|
||||
Down = 'down',
|
||||
Left = 'left',
|
||||
Up = 'up',
|
||||
Right = 'right',
|
||||
}
|
||||
export enum PlayerAnimationTypes {
|
||||
Walk = 'walk',
|
||||
Idle = 'idle',
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {PlayerAnimationNames} from "./Animation";
|
||||
import {PlayerAnimationDirections} from "./Animation";
|
||||
import {GameScene} from "../Game/GameScene";
|
||||
import {UserInputEvent, UserInputManager} from "../UserInput/UserInputManager";
|
||||
import {Character} from "../Entity/Character";
|
||||
|
@ -11,7 +11,7 @@ export interface CurrentGamerInterface extends Character{
|
|||
}
|
||||
|
||||
export class Player extends Character implements CurrentGamerInterface {
|
||||
private previousDirection: string = PlayerAnimationNames.WalkDown;
|
||||
private previousDirection: string = PlayerAnimationDirections.Down;
|
||||
private wasMoving: boolean = false;
|
||||
|
||||
constructor(
|
||||
|
@ -20,7 +20,7 @@ export class Player extends Character implements CurrentGamerInterface {
|
|||
y: number,
|
||||
name: string,
|
||||
texturesPromise: Promise<string[]>,
|
||||
direction: string,
|
||||
direction: PlayerAnimationDirections,
|
||||
moving: boolean,
|
||||
private userInputManager: UserInputManager
|
||||
) {
|
||||
|
@ -43,20 +43,20 @@ export class Player extends Character implements CurrentGamerInterface {
|
|||
let y = 0;
|
||||
if (activeEvents.get(UserInputEvent.MoveUp)) {
|
||||
y = - moveAmount;
|
||||
direction = PlayerAnimationNames.WalkUp;
|
||||
direction = PlayerAnimationDirections.Up;
|
||||
moving = true;
|
||||
} else if (activeEvents.get(UserInputEvent.MoveDown)) {
|
||||
y = moveAmount;
|
||||
direction = PlayerAnimationNames.WalkDown;
|
||||
direction = PlayerAnimationDirections.Down;
|
||||
moving = true;
|
||||
}
|
||||
if (activeEvents.get(UserInputEvent.MoveLeft)) {
|
||||
x = -moveAmount;
|
||||
direction = PlayerAnimationNames.WalkLeft;
|
||||
direction = PlayerAnimationDirections.Left;
|
||||
moving = true;
|
||||
} else if (activeEvents.get(UserInputEvent.MoveRight)) {
|
||||
x = moveAmount;
|
||||
direction = PlayerAnimationNames.WalkRight;
|
||||
direction = PlayerAnimationDirections.Right;
|
||||
moving = true;
|
||||
}
|
||||
if (x !== 0 || y !== 0) {
|
||||
|
|
|
@ -38,6 +38,25 @@ class AudioManager {
|
|||
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume;
|
||||
}
|
||||
|
||||
public playAudio(url: string|number|boolean, mapDirUrl: string, loop=false): void {
|
||||
const audioPath = url as string;
|
||||
let realAudioPath = '';
|
||||
|
||||
if (audioPath.indexOf('://') > 0) {
|
||||
// remote file or stream
|
||||
realAudioPath = audioPath;
|
||||
} else {
|
||||
// local file, include it relative to map directory
|
||||
realAudioPath = mapDirUrl + '/' + url;
|
||||
}
|
||||
|
||||
this.loadAudio(realAudioPath);
|
||||
|
||||
if (loop) {
|
||||
this.loop();
|
||||
}
|
||||
}
|
||||
|
||||
private close(): void {
|
||||
this.audioPlayerCtrl.classList.remove('loading');
|
||||
this.audioPlayerCtrl.classList.add('hidden');
|
||||
|
@ -75,7 +94,7 @@ class AudioManager {
|
|||
}
|
||||
|
||||
|
||||
public loadAudio(url: string): void {
|
||||
private loadAudio(url: string): void {
|
||||
this.load();
|
||||
|
||||
/* Solution 1, remove whole audio player */
|
||||
|
@ -125,7 +144,7 @@ class AudioManager {
|
|||
this.open();
|
||||
}
|
||||
|
||||
public loop(): void {
|
||||
private loop(): void {
|
||||
if (this.audioPlayerElem !== undefined) {
|
||||
this.audioPlayerElem.loop = true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {HtmlUtils} from "./HtmlUtils";
|
||||
|
||||
export type CoWebsiteStateChangedCallback = () => void;
|
||||
import {Subject} from "rxjs";
|
||||
|
||||
enum iframeStates {
|
||||
closed = 1,
|
||||
|
@ -8,29 +7,96 @@ enum iframeStates {
|
|||
opened,
|
||||
}
|
||||
|
||||
const cowebsiteDivId = "cowebsite"; // the id of the parent div of the iframe.
|
||||
const cowebsiteDivId = 'cowebsite'; // the id of the whole container.
|
||||
const cowebsiteMainDomId = 'cowebsite-main'; // the id of the parent div of the iframe.
|
||||
const cowebsiteAsideDomId = 'cowebsite-aside'; // the id of the parent div of the iframe.
|
||||
const cowebsiteCloseButtonId = 'cowebsite-close';
|
||||
const cowebsiteFullScreenButtonId = 'cowebsite-fullscreen';
|
||||
const cowebsiteOpenFullScreenImageId = 'cowebsite-fullscreen-open';
|
||||
const cowebsiteCloseFullScreenImageId = 'cowebsite-fullscreen-close';
|
||||
const animationTime = 500; //time used by the css transitions, in ms.
|
||||
|
||||
class CoWebsiteManager {
|
||||
|
||||
private opened: iframeStates = iframeStates.closed;
|
||||
|
||||
private observers = new Array<CoWebsiteStateChangedCallback>();
|
||||
private _onResize: Subject<void> = new Subject();
|
||||
public onResize = this._onResize.asObservable();
|
||||
/**
|
||||
* Quickly going in and out of an iframe trigger can create conflicts between the iframe states.
|
||||
* So we use this promise to queue up every cowebsite state transition
|
||||
*/
|
||||
private currentOperationPromise: Promise<void> = Promise.resolve();
|
||||
private cowebsiteDiv: HTMLDivElement;
|
||||
private resizing: boolean = false;
|
||||
private cowebsiteMainDom: HTMLDivElement;
|
||||
private cowebsiteAsideDom: HTMLDivElement;
|
||||
|
||||
get width(): number {
|
||||
return this.cowebsiteDiv.clientWidth;
|
||||
}
|
||||
|
||||
set width(width: number) {
|
||||
this.cowebsiteDiv.style.width = width+'px';
|
||||
}
|
||||
|
||||
get height(): number {
|
||||
return this.cowebsiteDiv.clientHeight;
|
||||
}
|
||||
|
||||
set height(height: number) {
|
||||
this.cowebsiteDiv.style.height = height+'px';
|
||||
}
|
||||
|
||||
get verticalMode(): boolean {
|
||||
return window.innerWidth < window.innerHeight;
|
||||
}
|
||||
|
||||
get isFullScreen(): boolean {
|
||||
return this.verticalMode ? this.height === this.cowebsiteDiv.clientHeight : this.width === this.cowebsiteDiv.clientWidth
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||
this.cowebsiteMainDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteMainDomId);
|
||||
this.cowebsiteAsideDom = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteAsideDomId);
|
||||
|
||||
this.initResizeListeners();
|
||||
|
||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId).addEventListener('click', () => {
|
||||
this.closeCoWebsite();
|
||||
});
|
||||
HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId).addEventListener('click', () => {
|
||||
this.fullscreen();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private initResizeListeners() {
|
||||
const movecallback = (event:MouseEvent) => {
|
||||
this.verticalMode ? this.height -= event.movementY : this.width -= event.movementX;
|
||||
this.fire();
|
||||
}
|
||||
|
||||
this.cowebsiteAsideDom.addEventListener('mousedown', (event) => {
|
||||
this.resizing = true;
|
||||
this.getIframeDom().style.display = 'none';
|
||||
|
||||
document.addEventListener('mousemove', movecallback);
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', (event) => {
|
||||
if (!this.resizing) return;
|
||||
document.removeEventListener('mousemove', movecallback);
|
||||
this.getIframeDom().style.display = 'block';
|
||||
this.resizing = false;
|
||||
});
|
||||
}
|
||||
|
||||
private close(): void {
|
||||
this.cowebsiteDiv.classList.remove('loaded'); //edit the css class to trigger the transition
|
||||
this.cowebsiteDiv.classList.add('hidden');
|
||||
this.opened = iframeStates.closed;
|
||||
this.resetStyle();
|
||||
}
|
||||
private load(): void {
|
||||
this.cowebsiteDiv.classList.remove('hidden'); //edit the css class to trigger the transition
|
||||
|
@ -40,29 +106,34 @@ class CoWebsiteManager {
|
|||
private open(): void {
|
||||
this.cowebsiteDiv.classList.remove('loading', 'hidden'); //edit the css class to trigger the transition
|
||||
this.opened = iframeStates.opened;
|
||||
this.resetStyle();
|
||||
}
|
||||
|
||||
public loadCoWebsite(url: string, allowPolicy?: string): void {
|
||||
public resetStyle() {
|
||||
this.cowebsiteDiv.style.width = '';
|
||||
this.cowebsiteDiv.style.height = '';
|
||||
}
|
||||
|
||||
private getIframeDom(): HTMLIFrameElement {
|
||||
const iframe = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId).querySelector('iframe');
|
||||
if (!iframe) throw new Error('Could not find iframe!');
|
||||
return iframe;
|
||||
}
|
||||
|
||||
public loadCoWebsite(url: string, base: string, allowPolicy?: string): void {
|
||||
this.load();
|
||||
this.cowebsiteDiv.innerHTML = `<button class="close-btn" id="cowebsite-close">
|
||||
<img src="resources/logos/close.svg">
|
||||
</button>`;
|
||||
setTimeout(() => {
|
||||
HtmlUtils.getElementByIdOrFail('cowebsite-close').addEventListener('click', () => {
|
||||
this.closeCoWebsite();
|
||||
});
|
||||
}, 100);
|
||||
this.cowebsiteMainDom.innerHTML = ``;
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.id = 'cowebsite-iframe';
|
||||
iframe.src = url;
|
||||
iframe.src = (new URL(url, base)).toString();
|
||||
if (allowPolicy) {
|
||||
iframe.allow = allowPolicy;
|
||||
}
|
||||
const onloadPromise = new Promise((resolve) => {
|
||||
iframe.onload = () => resolve();
|
||||
});
|
||||
this.cowebsiteDiv.appendChild(iframe);
|
||||
this.cowebsiteMainDom.appendChild(iframe);
|
||||
const onTimeoutPromise = new Promise((resolve) => {
|
||||
setTimeout(() => resolve(), 2000);
|
||||
});
|
||||
|
@ -79,7 +150,8 @@ class CoWebsiteManager {
|
|||
*/
|
||||
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void {
|
||||
this.load();
|
||||
this.currentOperationPromise = this.currentOperationPromise.then(() => callback(this.cowebsiteDiv)).then(() => {
|
||||
this.cowebsiteMainDom.innerHTML = ``;
|
||||
this.currentOperationPromise = this.currentOperationPromise.then(() => callback(this.cowebsiteMainDom)).then(() => {
|
||||
this.open();
|
||||
setTimeout(() => {
|
||||
this.fire();
|
||||
|
@ -93,9 +165,7 @@ class CoWebsiteManager {
|
|||
this.close();
|
||||
this.fire();
|
||||
setTimeout(() => {
|
||||
this.cowebsiteDiv.innerHTML = `<button class="close-btn" id="cowebsite-close">
|
||||
<img src="resources/logos/close.svg">
|
||||
</button>`;
|
||||
this.cowebsiteMainDom.innerHTML = ``;
|
||||
resolve();
|
||||
}, animationTime)
|
||||
}));
|
||||
|
@ -109,29 +179,36 @@ class CoWebsiteManager {
|
|||
height: window.innerHeight
|
||||
}
|
||||
}
|
||||
if (window.innerWidth >= window.innerHeight) {
|
||||
if (!this.verticalMode) {
|
||||
return {
|
||||
width: window.innerWidth / 2,
|
||||
width: window.innerWidth - this.width,
|
||||
height: window.innerHeight
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight / 2
|
||||
height: window.innerHeight - this.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//todo: is it still useful to allow any kind of observers?
|
||||
public onStateChange(observer: CoWebsiteStateChangedCallback) {
|
||||
this.observers.push(observer);
|
||||
}
|
||||
|
||||
|
||||
private fire(): void {
|
||||
for (const callback of this.observers) {
|
||||
callback();
|
||||
this._onResize.next();
|
||||
}
|
||||
|
||||
private fullscreen(): void {
|
||||
if (this.isFullScreen) {
|
||||
this.resetStyle();
|
||||
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'inline';
|
||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'none';
|
||||
} else {
|
||||
this.verticalMode ? this.height = window.innerHeight : this.width = window.innerWidth;
|
||||
//we don't trigger a resize of the phaser game since it won't be visible anyway.
|
||||
HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId).style.display = 'none';
|
||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId).style.display = 'inline';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const coWebsiteManager = new CoWebsiteManager();
|
||||
export const coWebsiteManager = new CoWebsiteManager();
|
||||
|
|
|
@ -192,7 +192,7 @@ class LayoutManager {
|
|||
} else {
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('sidebar').style.display = 'none';
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-section').style.display = 'none';
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('chat-mode').style.display = 'flex';
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('chat-mode').style.display = 'grid';
|
||||
}
|
||||
|
||||
for (const div of this.importantDivs.values()) {
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import 'phaser';
|
||||
import GameConfig = Phaser.Types.Core.GameConfig;
|
||||
import "../dist/resources/style/index.scss";
|
||||
|
||||
import {DEBUG_MODE, JITSI_URL, RESOLUTION} from "./Enum/EnvironmentVariable";
|
||||
import {LoginScene} from "./Phaser/Login/LoginScene";
|
||||
import {ReconnectingScene} from "./Phaser/Reconnecting/ReconnectingScene";
|
||||
import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene";
|
||||
import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene";
|
||||
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
||||
import {OutlinePipeline} from "./Phaser/Shaders/OutlinePipeline";
|
||||
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
||||
import {ResizableScene} from "./Phaser/Login/ResizableScene";
|
||||
import {EntryScene} from "./Phaser/Login/EntryScene";
|
||||
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
||||
import {MenuScene} from "./Phaser/Menu/MenuScene";
|
||||
import {HelpCameraSettingsScene} from "./Phaser/Menu/HelpCameraSettingsScene";
|
||||
import {localUserStore} from "./Connexion/LocalUserStore";
|
||||
import {ErrorScene} from "./Phaser/Reconnecting/ErrorScene";
|
||||
|
||||
|
@ -71,7 +72,7 @@ const config: GameConfig = {
|
|||
width: width / RESOLUTION,
|
||||
height: height / RESOLUTION,
|
||||
parent: "game",
|
||||
scene: [EntryScene, LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, ErrorScene, CustomizeScene, MenuScene],
|
||||
scene: [EntryScene, LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, ErrorScene, CustomizeScene, MenuScene, HelpCameraSettingsScene],
|
||||
zoom: RESOLUTION,
|
||||
fps: fps,
|
||||
dom: {
|
||||
|
@ -102,6 +103,7 @@ const config: GameConfig = {
|
|||
const game = new Phaser.Game(config);
|
||||
|
||||
window.addEventListener('resize', function (event) {
|
||||
coWebsiteManager.resetStyle();
|
||||
const {width, height} = coWebsiteManager.getGameSize();
|
||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||
|
||||
|
@ -113,7 +115,7 @@ window.addEventListener('resize', function (event) {
|
|||
}
|
||||
});
|
||||
|
||||
coWebsiteManager.onStateChange(() => {
|
||||
coWebsiteManager.onResize.subscribe(() => {
|
||||
const {width, height} = coWebsiteManager.getGameSize();
|
||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue