GameSpectator wip
+ forfeit button + refactoring GameSession
This commit is contained in:
@@ -48,7 +48,10 @@ export class GameSession {
|
||||
timeout += c.newRoundDelay*0.5;
|
||||
});
|
||||
}
|
||||
resume(s: GameSession) {
|
||||
resume(s?: GameSession)
|
||||
{
|
||||
if (!s) { s = this; }
|
||||
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.on("message", clientInputListener);
|
||||
});
|
||||
@@ -59,7 +62,10 @@ export class GameSession {
|
||||
s.playersUpdateInterval = setInterval(s._playersUpdate, c.playersUpdateIntervalMS, s);
|
||||
s.spectatorsUpdateInterval = setInterval(s._spectatorsUpdate, c.spectatorsUpdateIntervalMS, s);
|
||||
}
|
||||
pause(s: GameSession) {
|
||||
pause(s?: GameSession)
|
||||
{
|
||||
if (!s) { s = this; }
|
||||
|
||||
s.playersMap.forEach( (client) => {
|
||||
client.socket.off("message", clientInputListener);
|
||||
});
|
||||
@@ -68,6 +74,19 @@ export class GameSession {
|
||||
clearInterval(s.playersUpdateInterval);
|
||||
clearInterval(s.spectatorsUpdateInterval);
|
||||
}
|
||||
destroy(s?: GameSession)
|
||||
{
|
||||
if (!s) { s = this; }
|
||||
|
||||
s.pause();
|
||||
|
||||
s.spectatorsMap.forEach((client) => {
|
||||
clientTerminate(client);
|
||||
});
|
||||
s.playersMap.forEach((client) => {
|
||||
clientTerminate(client);
|
||||
});
|
||||
}
|
||||
instantInputDebug(client: ClientPlayer) {
|
||||
this._handleInput(c.fixedDeltaTime, client);
|
||||
}
|
||||
@@ -200,26 +219,35 @@ export class GameSession {
|
||||
ball.speed = ball.baseSpeed;
|
||||
ball.ballInPlay = true;
|
||||
}
|
||||
private _checkDisconnexions() {
|
||||
private _checkDisconnexions()
|
||||
{
|
||||
if (this.playersMap.size !== 2)
|
||||
{
|
||||
this.matchEnded = true;
|
||||
if (this.playersMap.size != 0)
|
||||
{
|
||||
console.log("Forfeit Ending");
|
||||
const gc = this.components;
|
||||
const luckyWinner: ClientPlayer = this.playersMap.values().next().value;
|
||||
if (luckyWinner.racket === gc.playerLeft) {
|
||||
this._matchEnd(en.PlayerSide.left, true);
|
||||
}
|
||||
else {
|
||||
this._matchEnd(en.PlayerSide.right, true);
|
||||
}
|
||||
if (this.playersMap.size != 0) {
|
||||
this._forfeit();
|
||||
}
|
||||
else {
|
||||
// WIP: envoyer un truc à Nest ? Genre "match draw"
|
||||
this.destroy();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private _forfeit()
|
||||
{
|
||||
this.matchEnded = true;
|
||||
console.log("Forfeit Ending");
|
||||
const gc = this.components;
|
||||
const luckyWinner: ClientPlayer = this.playersMap.values().next().value;
|
||||
if (luckyWinner.racket === gc.playerLeft) {
|
||||
this._matchEnd(en.PlayerSide.left, true);
|
||||
}
|
||||
else {
|
||||
this._matchEnd(en.PlayerSide.right, true);
|
||||
}
|
||||
}
|
||||
private async _matchEnd(winner: en.PlayerSide, forfeit_flag: boolean = false)
|
||||
{
|
||||
this.matchEnded = true;
|
||||
@@ -246,15 +274,7 @@ export class GameSession {
|
||||
})
|
||||
});
|
||||
|
||||
const gameSession = this;
|
||||
setTimeout(function kickRemainingClients() {
|
||||
gameSession.spectatorsMap.forEach((client) => {
|
||||
clientTerminate(client);
|
||||
});
|
||||
gameSession.playersMap.forEach((client) => {
|
||||
clientTerminate(client);
|
||||
});
|
||||
}, 15000);
|
||||
setTimeout(this.destroy, 15000, this);
|
||||
|
||||
// logs
|
||||
if (winner === en.PlayerSide.left) {
|
||||
|
||||
@@ -40,6 +40,14 @@ function connectionListener(socket: WebSocket, request: IncomingMessage)
|
||||
console.log(`client ${shortId(client.id)} is alive`);
|
||||
});
|
||||
|
||||
socket.on("error", function errorPrint(this: WebSocket, err: Error) {
|
||||
console.log(`error socket ${shortId(this.id)}:`);
|
||||
console.log(`${err.name}: ${err.message}`);
|
||||
if (err.stack) {
|
||||
console.log(`err.stack: ${err.stack}`);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("message", function log(data: string) {
|
||||
try {
|
||||
const event: ev.ClientEvent = JSON.parse(data);
|
||||
@@ -96,10 +104,13 @@ async function clientAnnounceListener(this: WebSocket, data: string)
|
||||
const player = clientsMap.get(this.id) as ClientPlayer;
|
||||
player.matchOptions = announce.matchOptions;
|
||||
player.token = announce.token;
|
||||
announce.isInvitedPerson ? player.username = announce.playerTwoUsername : player.username = announce.username;
|
||||
player.username = announce.username;
|
||||
this.send(JSON.stringify( new ev.EventAssignId(this.id) )); // unused
|
||||
this.send(JSON.stringify( new ev.ServerEvent(en.EventTypes.matchmakingInProgress) ));
|
||||
if (announce.privateMatch) {
|
||||
if (announce.isInvitedPerson) {
|
||||
player.username = announce.playerTwoUsername;
|
||||
}
|
||||
privateMatchmaking(player);
|
||||
}
|
||||
else {
|
||||
@@ -365,9 +376,7 @@ export function clientTerminate(client: Client)
|
||||
client.gameSession.playersMap.delete(client.id);
|
||||
if (client.gameSession.playersMap.size === 0)
|
||||
{
|
||||
clearInterval(client.gameSession.playersUpdateInterval);
|
||||
clearInterval(client.gameSession.spectatorsUpdateInterval);
|
||||
clearInterval(client.gameSession.gameLoopInterval);
|
||||
client.gameSession.destroy();
|
||||
gameSessionsMap.delete(client.gameSession.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Header from '../pieces/Header.svelte';
|
||||
import MatchListElem from "../pieces/MatchListElem.svelte";
|
||||
|
||||
let arr = [
|
||||
{
|
||||
id: "match-01",
|
||||
playerOneUsername: "toto",
|
||||
playerTwoUsername: "bruno",
|
||||
},
|
||||
{
|
||||
id: "match-02",
|
||||
playerOneUsername: "bertand",
|
||||
playerTwoUsername: "cassandre",
|
||||
},
|
||||
{
|
||||
id: "match-03",
|
||||
playerOneUsername: "madeleine",
|
||||
playerTwoUsername: "jack",
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<!-- -->
|
||||
|
||||
<Header/>
|
||||
<menu>
|
||||
{#each arr as match}
|
||||
<MatchListElem match={match}/>
|
||||
{/each}
|
||||
</menu>
|
||||
|
||||
|
||||
<!-- -->
|
||||
<style>
|
||||
</style>
|
||||
@@ -111,8 +111,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Pour Cherif: renommer en un truc du genre "initGameForInvitedPlayer" ?
|
||||
const initGameForPrivateParty = async(invitation : any) =>
|
||||
const initGameForInvitedPlayer = async(invitation : any) =>
|
||||
{
|
||||
idOfIntevalCheckTerminationOfTheMatch = setInterval(matchTermitation, 1000);
|
||||
optionsAreNotSet = false
|
||||
@@ -206,12 +205,18 @@
|
||||
if (res.status === 200)
|
||||
{
|
||||
showInvitation()
|
||||
initGameForPrivateParty(invitation)
|
||||
initGameForInvitedPlayer(invitation)
|
||||
}
|
||||
//Au final c'est utile !
|
||||
|
||||
initGameForPrivateParty(invitation)
|
||||
initGameForInvitedPlayer(invitation) // Luke: normal de initGameForInvitedPlayer() sur un "res.status" different de 200 ?
|
||||
}
|
||||
|
||||
function leaveMatch() {
|
||||
hiddenGame = true;
|
||||
pong.destroy();
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<Header />
|
||||
@@ -232,9 +237,16 @@
|
||||
</fieldset>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div id="canvas_container" hidden={hiddenGame}>
|
||||
<canvas id={gameAreaId}/>
|
||||
</div>
|
||||
{#if !hiddenGame}
|
||||
<div id="div_game">
|
||||
<button id="pong_button" on:click={leaveMatch}>forfeit</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
{#if showWaitPage === true}
|
||||
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
|
||||
@@ -282,7 +294,7 @@
|
||||
</select>
|
||||
{/if}
|
||||
<div>
|
||||
<button id="pong_button" >PLAY</button>
|
||||
<button id="pong_button">PLAY</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -343,12 +355,12 @@
|
||||
/* max-height: 80vh; */
|
||||
/* overflow: hidden; */
|
||||
}
|
||||
|
||||
#users_name {
|
||||
text-align: center;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: x-large;
|
||||
canvas {
|
||||
/* background-color: #ff0000; */
|
||||
background-color: #333333;
|
||||
max-width: 75vw;
|
||||
/* max-height: 100vh; */
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#div_game {
|
||||
@@ -358,15 +370,6 @@
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
#error_notification {
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(143, 19, 19);
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
#div_game fieldset {
|
||||
max-width: 50vw;
|
||||
width: auto;
|
||||
@@ -382,12 +385,19 @@
|
||||
font-size: x-large;
|
||||
padding: 10px;
|
||||
}
|
||||
canvas {
|
||||
/* background-color: #ff0000; */
|
||||
background-color: #333333;
|
||||
max-width: 75vw;
|
||||
/* max-height: 100vh; */
|
||||
width: 80%;
|
||||
|
||||
#users_name { /* UNUSED */
|
||||
text-align: center;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: x-large;
|
||||
}
|
||||
#error_notification { /* UNUSED */
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(143, 19, 19);
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import Header from '../../pieces/Header.svelte';
|
||||
import MatchListElem from "../../pieces/MatchListElem.svelte";
|
||||
import { fade, fly } from 'svelte/transition';
|
||||
|
||||
import * as pongSpectator from "./client/pongSpectator";
|
||||
@@ -15,6 +16,28 @@
|
||||
|
||||
//Game's stuff client side only
|
||||
const gameAreaId = "game_area";
|
||||
let sound = "off";
|
||||
const dummyMatchList = [
|
||||
{
|
||||
gameSessionId: "id2445",
|
||||
matchOptions: pongSpectator.MatchOptions.noOption,
|
||||
playerOneUsername: "toto",
|
||||
playerTwoUsername: "bruno",
|
||||
},
|
||||
{
|
||||
gameSessionId: "id6543",
|
||||
matchOptions: pongSpectator.MatchOptions.movingWalls | pongSpectator.MatchOptions.multiBalls,
|
||||
playerOneUsername: "bertand",
|
||||
playerTwoUsername: "cassandre",
|
||||
},
|
||||
{
|
||||
gameSessionId: "id3452",
|
||||
matchOptions: pongSpectator.MatchOptions.multiBalls,
|
||||
playerOneUsername: "madeleine",
|
||||
playerTwoUsername: "jack",
|
||||
},
|
||||
];
|
||||
let matchList = dummyMatchList;
|
||||
|
||||
//html boolean for pages
|
||||
let hiddenGame = true;
|
||||
@@ -24,21 +47,26 @@
|
||||
.then( x => x.json() );
|
||||
allUsers = await fetch('http://transcendance:8080/api/v2/user/all')
|
||||
.then( x => x.json() );
|
||||
// WIP: fetch for match list here
|
||||
matchList = dummyMatchList;
|
||||
})
|
||||
|
||||
onDestroy( async() => {
|
||||
pongSpectator.destroy();
|
||||
})
|
||||
|
||||
const initGameSpectator = async() => {
|
||||
let gameSessionId = "ID_PLACEHOLDER"; // PLACEHOLDER
|
||||
let matchOptions = 0; // PLACEHOLDER
|
||||
let sound = "off"; // PLACEHOLDER
|
||||
const initGameSpectator = async(gameSessionId: string, matchOptions: pongSpectator.MatchOptions) => {
|
||||
pongSpectator.init(matchOptions, sound, gameAreaId, gameSessionId);
|
||||
hiddenGame = false;
|
||||
};
|
||||
|
||||
function leaveMatch() {
|
||||
hiddenGame = true;
|
||||
pongSpectator.destroy();
|
||||
};
|
||||
|
||||
</script>
|
||||
<!-- -->
|
||||
|
||||
<Header />
|
||||
<!-- <div id="game_page"> Replacement for <body>.
|
||||
@@ -49,7 +77,87 @@
|
||||
<canvas id={gameAreaId}/>
|
||||
</div>
|
||||
|
||||
{#if hiddenGame}
|
||||
<div id="div_game">
|
||||
<div id="game_options">
|
||||
<fieldset>
|
||||
<legend>options</legend>
|
||||
<div>
|
||||
<p>sound :</p>
|
||||
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
|
||||
<label for="sound_on">on</label>
|
||||
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
|
||||
<label for="sound_off">off</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<menu id="match_list">
|
||||
{#each matchList as match}
|
||||
<MatchListElem match={match} on:click={(e) => initGameSpectator(match.gameSessionId, match.matchOptions)} />
|
||||
{/each}
|
||||
</menu>
|
||||
</div>
|
||||
{:else}
|
||||
<div id="div_game">
|
||||
<button id="pong_button" on:click={leaveMatch}>leave match</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div> <!-- div "game_page" -->
|
||||
|
||||
<!-- -->
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "Bit5x3";
|
||||
src:
|
||||
url("/fonts/Bit5x3.woff2") format("woff2"),
|
||||
local("Bit5x3"),
|
||||
url("/fonts/Bit5x3.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
#game_page {
|
||||
margin: 0;
|
||||
background-color: #222425;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#canvas_container {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
canvas {
|
||||
background-color: #333333;
|
||||
max-width: 75vw;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#div_game {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: x-large;
|
||||
}
|
||||
#div_game fieldset {
|
||||
max-width: 50vw;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#div_game fieldset div {
|
||||
padding: 10px;
|
||||
}
|
||||
#match_list {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: large;
|
||||
}
|
||||
#pong_button {
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
background-color: #333333;
|
||||
font-size: x-large;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { drawLoop } from "./draw.js";
|
||||
import { initWebSocketSpectator } from "./ws.js";
|
||||
import { initBase, destroyBase, computeMatchOptions } from "./init.js";
|
||||
export { computeMatchOptions } from "./init.js";
|
||||
export { MatchOptions } from "../shared_js/enums.js"
|
||||
|
||||
/* TODO: A way to delay the init of variables, but still use "const" not "let" ? */
|
||||
import { pong, gc } from "./global.js"
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
<img src="/img/potato_logo.png" alt="Potato Pong Logo" on:click={() => (push('/'))}>
|
||||
<h1>Potato Pong</h1>
|
||||
<nav>
|
||||
<button on:click={() => (push('/game'))}>Game</button>
|
||||
<button on:click={() => (push('/matchlist'))}>Match List</button>
|
||||
<button on:click={() => (push('/game'))}>Play</button>
|
||||
<button on:click={() => (push('/spectator'))}>Spectate</button>
|
||||
<button on:click={() => (push('/ranking'))}>Ranking</button>
|
||||
{#if $location !== '/profile'}
|
||||
<button on:click={() => (push('/profile'))}>My Profile</button>
|
||||
|
||||
@@ -1,15 +1,40 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { MatchOptions } from "../pages/game/client/pongSpectator";
|
||||
|
||||
export let match: {
|
||||
id: string,
|
||||
gameSessionId: string,
|
||||
matchOptions: MatchOptions,
|
||||
playerOneUsername: string,
|
||||
playerTwoUsername: string
|
||||
};
|
||||
|
||||
let matchOptionsString = "";
|
||||
|
||||
onMount( async() => {
|
||||
if (match.matchOptions === MatchOptions.noOption) {
|
||||
matchOptionsString = "standard";
|
||||
}
|
||||
else {
|
||||
if (match.matchOptions & MatchOptions.multiBalls) {
|
||||
matchOptionsString += "multi balls";
|
||||
}
|
||||
if (match.matchOptions & MatchOptions.movingWalls) {
|
||||
if (matchOptionsString) { matchOptionsString += ", "; }
|
||||
matchOptionsString += "moving walls";
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<!-- -->
|
||||
|
||||
<li>
|
||||
{match.id} "{match.playerOneUsername}" VS "{match.playerTwoUsername}"
|
||||
<button on:click>
|
||||
"{match.playerOneUsername}" VS "{match.playerTwoUsername}"
|
||||
<br/> [{matchOptionsString}]
|
||||
</button>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { wrap } from 'svelte-spa-router/wrap'
|
||||
import TestPage from '../pages/TmpTestPage.svelte';
|
||||
import Game from '../pages/game/Game.svelte';
|
||||
import Ranking from '../pages/game/Ranking.svelte';
|
||||
import SpectatorMatchList from '../pages/SpectatorMatchList.svelte';
|
||||
import GameSpectator from '../pages/game/GameSpectator.svelte';
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export const primaryRoutes = {
|
||||
'/': SplashPage,
|
||||
'/2fa': TwoFactorAuthentication,
|
||||
'/game': Game,
|
||||
'/matchlist': SpectatorMatchList,
|
||||
'/spectator': GameSpectator,
|
||||
'/ranking' : Ranking,
|
||||
'/profile': wrap({
|
||||
component: ProfilePage,
|
||||
|
||||
Reference in New Issue
Block a user