Merge pull request #99 from thecodingmachine/map_history
Adding support for history API
This commit is contained in:
commit
23a12ea652
@ -49,7 +49,7 @@
|
|||||||
{
|
{
|
||||||
"name":"exitSceneUrl",
|
"name":"exitSceneUrl",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"value":"\/Floor1\/floor1.json"
|
"value":"..\/Floor1\/floor1.json"
|
||||||
}],
|
}],
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
@ -67,7 +67,7 @@
|
|||||||
{
|
{
|
||||||
"name":"exitSceneUrl",
|
"name":"exitSceneUrl",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"value":"\/Lyon\/lyon.json"
|
"value":"..\/Lyon\/lyon.json"
|
||||||
}],
|
}],
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
{
|
{
|
||||||
"name":"exitSceneUrl",
|
"name":"exitSceneUrl",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"value":"\/Floor0\/floor0.json"
|
"value":"..\/Floor0\/floor0.json"
|
||||||
}],
|
}],
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
|
BIN
back/src/Assets/Maps/Lyon/floortileset.png
Normal file
BIN
back/src/Assets/Maps/Lyon/floortileset.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 85 KiB |
@ -37,7 +37,7 @@
|
|||||||
{
|
{
|
||||||
"name":"exitSceneUrl",
|
"name":"exitSceneUrl",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"value":"\/Floor0\/floor0.json"
|
"value":"..\/Floor0\/floor0.json"
|
||||||
}],
|
}],
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
|
BIN
back/src/Assets/Maps/Lyon/tilesets_deviant_milkian_1.png
Normal file
BIN
back/src/Assets/Maps/Lyon/tilesets_deviant_milkian_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -20,7 +20,7 @@ export class MapController {
|
|||||||
getMaps() {
|
getMaps() {
|
||||||
this.App.get("/maps", (req: Request, res: Response) => {
|
this.App.get("/maps", (req: Request, res: Response) => {
|
||||||
return res.status(OK).send({
|
return res.status(OK).send({
|
||||||
mapUrlStart: URL_ROOM_STARTED
|
mapUrlStart: req.headers.host + "/map/files" + URL_ROOM_STARTED
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
23
front/dist/.htaccess
vendored
Normal file
23
front/dist/.htaccess
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DirectoryIndex index.html
|
||||||
|
|
||||||
|
# By default, Apache does not evaluate symbolic links if you did not enable this
|
||||||
|
# feature in your server configuration. Uncomment the following line if you
|
||||||
|
# install assets as symlinks or if you experience problems related to symlinks
|
||||||
|
# when compiling LESS/Sass/CoffeScript assets.
|
||||||
|
# Options FollowSymlinks
|
||||||
|
|
||||||
|
# Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve
|
||||||
|
# to the front controller "/index.php" but be rewritten to "/index.php/index".
|
||||||
|
<IfModule mod_negotiation.c>
|
||||||
|
Options -MultiViews
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
RewriteBase /
|
||||||
|
|
||||||
|
# If the requested filename exists, simply serve it.
|
||||||
|
# We only want to let Apache serve files and not directories.
|
||||||
|
# Rewrite all other queries starting with _ to index.ts.
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule "^_/" "/index.html" [L]
|
1
front/dist/index.html
vendored
1
front/dist/index.html
vendored
@ -5,6 +5,7 @@
|
|||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<base href="/">
|
||||||
<link rel="stylesheet" href="/resources/style/style.css">
|
<link rel="stylesheet" href="/resources/style/style.css">
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
</head>
|
</head>
|
||||||
|
@ -140,7 +140,6 @@ export interface ConnexionInterface {
|
|||||||
token: string;
|
token: string;
|
||||||
email: string;
|
email: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
startedRoom: string;
|
|
||||||
|
|
||||||
createConnexion(characterSelected: string): Promise<any>;
|
createConnexion(characterSelected: string): Promise<any>;
|
||||||
|
|
||||||
@ -167,7 +166,6 @@ export class Connexion implements ConnexionInterface {
|
|||||||
token: string;
|
token: string;
|
||||||
email: string;
|
email: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
startedRoom: string;
|
|
||||||
|
|
||||||
GameManager: GameManager;
|
GameManager: GameManager;
|
||||||
|
|
||||||
@ -183,8 +181,6 @@ export class Connexion implements ConnexionInterface {
|
|||||||
return Axios.post(`${API_URL}/login`, {email: this.email})
|
return Axios.post(`${API_URL}/login`, {email: this.email})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.token = res.data.token;
|
this.token = res.data.token;
|
||||||
|
|
||||||
this.startedRoom = getMapKeyByUrl(res.data.mapUrlStart);
|
|
||||||
this.userId = res.data.userId;
|
this.userId = res.data.userId;
|
||||||
|
|
||||||
this.socket = SocketIo(`${API_URL}`, {
|
this.socket = SocketIo(`${API_URL}`, {
|
||||||
@ -194,10 +190,10 @@ export class Connexion implements ConnexionInterface {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//join the room
|
//join the room
|
||||||
this.joinARoom(this.startedRoom, characterSelected);
|
//this.joinARoom(this.startedRoom, characterSelected);
|
||||||
|
|
||||||
//share your first position
|
//share your first position
|
||||||
this.sharePosition(0, 0, characterSelected, this.startedRoom);
|
//this.sharePosition(0, 0, characterSelected, this.startedRoom);
|
||||||
|
|
||||||
this.positionOfAllUser();
|
this.positionOfAllUser();
|
||||||
|
|
||||||
|
@ -3,13 +3,11 @@ const API_URL = process.env.API_URL || "http://api.workadventure.localhost";
|
|||||||
const ROOM = [process.env.ROOM || "THECODINGMACHINE"];
|
const ROOM = [process.env.ROOM || "THECODINGMACHINE"];
|
||||||
const RESOLUTION = 3;
|
const RESOLUTION = 3;
|
||||||
const ZOOM_LEVEL = 1/*3/4*/;
|
const ZOOM_LEVEL = 1/*3/4*/;
|
||||||
const MAP_FILE_URL = `${API_URL}/map/files`;
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DEBUG_MODE,
|
DEBUG_MODE,
|
||||||
API_URL,
|
API_URL,
|
||||||
RESOLUTION,
|
RESOLUTION,
|
||||||
ZOOM_LEVEL,
|
ZOOM_LEVEL,
|
||||||
ROOM,
|
ROOM
|
||||||
MAP_FILE_URL
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ import {
|
|||||||
ListMessageUserPositionInterface
|
ListMessageUserPositionInterface
|
||||||
} from "../../Connexion";
|
} from "../../Connexion";
|
||||||
import {SimplePeerInterface, SimplePeer} from "../../WebRtc/SimplePeer";
|
import {SimplePeerInterface, SimplePeer} from "../../WebRtc/SimplePeer";
|
||||||
|
import {getMapKeyByUrl} from "../Login/LogincScene";
|
||||||
|
import SceneManager = Phaser.Scenes.SceneManager;
|
||||||
|
import ScenePlugin = Phaser.Scenes.ScenePlugin;
|
||||||
|
|
||||||
export enum StatusGameManagerEnum {
|
export enum StatusGameManagerEnum {
|
||||||
IN_PROGRESS = 1,
|
IN_PROGRESS = 1,
|
||||||
@ -124,6 +127,18 @@ export class GameManager {
|
|||||||
pushPlayerPosition(event: HasMovedEvent) {
|
pushPlayerPosition(event: HasMovedEvent) {
|
||||||
this.ConnexionInstance.sharePosition(event.x, event.y, event.character, this.currentGameScene.scene.key, event.direction);
|
this.ConnexionInstance.sharePosition(event.x, event.y, event.character, this.currentGameScene.scene.key, event.direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadMap(mapUrl: string, scene: ScenePlugin): string {
|
||||||
|
let sceneKey = getMapKeyByUrl(mapUrl);
|
||||||
|
|
||||||
|
let gameIndex = scene.getIndex(sceneKey);
|
||||||
|
let game : Phaser.Scene = null;
|
||||||
|
if(gameIndex === -1){
|
||||||
|
game = new GameScene(sceneKey, mapUrl);
|
||||||
|
scene.add(sceneKey, game, false);
|
||||||
|
}
|
||||||
|
return sceneKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const gameManager = new GameManager();
|
export const gameManager = new GameManager();
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import {GameManager, gameManager, HasMovedEvent, MapObject, StatusGameManagerEnum} from "./GameManager";
|
import {GameManager, gameManager, HasMovedEvent, MapObject, StatusGameManagerEnum} from "./GameManager";
|
||||||
import {GroupCreatedUpdatedMessageInterface, MessageUserPositionInterface} from "../../Connexion";
|
import {GroupCreatedUpdatedMessageInterface, MessageUserPositionInterface} from "../../Connexion";
|
||||||
import {CurrentGamerInterface, GamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
import {CurrentGamerInterface, GamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
||||||
import { DEBUG_MODE, MAP_FILE_URL, RESOLUTION, ROOM, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
|
import { DEBUG_MODE, RESOLUTION, ROOM, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
|
||||||
import {ITiledMap, ITiledMapLayer, ITiledTileSet} from "../Map/ITiledMap";
|
import {ITiledMap, ITiledMapLayer, ITiledTileSet} from "../Map/ITiledMap";
|
||||||
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||||
import CreateSceneFromObjectConfig = Phaser.Types.Scenes.CreateSceneFromObjectConfig;
|
import CreateSceneFromObjectConfig = Phaser.Types.Scenes.CreateSceneFromObjectConfig;
|
||||||
import {getMapKeyByUrl} from "../Login/LogincScene";
|
|
||||||
|
|
||||||
export enum Textures {
|
export enum Textures {
|
||||||
Player = "male1"
|
Player = "male1"
|
||||||
@ -61,7 +60,7 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface, Creat
|
|||||||
// Triggered when the map is loaded
|
// Triggered when the map is loaded
|
||||||
// Load tiles attached to the map recursively
|
// Load tiles attached to the map recursively
|
||||||
this.map = data.data;
|
this.map = data.data;
|
||||||
let url = this.MapUrlFile.substr(0, this.MapUrlFile.indexOf(`${this.MapKey}.json`));
|
let url = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||||
this.map.tilesets.forEach((tileset) => {
|
this.map.tilesets.forEach((tileset) => {
|
||||||
if (typeof tileset.name === 'undefined' || typeof tileset.image === 'undefined') {
|
if (typeof tileset.name === 'undefined' || typeof tileset.image === 'undefined') {
|
||||||
console.warn("Don't know how to handle tileset ", tileset)
|
console.warn("Don't know how to handle tileset ", tileset)
|
||||||
@ -151,6 +150,15 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface, Creat
|
|||||||
context.strokeStyle = '#ffffff';
|
context.strokeStyle = '#ffffff';
|
||||||
context.stroke();
|
context.stroke();
|
||||||
this.circleTexture.refresh();
|
this.circleTexture.refresh();
|
||||||
|
|
||||||
|
// Let's alter browser history
|
||||||
|
let url = new URL(this.MapUrlFile);
|
||||||
|
let path = '/_/'+url.host+url.pathname;
|
||||||
|
if (url.hash) {
|
||||||
|
// FIXME: entry should be dictated by a property passed to init()
|
||||||
|
path += '#'+url.hash;
|
||||||
|
}
|
||||||
|
window.history.pushState({}, null, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
|
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
|
||||||
@ -175,19 +183,11 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface, Creat
|
|||||||
private loadNextGame(layer: ITiledMapLayer, mapWidth: number, tileWidth: number, tileHeight: number){
|
private loadNextGame(layer: ITiledMapLayer, mapWidth: number, tileWidth: number, tileHeight: number){
|
||||||
let exitSceneUrl = this.getExitSceneUrl(layer);
|
let exitSceneUrl = this.getExitSceneUrl(layer);
|
||||||
|
|
||||||
let exitSceneKey = getMapKeyByUrl(exitSceneUrl);
|
// TODO: eventually compute a relative URL
|
||||||
|
let absoluteExitSceneUrl = new URL(exitSceneUrl, this.MapUrlFile).href;
|
||||||
|
console.log('absoluteExitSceneUrl ', absoluteExitSceneUrl);
|
||||||
|
let exitSceneKey = gameManager.loadMap(absoluteExitSceneUrl, this.scene);
|
||||||
|
|
||||||
let gameIndex = this.scene.getIndex(exitSceneKey);
|
|
||||||
let game : Phaser.Scene = null;
|
|
||||||
if(gameIndex === -1){
|
|
||||||
game = new GameScene(exitSceneKey, `${MAP_FILE_URL}${exitSceneUrl}`);
|
|
||||||
this.scene.add(exitSceneKey, game, false);
|
|
||||||
}else{
|
|
||||||
game = this.scene.get(exitSceneKey);
|
|
||||||
}
|
|
||||||
if(!game){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let tiles : any = layer.data;
|
let tiles : any = layer.data;
|
||||||
tiles.forEach((objectKey : number, key: number) => {
|
tiles.forEach((objectKey : number, key: number) => {
|
||||||
if(objectKey === 0){
|
if(objectKey === 0){
|
||||||
|
@ -8,9 +8,15 @@ import Rectangle = Phaser.GameObjects.Rectangle;
|
|||||||
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
||||||
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
||||||
import {GroupCreatedUpdatedMessageInterface, MessageUserPositionInterface} from "../../Connexion";
|
import {GroupCreatedUpdatedMessageInterface, MessageUserPositionInterface} from "../../Connexion";
|
||||||
import {MAP_FILE_URL} from "../../Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
export function getMapKeyByUrl(mapUrlStart: string){
|
export function getMapKeyByUrl(mapUrlStart: string){
|
||||||
|
// FIXME: the key should be computed from the full URL of the map.
|
||||||
|
let startPos = mapUrlStart.indexOf('://')+3;
|
||||||
|
let endPos = mapUrlStart.indexOf(".json");
|
||||||
|
console.log('MAP KEY '+mapUrlStart.substring(startPos, endPos));
|
||||||
|
return mapUrlStart.substring(startPos, endPos);
|
||||||
|
|
||||||
|
|
||||||
let tab = mapUrlStart.split("/");
|
let tab = mapUrlStart.split("/");
|
||||||
return tab[tab.length -1].substr(0, tab[tab.length -1].indexOf(".json"));
|
return tab[tab.length -1].substr(0, tab[tab.length -1].indexOf(".json"));
|
||||||
}
|
}
|
||||||
@ -99,25 +105,40 @@ export class LogincScene extends Phaser.Scene implements GameSceneInterface {
|
|||||||
|
|
||||||
private async login(name: string) {
|
private async login(name: string) {
|
||||||
return gameManager.connect(name, this.selectedPlayer.texture.key).then(() => {
|
return gameManager.connect(name, this.selectedPlayer.texture.key).then(() => {
|
||||||
return gameManager.loadMaps().then((scene : any) => {
|
// Do we have a start URL in the address bar? If so, let's redirect to this address
|
||||||
if (!scene) {
|
let mapUrl = this.findMapUrl();
|
||||||
return;
|
if (mapUrl !== null) {
|
||||||
}
|
let key = gameManager.loadMap(mapUrl, this.scene);
|
||||||
let key = getMapKeyByUrl(scene.mapUrlStart);
|
|
||||||
let game = new GameScene(key,`${MAP_FILE_URL}${scene.mapUrlStart}`);
|
|
||||||
this.scene.add(key, game, false);
|
|
||||||
this.scene.start(key);
|
this.scene.start(key);
|
||||||
return scene;
|
return mapUrl;
|
||||||
}).catch((err) => {
|
} else {
|
||||||
console.error(err);
|
// If we do not have a map address in the URL, let's ask the server for a start map.
|
||||||
throw err;
|
return gameManager.loadMaps().then((scene : any) => {
|
||||||
});
|
if (!scene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let key = gameManager.loadMap(window.location.protocol+"//"+scene.mapUrlStart, this.scene);
|
||||||
|
this.scene.start(key);
|
||||||
|
return scene;
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private findMapUrl(): string|null {
|
||||||
|
let path = window.location.pathname;
|
||||||
|
if (!path.startsWith('/_/')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return window.location.protocol+'//'+path.substr(3);
|
||||||
|
}
|
||||||
|
|
||||||
Map: Phaser.Tilemaps.Tilemap;
|
Map: Phaser.Tilemaps.Tilemap;
|
||||||
|
|
||||||
initAnimation(): void {
|
initAnimation(): void {
|
||||||
|
@ -8,6 +8,12 @@ module.exports = {
|
|||||||
contentBase: './dist',
|
contentBase: './dist',
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
disableHostCheck: true,
|
disableHostCheck: true,
|
||||||
|
historyApiFallback: {
|
||||||
|
rewrites: [
|
||||||
|
{ from: /^_\/.*$/, to: '/index.html' }
|
||||||
|
],
|
||||||
|
disableDotRule: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
@ -24,6 +30,7 @@ module.exports = {
|
|||||||
output: {
|
output: {
|
||||||
filename: 'bundle.js',
|
filename: 'bundle.js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
publicPath: '/'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
|
Loading…
Reference in New Issue
Block a user