|
|
|
@@ -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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|