Refactoring connection to be part of a GameScene

Most of the refactoring issues we are seeing are probably due to the fact that we are trying to manipulate a ScenePlugin out of a Scene (the GameManager is not a Scene and holds a reference to a ScenePlugin coming from a Scene that might get invalidated by Phaser 3).
Furthermore, if we want in the future to be able to scale, scenes could be hosted on different servers. Therefore, it makes no sense to have one connexion for the whole application.
Instead, we should have one connexion for each scene.
This commit is contained in:
David Négrier 2020-06-22 11:58:07 +02:00
parent 593e0dc642
commit d785a8a1bf
5 changed files with 157 additions and 202 deletions

View file

@ -1,6 +1,7 @@
import {GameManager, gameManager, HasMovedEvent} from "./GameManager";
import {
GroupCreatedUpdatedMessageInterface,
Connection,
GroupCreatedUpdatedMessageInterface, MessageUserJoined,
MessageUserMovedInterface,
MessageUserPositionInterface, PointInterface, PositionInterface
} from "../../Connection";
@ -23,6 +24,7 @@ import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
import {RemotePlayer} from "../Entity/RemotePlayer";
import GameObject = Phaser.GameObjects.GameObject;
import { Queue } from 'queue-typescript';
import {SimplePeer} from "../../WebRtc/SimplePeer";
export enum Textures {
@ -81,6 +83,9 @@ export class GameScene extends Phaser.Scene {
pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>();
private initPosition: PositionInterface|null = null;
private playersPositionInterpolator = new PlayersPositionInterpolator();
private connection: Connection;
private simplePeer : SimplePeer;
private connectionPromise: Promise<Connection>
MapKey: string;
MapUrlFile: string;
@ -99,8 +104,10 @@ export class GameScene extends Phaser.Scene {
private PositionNextScene: Array<Array<{ key: string, hash: string }>> = new Array<Array<{ key: string, hash: string }>>();
private startLayerName: string|undefined;
static createFromUrl(mapUrlFile: string, instance: string): GameScene {
const key = GameScene.getMapKeyByUrl(mapUrlFile);
static createFromUrl(mapUrlFile: string, instance: string, key: string|null = null): GameScene {
if (key === null) {
key = GameScene.getMapKeyByUrl(mapUrlFile);
}
return new GameScene(key, mapUrlFile, instance);
}
@ -117,6 +124,7 @@ export class GameScene extends Phaser.Scene {
this.MapKey = MapKey;
this.MapUrlFile = MapUrlFile;
this.RoomId = this.instance + '__' + this.MapKey;
}
//hook preload scene
@ -144,6 +152,49 @@ export class GameScene extends Phaser.Scene {
});
this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
this.connectionPromise = Connection.createConnection(gameManager.getPlayerName(), gameManager.getCharacterSelected()).then((connection : Connection) => {
this.connection = connection;
connection.onUserJoins((message: MessageUserJoined) => {
const userMessage: AddPlayerInterface = {
userId: message.userId,
character: message.character,
name: message.name,
position: message.position
}
this.addPlayer(userMessage);
});
connection.onUserMoved((message: MessageUserMovedInterface) => {
this.updatePlayerPosition(message);
});
connection.onUserLeft((userId: string) => {
this.removePlayer(userId);
});
connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
})
connection.onGroupDeleted((groupId: string) => {
try {
this.deleteGroup(groupId);
} catch (e) {
console.error(e);
}
})
// When connection is performed, let's connect SimplePeer
this.simplePeer = new SimplePeer(this.connection);
if (this.scene.isPaused()) {
this.scene.resume();
}
return connection;
});
}
// FIXME: we need to put a "unknown" instead of a "any" and validate the structure of the JSON we are receiving.
@ -272,6 +323,11 @@ export class GameScene extends Phaser.Scene {
path += '#'+this.startLayerName;
}
window.history.pushState({}, 'WorkAdventure', path);
// Let's pause the scene if the connection is not established yet
if (this.connection === undefined) {
this.scene.pause();
}
}
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
@ -430,10 +486,14 @@ export class GameScene extends Phaser.Scene {
this.createCollisionObject();
//join room
this.GameManager.joinRoom(this.RoomId, this.startX, this.startY, PlayerAnimationNames.WalkDown, false);
this.connectionPromise.then((connection: Connection) => {
connection.joinARoom(this.RoomId, this.startX, this.startY, PlayerAnimationNames.WalkDown, false).then((userPositions: MessageUserPositionInterface[]) => {
this.initUsersPosition(userPositions);
});
//listen event to share position of user
this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this))
//listen event to share position of user
this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this))
});
}
pushPlayerPosition(event: HasMovedEvent) {
@ -465,7 +525,7 @@ export class GameScene extends Phaser.Scene {
private doPushPlayerPosition(event: HasMovedEvent): void {
this.lastMoveEventSent = event;
this.lastSentTick = this.currentTick;
this.GameManager.pushPlayerPosition(event);
this.connection.sharePosition(event.x, event.y, event.direction, event.moving);
}
EventToClickOnTile(){
@ -525,6 +585,8 @@ export class GameScene extends Phaser.Scene {
const nextSceneKey = this.checkToExit();
if(nextSceneKey){
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
this.connection.closeConnection();
this.scene.stop();
this.scene.remove(this.scene.key);
this.scene.start(nextSceneKey.key, {
startLayerName: nextSceneKey.hash
@ -549,7 +611,7 @@ export class GameScene extends Phaser.Scene {
/**
* Called by the connexion when the full list of user position is received.
*/
public initUsersPosition(usersPosition: MessageUserPositionInterface[]): void {
private initUsersPosition(usersPosition: MessageUserPositionInterface[]): void {
this.pendingEvents.enqueue({
type: "InitUserPositionEvent",
event: usersPosition
@ -561,7 +623,7 @@ export class GameScene extends Phaser.Scene {
* Put all the players on the map on map load.
*/
private doInitUsersPosition(usersPosition: MessageUserPositionInterface[]): void {
const currentPlayerId = this.GameManager.getPlayerId();
const currentPlayerId = this.connection.userId;
// clean map
this.MapPlayersByKey.forEach((player: RemotePlayer) => {