diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 3e4b0fff..3bf00b99 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -149,6 +149,37 @@ jobs: # Create a slugified value of the branch - uses: rlespinasse/github-slug-action@3.1.0 + - name: Write certificate + run: echo "${CERTS_PRIVATE_KEY}" > secret.key && chmod 0600 secret.key + env: + CERTS_PRIVATE_KEY: ${{ secrets.CERTS_PRIVATE_KEY }} + + - name: Download certificate + run: mkdir secrets && scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i secret.key ubuntu@cert.workadventu.re:./config/live/workadventu.re/* secrets/ + + - name: Create namespace + uses: steebchen/kubectl@v1.0.0 + env: + KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_FILE_BASE64 }} + with: + args: create namespace workadventure-${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} + continue-on-error: true + + - name: Delete old certificates in namespace + uses: steebchen/kubectl@v1.0.0 + env: + KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_FILE_BASE64 }} + with: + args: -n workadventure-${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} delete secret certificate-tls + continue-on-error: true + + - name: Install certificates in namespace + uses: steebchen/kubectl@v1.0.0 + env: + KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_FILE_BASE64 }} + with: + args: -n workadventure-${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} create secret tls certificate-tls --key="secrets/privkey.pem" --cert="secrets/fullchain.pem" + - name: Deploy uses: thecodingmachine/deeployer-action@master env: @@ -168,4 +199,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - msg: Environment deployed at https://play.${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re + msg: Environment deployed at https://play-${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re diff --git a/deeployer.libsonnet b/deeployer.libsonnet index f9dd87bd..8d9c2bfd 100644 --- a/deeployer.libsonnet +++ b/deeployer.libsonnet @@ -11,8 +11,7 @@ "back1": { "image": "thecodingmachine/workadventure-back:"+tag, "host": { - "url": "api1."+url, - "https": "enable", + "url": "api1-"+url, "containerPort": 8080 }, "ports": [8080, 50051], @@ -30,8 +29,7 @@ "back2": { "image": "thecodingmachine/workadventure-back:"+tag, "host": { - "url": "api2."+url, - "https": "enable", + "url": "api2-"+url, "containerPort": 8080 }, "ports": [8080, 50051], @@ -50,8 +48,7 @@ "replicas": 2, "image": "thecodingmachine/workadventure-pusher:"+tag, "host": { - "url": "pusher."+url, - "https": "enable" + "url": "pusher-"+url, }, "ports": [8080], "env": { @@ -68,27 +65,25 @@ "front": { "image": "thecodingmachine/workadventure-front:"+tag, "host": { - "url": "play."+url, - "https": "enable" + "url": "play-"+url, }, "ports": [80], "env": { - "PUSHER_URL": "//pusher."+url, - "UPLOADER_URL": "//uploader."+url, + "PUSHER_URL": "//pusher-"+url, + "UPLOADER_URL": "//uploader-"+url, "ADMIN_URL": "//"+url, "JITSI_URL": env.JITSI_URL, "SECRET_JITSI_KEY": env.SECRET_JITSI_KEY, "TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443", "JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false", - "START_ROOM_URL": "/_/global/maps."+url+"/Floor0/floor0.json" + "START_ROOM_URL": "/_/global/maps-"+url+"/Floor0/floor0.json" //"GA_TRACKING_ID": "UA-10196481-11" } }, "uploader": { "image": "thecodingmachine/workadventure-uploader:"+tag, "host": { - "url": "uploader."+url, - "https": "enable", + "url": "uploader-"+url, "containerPort": 8080 }, "ports": [8080], @@ -98,16 +93,12 @@ "maps": { "image": "thecodingmachine/workadventure-maps:"+tag, "host": { - "url": "maps."+url, - "https": "enable" + "url": "maps-"+url }, "ports": [80] }, }, "config": { - "https": { - "mail": "d.negrier@thecodingmachine.com" - }, k8sextension(k8sConf):: k8sConf + { back1+: { @@ -122,6 +113,14 @@ } } } + }, + ingress+: { + spec+: { + tls+: [{ + hosts: ["api1-"+url], + secretName: "certificate-tls" + }] + } } }, back2+: { @@ -136,6 +135,14 @@ } } } + }, + ingress+: { + spec+: { + tls+: [{ + hosts: ["api2-"+url], + secretName: "certificate-tls" + }] + } } }, pusher+: { @@ -150,8 +157,46 @@ } } } - } - } + }, + ingress+: { + spec+: { + tls+: [{ + hosts: ["pusher-"+url], + secretName: "certificate-tls" + }] + } + } + }, + front+: { + ingress+: { + spec+: { + tls+: [{ + hosts: ["play-"+url], + secretName: "certificate-tls" + }] + } + } + }, + uploader+: { + ingress+: { + spec+: { + tls+: [{ + hosts: ["uploader-"+url], + secretName: "certificate-tls" + }] + } + } + }, + maps+: { + ingress+: { + spec+: { + tls+: [{ + hosts: ["maps-"+url], + secretName: "certificate-tls" + }] + } + } + }, } } } diff --git a/front/src/Components/VisitCard/VisitCard.svelte b/front/src/Components/VisitCard/VisitCard.svelte index cc7f00d6..5cdb4cfe 100644 --- a/front/src/Components/VisitCard/VisitCard.svelte +++ b/front/src/Components/VisitCard/VisitCard.svelte @@ -1,39 +1,64 @@ -
- -
- -
+
+ {#if hidden} +
+ {/if} + + {#if !hidden} +
+ +
+ {/if} +
+ + diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index b1e8dc73..2ff66178 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -56,7 +56,7 @@ export abstract class Character extends Container { this.addTextures(textures, frame); this.invisible = false }) - + this.playerName = new Text(scene, 0, playerNameY, name, {fontFamily: '"Press Start 2P"', fontSize: '8px', strokeThickness: 2, stroke: "gray"}); this.playerName.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX); this.add(this.playerName); @@ -80,7 +80,7 @@ export abstract class Character extends Container { this.setDepth(-1); this.playAnimation(direction, moving); - + if (typeof companion === 'string') { this.addCompanion(companion, companionTexturePromise); } @@ -94,7 +94,7 @@ export abstract class Character extends Container { public addTextures(textures: string[], frame?: string | number): void { for (const texture of textures) { - if(!this.scene.textures.exists(texture)){ + if(this.scene && !this.scene.textures.exists(texture)){ throw new TextureError('texture not found'); } const sprite = new Sprite(this.scene, 0, 0, texture, frame); @@ -239,23 +239,23 @@ export abstract class Character extends Container { this.scene.sys.updateList.remove(sprite); } } - this.list.forEach(objectContaining => objectContaining.destroy()) + this.list.forEach(objectContaining => objectContaining.destroy()) super.destroy(); } - + playEmote(emoteKey: string) { this.cancelPreviousEmote(); const scalingFactor = waScaleManager.uiScalingFactor * 0.05; const emoteY = -30 - scalingFactor * 10; - + this.playerName.setVisible(false); this.emote = new Sprite(this.scene, 0, 0, emoteKey); this.emote.setAlpha(0); this.emote.setScale(0.1 * scalingFactor); this.add(this.emote); this.scene.sys.updateList.add(this.emote); - + this.createStartTransition(scalingFactor, emoteY); } diff --git a/front/src/Phaser/Entity/CustomizedCharacter.ts b/front/src/Phaser/Entity/CustomizedCharacter.ts new file mode 100644 index 00000000..3a7f1597 --- /dev/null +++ b/front/src/Phaser/Entity/CustomizedCharacter.ts @@ -0,0 +1,20 @@ +import Container = Phaser.GameObjects.Container; +import type {Scene} from "phaser"; +import Sprite = Phaser.GameObjects.Sprite; + +/** + * A sprite of a customized character (used in the Customize Scene only) + */ +export class CustomizedCharacter extends Container { + public constructor(scene: Scene, x: number, y: number, layers: string[]) { + super(scene, x, y); + this.updateSprites(layers); + } + + public updateSprites(layers: string[]): void { + this.removeAll(true); + for (const layer of layers) { + this.add(new Sprite(this.scene, 0, 0, layer)); + } + } +} diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index cc0c7208..f1d48235 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -15,6 +15,7 @@ import {customCharacterSceneVisibleStore} from "../../Stores/CustomCharacterStor import {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore"; import {waScaleManager} from "../Services/WaScaleManager"; import {isMobile} from "../../Enum/EnvironmentVariable"; +import {CustomizedCharacter} from "../Entity/CustomizedCharacter"; export const CustomizeSceneName = "CustomizeScene"; @@ -25,12 +26,15 @@ export class CustomizeScene extends AbstractCharacterScene { private Rectangle!: Rectangle; private selectedLayers: number[] = [0]; - private containersRow: Container[][] = []; + private containersRow: CustomizedCharacter[][] = []; public activeRow:number = 0; private layers: BodyResourceDescriptionInterface[][] = []; protected lazyloadingAttempt = true; //permit to update texture loaded after renderer + private moveHorizontally: number = 0; + private moveVertically: number = 0; + constructor() { super({ key: CustomizeSceneName @@ -88,10 +92,13 @@ export class CustomizeScene extends AbstractCharacterScene { this.backToPreviousScene(); }); - this.input.keyboard.on('keyup-RIGHT', () => this.moveCursorHorizontally(1)); - this.input.keyboard.on('keyup-LEFT', () => this.moveCursorHorizontally(-1)); - this.input.keyboard.on('keyup-DOWN', () => this.moveCursorVertically(1)); - this.input.keyboard.on('keyup-UP', () => this.moveCursorVertically(-1)); + // Note: the key bindings are not directly put on the moveCursorVertically or moveCursorHorizontally methods + // because if 2 such events are fired close to one another, it makes the whole application crawl to a halt (for a reason I cannot + // explain, the list of sprites managed by the update list become immense + this.input.keyboard.on('keyup-RIGHT', () => this.moveHorizontally = 1); + this.input.keyboard.on('keyup-LEFT', () => this.moveHorizontally = -1); + this.input.keyboard.on('keyup-DOWN', () => this.moveVertically = 1); + this.input.keyboard.on('keyup-UP', () => this.moveVertically = -1); const customCursorPosition = localUserStore.getCustomCursorPosition(); if (customCursorPosition) { @@ -104,7 +111,7 @@ export class CustomizeScene extends AbstractCharacterScene { this.onResize(); } - public moveCursorHorizontally(index: number): void { + public doMoveCursorHorizontally(index: number): void { this.selectedLayers[this.activeRow] += index; if (this.selectedLayers[this.activeRow] < 0) { this.selectedLayers[this.activeRow] = 0 @@ -116,7 +123,7 @@ export class CustomizeScene extends AbstractCharacterScene { this.saveInLocalStorage(); } - public moveCursorVertically(index:number): void { + public doMoveCursorVertically(index:number): void { this.activeRow += index; if (this.activeRow < 0) { @@ -165,20 +172,20 @@ export class CustomizeScene extends AbstractCharacterScene { * @param selectedItem, The number of the item select (0 for black body...) */ private generateCharacter(x: number, y: number, layerNumber: number, selectedItem: number) { - return new Container(this, x, y,this.getContainerChildren(layerNumber,selectedItem)); + return new CustomizedCharacter(this, x, y, this.getContainerChildren(layerNumber,selectedItem)); } - private getContainerChildren(layerNumber: number, selectedItem: number): Array { - const children: Array = new Array(); + private getContainerChildren(layerNumber: number, selectedItem: number): Array { + const children: Array = new Array(); for (let j = 0; j <= layerNumber; j++) { if (j === layerNumber) { - children.push(this.generateLayers(0, 0, this.layers[j][selectedItem].name)); + children.push(this.layers[j][selectedItem].name); } else { const layer = this.selectedLayers[j]; if (layer === undefined) { continue; } - children.push(this.generateLayers(0, 0, this.layers[j][layer].name)); + children.push(this.layers[j][layer].name); } } return children; @@ -215,15 +222,15 @@ export class CustomizeScene extends AbstractCharacterScene { * @return a new sprite */ private generateLayers(x: number, y: number, name: string): Sprite { - return new Sprite(this, x, y, name); + //return new Sprite(this, x, y, name); + return this.add.sprite(0, 0, name); } private updateSelectedLayer() { for(let i = 0; i < this.containersRow.length; i++){ for(let j = 0; j < this.containersRow[i].length; j++){ - const children = this.getContainerChildren(i, j); - this.containersRow[i][j].removeAll(true); - this.containersRow[i][j].add(children); + const children = this.getContainerChildren(i, j); + this.containersRow[i][j].updateSprites(children); } } } @@ -234,6 +241,15 @@ export class CustomizeScene extends AbstractCharacterScene { this.moveLayers(); this.lazyloadingAttempt = false; } + + if (this.moveHorizontally !== 0) { + this.doMoveCursorHorizontally(this.moveHorizontally); + this.moveHorizontally = 0; + } + if (this.moveVertically !== 0) { + this.doMoveCursorVertically(this.moveVertically); + this.moveVertically = 0; + } } diff --git a/front/src/Phaser/Services/WaScaleManager.ts b/front/src/Phaser/Services/WaScaleManager.ts index acbecc38..1da0fcf3 100644 --- a/front/src/Phaser/Services/WaScaleManager.ts +++ b/front/src/Phaser/Services/WaScaleManager.ts @@ -39,10 +39,11 @@ class WaScaleManager { const style = this.scaleManager.canvas.style; style.width = Math.ceil(realSize.width / devicePixelRatio) + 'px'; style.height = Math.ceil(realSize.height / devicePixelRatio) + 'px'; - // Note: onResize will be called twice (once here and once is Game.ts), but we have no better way. + // Note: onResize will be called twice (once here and once in Game.ts), but we have no better way. for (const scene of this.game.scene.getScenes(true)) { if (scene instanceof ResizableScene) { - scene.onResize(); + // We are delaying the call to the "render" event because otherwise, the "camera" coordinates are not correctly updated. + scene.events.once(Phaser.Scenes.Events.RENDER, () => scene.onResize()); } } diff --git a/front/src/Stores/ScreenSharingStore.ts b/front/src/Stores/ScreenSharingStore.ts index 0a7ef3e6..ec5aa46f 100644 --- a/front/src/Stores/ScreenSharingStore.ts +++ b/front/src/Stores/ScreenSharingStore.ts @@ -169,6 +169,7 @@ export const screenSharingLocalStreamStore = derived