FIX: rewrote the way scene exits are triggered

This commit is contained in:
kharhamel 2020-11-18 18:15:57 +01:00
parent c5af6df7fa
commit 09d6d22a5d
6 changed files with 135 additions and 129 deletions

View file

@ -59,6 +59,7 @@ import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMes
import {ResizableScene} from "../Login/ResizableScene";
import {Room} from "../../Connexion/Room";
import {jitsiFactory} from "../../WebRtc/JitsiFactory";
import {urlManager} from "../../Url/UrlManager";
export interface GameSceneInitInterface {
initPosition: PointInterface|null
@ -123,7 +124,6 @@ export class GameScene extends ResizableScene implements CenterListener {
private createPromise: Promise<void>;
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
MapKey: string;
MapUrlFile: string;
RoomId: string;
instance: string;
@ -137,7 +137,6 @@ export class GameScene extends ResizableScene implements CenterListener {
y: -1000
}
private PositionNextScene: Array<Array<{ key: string, hash: string }>> = new Array<Array<{ key: string, hash: string }>>();
private presentationModeSprite!: Sprite;
private chatModeSprite!: Sprite;
private gameMap!: GameMap;
@ -146,17 +145,14 @@ export class GameScene extends ResizableScene implements CenterListener {
private outlinedItem: ActionableItem|null = null;
private userInputManager!: UserInputManager;
static createFromUrl(room: Room, mapUrlFile: string, gameSceneKey: string|null = null): GameScene {
static createFromUrl(room: Room, mapUrlFile: string): GameScene {
// We use the map URL as a key
if (gameSceneKey === null) {
gameSceneKey = mapUrlFile;
}
return new GameScene(room, mapUrlFile, gameSceneKey);
return new GameScene(room, mapUrlFile);
}
constructor(private room: Room, MapUrlFile: string, gameSceneKey: string) {
constructor(private room: Room, MapUrlFile: string) {
super({
key: gameSceneKey
key: room.id
});
this.GameManager = gameManager;
@ -164,7 +160,6 @@ export class GameScene extends ResizableScene implements CenterListener {
this.groups = new Map<number, Sprite>();
this.instance = room.getInstance();
this.MapKey = MapUrlFile;
this.MapUrlFile = MapUrlFile;
this.RoomId = room.id;
@ -183,15 +178,15 @@ export class GameScene extends ResizableScene implements CenterListener {
file: file.src
});
});
this.load.on('filecomplete-tilemapJSON-'+this.MapKey, (key: string, type: string, data: unknown) => {
this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => {
this.onMapLoad(data);
});
//TODO strategy to add access token
this.load.tilemapTiledJSON(this.MapKey, this.MapUrlFile);
this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile);
// If the map has already been loaded as part of another GameScene, the "on load" event will not be triggered.
// In this case, we check in the cache to see if the map is here and trigger the event manually.
if (this.cache.tilemap.exists(this.MapKey)) {
const data = this.cache.tilemap.get(this.MapKey);
if (this.cache.tilemap.exists(this.MapUrlFile)) {
const data = this.cache.tilemap.get(this.MapUrlFile);
this.onMapLoad(data);
}
@ -302,14 +297,16 @@ export class GameScene extends ResizableScene implements CenterListener {
//hook initialisation
init(initData : GameSceneInitInterface) {
if (initData.initPosition !== undefined) {
this.initPosition = initData.initPosition;
this.initPosition = initData.initPosition; //todo: still used?
}
}
//hook create scene
create(): void {
urlManager.editUrlForCurrentRoom(this.room);
//initalise map
this.Map = this.add.tilemap(this.MapKey);
this.Map = this.add.tilemap(this.MapUrlFile);
this.gameMap = new GameMap(this.mapFile);
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
this.mapFile.tilesets.forEach((tileset: ITiledTileSet) => {
@ -319,25 +316,21 @@ export class GameScene extends ResizableScene implements CenterListener {
//permit to set bound collision
this.physics.world.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels);
// Let's alter browser history
let path = this.room.id;
if (this.room.hash) {
path += '#' + this.room.hash;
}
window.history.pushState({}, 'WorkAdventure', path);
//add layer on map
this.Layers = new Array<Phaser.Tilemaps.StaticTilemapLayer>();
let depth = -2;
for (const layer of this.mapFile.layers) {
if (layer.type === 'tilelayer') {
this.addLayer(this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
}
if (layer.type === 'tilelayer' && this.getExitSceneUrl(layer) !== undefined) {
this.loadNextGameFromExitSceneUrl(layer, this.mapFile.width);
} else if (layer.type === 'tilelayer' && this.getExitUrl(layer) !== undefined) {
console.log('Loading exitUrl ', this.getExitUrl(layer))
this.loadNextGameFromExitUrl(layer, this.mapFile.width);
const exitSceneUrl = this.getExitSceneUrl(layer);
if (exitSceneUrl !== undefined) {
this.loadNextGame(exitSceneUrl);
}
const exitUrl = this.getExitUrl(layer);
if (exitUrl !== undefined) {
this.loadNextGame(exitUrl);
}
}
if (layer.type === 'objectgroup' && layer.name === 'floorLayer') {
depth = 10000;
@ -482,7 +475,6 @@ export class GameScene extends ResizableScene implements CenterListener {
if (position === undefined) {
throw new Error('Position missing from UserMovedMessage');
}
//console.log('Received position ', position.getX(), position.getY(), "from user", message.getUserid());
const messageUserMoved: MessageUserMovedInterface = {
userId: message.getUserid(),
@ -515,7 +507,7 @@ export class GameScene extends ResizableScene implements CenterListener {
this.simplePeer.unregister();
const gameSceneKey = 'somekey' + Math.round(Math.random() * 10000);
const game: Phaser.Scene = GameScene.createFromUrl(this.room, this.MapUrlFile, gameSceneKey);
const game: Phaser.Scene = GameScene.createFromUrl(this.room, this.MapUrlFile);
this.scene.add(gameSceneKey, game, true,
{
initPosition: {
@ -581,6 +573,12 @@ export class GameScene extends ResizableScene implements CenterListener {
}
private triggerOnMapLayerPropertyChange(){
this.gameMap.onPropertyChange('exitSceneUrl', (newValue, oldValue) => {
if (newValue) this.onMapExit(newValue as string);
});
this.gameMap.onPropertyChange('exitUrl', (newValue, oldValue) => {
if (newValue) this.onMapExit(newValue as string);
});
this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue, allProps) => {
if (newValue === undefined) {
layoutManager.removeActionButton('openWebsite', this.userInputManager);
@ -635,6 +633,25 @@ export class GameScene extends ResizableScene implements CenterListener {
}
});
}
private onMapExit(exitKey: string) {
const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
//todo: push the hash into the url
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
if (roomId !== this.scene.key) {
// 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.simplePeer.unregister();
this.scene.stop();
this.scene.remove(this.scene.key);
this.scene.start(roomId, {hash});
} else {
//if the exit points to the current map, we simply teleport the user back to the startLayer
this.initPositionFromLayerName(this.room.hash || 'start');
this.CurrentPlayer.x = this.startX;
this.CurrentPlayer.y = this.startY;
}
}
private switchLayoutMode(): void {
//if discussion is activated, this layout cannot be activated
@ -691,14 +708,13 @@ export class GameScene extends ResizableScene implements CenterListener {
return this.getProperty(layer, "exitUrl") as string|undefined;
}
/**
* @deprecated the map property exitSceneUrl is deprecated
*/
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
return this.getProperty(layer, "exitSceneUrl") as string|undefined;
}
private getExitSceneInstance(layer: ITiledMapLayer): string|undefined {
return this.getProperty(layer, "exitInstance") as string|undefined;
}
private isStartLayer(layer: ITiledMapLayer): boolean {
return this.getProperty(layer, "startLayer") == true;
}
@ -715,66 +731,11 @@ export class GameScene extends ResizableScene implements CenterListener {
return obj.value;
}
private loadNextGameFromExitSceneUrl(layer: ITiledMapLayer, mapWidth: number) {
const exitSceneUrl = this.getExitSceneUrl(layer);
if (exitSceneUrl === undefined) {
throw new Error('Layer is not an exit scene layer.');
}
let instance = this.getExitSceneInstance(layer);
if (instance === undefined) {
instance = this.instance;
}
const absoluteExitSceneUrl = new URL(exitSceneUrl, this.MapUrlFile).href;
const absoluteExitSceneUrlWithoutProtocol = absoluteExitSceneUrl.toString().substr(absoluteExitSceneUrl.toString().indexOf('://')+3);
const roomId = '_/'+instance+'/'+absoluteExitSceneUrlWithoutProtocol;
this.loadNextGame(layer, mapWidth, roomId);
}
private loadNextGameFromExitUrl(layer: ITiledMapLayer, mapWidth: number) {
const exitUrl = this.getExitUrl(layer);
if (exitUrl === undefined) {
throw new Error('Layer is not an exit layer.');
}
const fullPath = new URL(exitUrl, window.location.toString()).pathname;
this.loadNextGame(layer, mapWidth, fullPath);
}
//todo: push that into the gameManager
private loadNextGame(layer: ITiledMapLayer, mapWidth: number, roomId: string){
private async loadNextGame(exitSceneIdentifier: string){
const {roomId, hash} = Room.getIdFromIdentifier(exitSceneIdentifier, this.MapUrlFile, this.instance);
const room = new Room(roomId);
gameManager.loadMap(room, this.scene);
const exitSceneKey = roomId;
const tiles : number[] = layer.data as number[];
for (let key=0; key < tiles.length; key++) {
const objectKey = tiles[key];
if(objectKey === 0){
continue;
}
//key + 1 because the start x = 0;
const y : number = parseInt(((key + 1) / mapWidth).toString());
const x : number = key - (y * mapWidth);
let hash = new URL(roomId, this.MapUrlFile).hash;
if (hash) {
hash = hash.substr(1);
}
//push and save switching case
if (this.PositionNextScene[y] === undefined) {
this.PositionNextScene[y] = new Array<{key: string, hash: string}>();
}
room.getMapUrl().then((url: string) => {
this.PositionNextScene[y][x] = {
key: url,
hash
}
})
}
await gameManager.loadMap(room, this.scene);
}
private startUser(layer: ITiledMapLayer): PositionInterface {
@ -975,33 +936,6 @@ export class GameScene extends ResizableScene implements CenterListener {
}
player.updatePosition(moveEvent);
});
const nextSceneKey = this.checkToExit();
if (!nextSceneKey) return;
if (nextSceneKey.key !== this.scene.key) {
// 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.simplePeer.unregister();
this.scene.stop();
this.scene.remove(this.scene.key);
this.scene.start(nextSceneKey.key);
} else {
//if the exit points to the current map, we simply teleport the user back to the startLayer
this.initPositionFromLayerName(this.room.hash || 'start');
this.CurrentPlayer.x = this.startX;
this.CurrentPlayer.y = this.startY;
}
}
private checkToExit(): {key: string, hash: string} | null {
const x = Math.floor(this.CurrentPlayer.x / 32);
const y = Math.floor(this.CurrentPlayer.y / 32);
if (this.PositionNextScene[y] !== undefined && this.PositionNextScene[y][x] !== undefined) {
return this.PositionNextScene[y][x];
} else {
return null;
}
}
/**