mirror of
https://github.com/OpenLiberty/liberty-bikes.git
synced 2025-01-30 10:40:13 +08:00
Merge pull request #78 from aguibert/queue-bugfix-2
Smooth out requeueing after a game is over
This commit is contained in:
commit
0b033ed5ab
@ -3,6 +3,9 @@ import { Router } from '@angular/router';
|
||||
import { GameService } from '../game/game.service';
|
||||
import { Triangle } from '../geom/triangle';
|
||||
import { Point } from '../geom/point';
|
||||
import { LoginComponent } from '../login/login.component';
|
||||
import * as EventSource from 'eventsource';
|
||||
import { environment } from './../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-controls',
|
||||
@ -346,14 +349,31 @@ export class ControlsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
requeue() {
|
||||
if (sessionStorage.getItem('isSpectator') === 'true' ||
|
||||
sessionStorage.getItem('partyId') === null) {
|
||||
let partyId = sessionStorage.getItem('partyId');
|
||||
if (sessionStorage.getItem('isSpectator') === 'true' || partyId === null) {
|
||||
this.gameService.send({ message: 'GAME_REQUEUE' });
|
||||
} else {
|
||||
sessionStorage.setItem('requeueRequested', 'true');
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login']);
|
||||
});
|
||||
let queueCallback = new EventSource(`${environment.API_URL_PARTY}/${partyId}/queue`);
|
||||
queueCallback.onmessage = msg => {
|
||||
let queueMsg = JSON.parse(msg.data);
|
||||
if (queueMsg.queuePosition) {
|
||||
// go to login page, reuse the same EventSource
|
||||
LoginComponent.queueCallback = queueCallback;
|
||||
sessionStorage.setItem('queuePosition', queueMsg.queuePosition);
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login']);
|
||||
});
|
||||
} else if (queueMsg.requeue) {
|
||||
console.log(`ready to join game! Joining round ${queueMsg.requeue}`);
|
||||
queueCallback.close();
|
||||
this.processRequeue(queueMsg.requeue);
|
||||
} else {
|
||||
console.log('Error: unrecognized message ' + msg.data);
|
||||
}
|
||||
}
|
||||
queueCallback.onerror = msg => {
|
||||
console.log('Error showing queue position: ' + JSON.stringify(msg.data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,9 @@ import { Component, OnInit, OnDestroy, NgZone } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Meta } from '@angular/platform-browser';
|
||||
import { GameService } from './game.service';
|
||||
import { LoginComponent } from '../login/login.component';
|
||||
import * as EventSource from 'eventsource';
|
||||
import { environment } from './../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-game',
|
||||
@ -111,14 +114,31 @@ export class GameComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
requeue() {
|
||||
if (sessionStorage.getItem('isSpectator') === 'true' ||
|
||||
sessionStorage.getItem('partyId') === null) {
|
||||
let partyId = sessionStorage.getItem('partyId');
|
||||
if (sessionStorage.getItem('isSpectator') === 'true' || partyId === null) {
|
||||
this.gameService.send({ message: 'GAME_REQUEUE' });
|
||||
} else {
|
||||
sessionStorage.setItem('requeueRequested', 'true');
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login']);
|
||||
});
|
||||
let queueCallback = new EventSource(`${environment.API_URL_PARTY}/${partyId}/queue`);
|
||||
queueCallback.onmessage = msg => {
|
||||
let queueMsg = JSON.parse(msg.data);
|
||||
if (queueMsg.queuePosition) {
|
||||
// go to login page, reuse the same EventSource
|
||||
LoginComponent.queueCallback = queueCallback;
|
||||
sessionStorage.setItem('queuePosition', queueMsg.queuePosition);
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login']);
|
||||
});
|
||||
} else if (queueMsg.requeue) {
|
||||
console.log(`ready to join game! Joining round ${queueMsg.requeue}`);
|
||||
queueCallback.close();
|
||||
this.processRequeue(queueMsg.requeue);
|
||||
} else {
|
||||
console.log('Error: unrecognized message ' + msg.data);
|
||||
}
|
||||
}
|
||||
queueCallback.onerror = msg => {
|
||||
console.log('Error showing queue position: ' + JSON.stringify(msg.data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, NgZone, HostBinding, Injectable } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, NgZone, HostBinding, Injectable } from '@angular/core';
|
||||
import { Meta } from '@angular/platform-browser';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
@ -14,13 +14,13 @@ import { Player } from '../game/player/player';
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
export class LoginComponent implements OnInit, OnDestroy {
|
||||
pane: PaneType = sessionStorage.getItem('username') === null ? 'left' : 'right';
|
||||
username: string;
|
||||
party: string;
|
||||
queuePosition: number;
|
||||
player = new Player('PLAYER NAME HERE', 'none', '#FFFFFF');
|
||||
queueCallback: EventSource;
|
||||
static queueCallback: EventSource;
|
||||
isFullDevice: boolean = !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
|
||||
constructor(
|
||||
@ -39,8 +39,7 @@ export class LoginComponent implements OnInit {
|
||||
|
||||
this.meta.addTag({name: 'viewport', content: `width=${viewWidth}, height=${viewHeight}, initial-scale=1.0`}, true);
|
||||
|
||||
this.route.params.subscribe( params =>
|
||||
{
|
||||
this.route.params.subscribe( params => {
|
||||
sessionStorage.setItem("jwt", params['jwt']);
|
||||
});
|
||||
if (sessionStorage.getItem('jwt')) {
|
||||
@ -52,15 +51,21 @@ export class LoginComponent implements OnInit {
|
||||
this.player.name = this.username;
|
||||
}
|
||||
|
||||
if (sessionStorage.getItem('partyId') !== null &&
|
||||
sessionStorage.getItem('requeueRequested') === 'true') {
|
||||
sessionStorage.removeItem('requeueRequested');
|
||||
this.party = sessionStorage.getItem('partyId');
|
||||
console.log(`User already associated with party ${this.party}, entering queue`);
|
||||
this.enterQueue();
|
||||
// If a player has participated in a game and requeued and the next round is full, they will be redirected back to the login page.
|
||||
// Re-use the EventSource initiated on the game page, but change the onMessage() function to match the context of this page
|
||||
var queuePosition = sessionStorage.getItem('queuePosition');
|
||||
if (queuePosition) {
|
||||
sessionStorage.removeItem('queuePosition')
|
||||
console.log(`User already associated with party, entering queue`);
|
||||
this.setQueueOnMessage();
|
||||
this.showQueue(queuePosition);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.cancelQueue();
|
||||
}
|
||||
|
||||
loginGoogle() {
|
||||
window.location.href = `http://${environment.API_URL_AUTH}/auth-service/GoogleAuth`;
|
||||
}
|
||||
@ -107,9 +112,9 @@ export class LoginComponent implements OnInit {
|
||||
|
||||
if (data.gameState !== 'OPEN') {
|
||||
if (this.party === null) {
|
||||
if (data.gameState === 'FULL')
|
||||
alert('All games are full! Try again in a few seconds.');
|
||||
else
|
||||
if (data.gameState === 'FULL')
|
||||
alert('All games are full! Try again in a few seconds.');
|
||||
else
|
||||
alert('Game has already begun! Try again later.');
|
||||
} else {
|
||||
this.enterQueue();
|
||||
@ -140,7 +145,7 @@ export class LoginComponent implements OnInit {
|
||||
let ngZone = this.ngZone;
|
||||
let router = this.router;
|
||||
try {
|
||||
let party: any = await this.http.post(`${environment.API_URL_PARTY}/create`, '', { responseType: 'json' }).toPromise();
|
||||
let party: any = await this.http.post(`${environment.API_URL_PARTY}/create`, '', { responseType: 'json' }).toPromise();
|
||||
|
||||
console.log(`Created round with id=${party}`);
|
||||
sessionStorage.setItem('isSpectator', 'true');
|
||||
@ -158,36 +163,44 @@ export class LoginComponent implements OnInit {
|
||||
this.pane = 'center';
|
||||
}
|
||||
|
||||
enterQueue() {
|
||||
console.log(`enering queue for party ${this.party}`);
|
||||
if (this.queueCallback)
|
||||
this.queueCallback.close();
|
||||
this.queueCallback = new EventSource(`${environment.API_URL_PARTY}/${this.party}/queue`);
|
||||
this.queueCallback.onmessage = msg => {
|
||||
setQueueOnMessage() {
|
||||
LoginComponent.queueCallback.onmessage = msg => {
|
||||
let queueMsg = JSON.parse(msg.data);
|
||||
if (queueMsg.queuePosition) {
|
||||
this.ngZone.run(() => {
|
||||
this.queuePosition = queueMsg.queuePosition;
|
||||
console.log(`Still waiting in queue at position ${this.queuePosition}`);
|
||||
this.pane = 'queue';
|
||||
});
|
||||
this.showQueue(queueMsg.queuePosition);
|
||||
} else if (queueMsg.requeue) {
|
||||
console.log(`ready to join game! Joining round ${queueMsg.requeue}`);
|
||||
this.queueCallback.close();
|
||||
LoginComponent.queueCallback.close();
|
||||
this.joinRoundById(queueMsg.requeue);
|
||||
} else {
|
||||
console.log('Error: unrecognized message ' + msg.data);
|
||||
console.log('Error: unrecognized message ' + msg.data);
|
||||
}
|
||||
}
|
||||
this.queueCallback.onerror = msg => {
|
||||
}
|
||||
|
||||
enterQueue() {
|
||||
console.log(`enering queue for party ${this.party}`);
|
||||
if (LoginComponent.queueCallback)
|
||||
LoginComponent.queueCallback.close();
|
||||
LoginComponent.queueCallback = new EventSource(`${environment.API_URL_PARTY}/${this.party}/queue`);
|
||||
this.setQueueOnMessage();
|
||||
LoginComponent.queueCallback.onerror = msg => {
|
||||
console.log('Error showing queue position: ' + JSON.stringify(msg.data));
|
||||
}
|
||||
}
|
||||
|
||||
showQueue(queuePosition) {
|
||||
this.ngZone.run(() => {
|
||||
this.queuePosition = queuePosition;
|
||||
console.log(`Still waiting in queue at position ${this.queuePosition}`);
|
||||
this.pane = 'queue';
|
||||
});
|
||||
}
|
||||
|
||||
cancelQueue() {
|
||||
if (this.queueCallback)
|
||||
if (LoginComponent.queueCallback)
|
||||
try {
|
||||
this.queueCallback.close();
|
||||
LoginComponent.queueCallback.close();
|
||||
this.pane = 'right';
|
||||
} catch (ignore) {
|
||||
}
|
||||
|
@ -371,8 +371,18 @@ public class GameRound implements Runnable {
|
||||
broadcastPlayerList();
|
||||
|
||||
long start = System.nanoTime();
|
||||
updatePlayerStats();
|
||||
lifecycleCallbacks.forEach(c -> c.gameEnding());
|
||||
try {
|
||||
ManagedScheduledExecutorService exec = InitialContext.doLookup("java:comp/DefaultManagedScheduledExecutorService");
|
||||
exec.submit(() -> {
|
||||
updatePlayerStats();
|
||||
});
|
||||
exec.submit(() -> {
|
||||
lifecycleCallbacks.forEach(c -> c.gameEnding());
|
||||
});
|
||||
} catch (NamingException e) {
|
||||
log("Unable to perform post game processing");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Wait for 5 seconds, but subtract the amount of time it took to update player stats
|
||||
long nanoWait = TimeUnit.SECONDS.toNanos(5) - (System.nanoTime() - start);
|
||||
|
@ -11,18 +11,13 @@ public class OutboundMessage {
|
||||
public final Player[] playerlist;
|
||||
|
||||
public PlayerList(Set<Player> players) {
|
||||
if (players.size() > 0) {
|
||||
// Send players in proper order, padding out empty slots with "Bot Player"
|
||||
playerlist = new Player[Player.MAX_PLAYERS];
|
||||
for (Player p : players)
|
||||
playerlist[p.playerNum] = p;
|
||||
for (int i = 0; i < Player.MAX_PLAYERS; i++)
|
||||
if (playerlist[i] == null)
|
||||
playerlist[i] = new Player("", "Bot Player", (short) i, 0, 0);
|
||||
} else {
|
||||
// If no players are in the game yet, do not show all bot players
|
||||
playerlist = new Player[0];
|
||||
}
|
||||
// Send players in proper order, padding out empty slots with "Bot Player"
|
||||
playerlist = new Player[Player.MAX_PLAYERS];
|
||||
for (Player p : players)
|
||||
playerlist[p.playerNum] = p;
|
||||
for (int i = 0; i < Player.MAX_PLAYERS; i++)
|
||||
if (playerlist[i] == null)
|
||||
playerlist[i] = new Player("", "Bot Player", (short) i, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user