mirror of
https://github.com/OpenLiberty/liberty-bikes.git
synced 2025-03-13 11:36:43 +08:00
Merge pull request #148 from aguibert/singleParty-fixes
Bug fixes from testing on 10/15
This commit is contained in:
commit
33eaf14720
@ -5,7 +5,7 @@
|
||||
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="build/classes/java/main"/>
|
||||
|
@ -357,7 +357,8 @@ export class ControlsComponent implements OnInit, OnDestroy {
|
||||
).toPromise();
|
||||
this.processRequeue(nextRoundID);
|
||||
} else {
|
||||
let queueCallback = new EventSourcePolyfill(`${environment.API_URL_PARTY}/${partyId}/queue`, {});
|
||||
let playerId = sessionStorage.getItem('userId');
|
||||
let queueCallback = new EventSourcePolyfill(`${environment.API_URL_PARTY}/${partyId}/queue?playerId=${playerId}`, {});
|
||||
queueCallback.onmessage = msg => {
|
||||
let queueMsg = JSON.parse(msg.data);
|
||||
if (queueMsg.queuePosition) {
|
||||
|
@ -367,7 +367,8 @@ export class GameComponent implements OnInit, OnDestroy {
|
||||
this.processRequeue(nextRoundID);
|
||||
}
|
||||
} else {
|
||||
let queueCallback = new EventSourcePolyfill(`${environment.API_URL_PARTY}/${partyId}/queue`, {});
|
||||
let playerId = sessionStorage.getItem('userId');
|
||||
let queueCallback = new EventSourcePolyfill(`${environment.API_URL_PARTY}/${partyId}/queue?playerId=${playerId}`, {});
|
||||
queueCallback.onmessage = msg => {
|
||||
let queueMsg = JSON.parse(msg.data);
|
||||
if (queueMsg.queuePosition) {
|
||||
@ -455,6 +456,11 @@ export class GameComponent implements OnInit, OnDestroy {
|
||||
this.waitingSub = this.waitingTimer.subscribe((t) => {
|
||||
if (this.waitCard) {
|
||||
this.waitCard.bodyString = `${seconds - t}`;
|
||||
// If we have gotten down to -2, a connection was probably interrupted
|
||||
if (-1 > (seconds - t)) {
|
||||
this.waitingSub.unsubscribe();
|
||||
this.connectionInterrupted();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -484,13 +490,17 @@ export class GameComponent implements OnInit, OnDestroy {
|
||||
|
||||
verifyOpen() {
|
||||
if (!this.gameService.isOpen()) {
|
||||
console.log('GameService socket not open');
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login']);
|
||||
});
|
||||
this.connectionInterrupted();
|
||||
}
|
||||
}
|
||||
|
||||
connectionInterrupted() {
|
||||
alert('Connection to game-service interrrupted. Re-directing to login page.');
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login']);
|
||||
});
|
||||
}
|
||||
|
||||
addBorder(x, y, w, h) {
|
||||
let shape: Shape = new Shape();
|
||||
shape.shadow = new Shadow(Obstacle.COLOR, 0, 0, 20);
|
||||
|
@ -24,6 +24,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
player = new Player();
|
||||
isFullDevice: boolean = !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
isQuickPlayAllowed: boolean = this.isFullDevice;
|
||||
isSingleParty: boolean = false;
|
||||
isGoogleConfigured: boolean = false;
|
||||
isGithubConfigured: boolean = false;
|
||||
isTwitterConfigured: boolean = false;
|
||||
@ -71,7 +72,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
this.showQueue(queuePosition);
|
||||
}
|
||||
|
||||
this.checkForQuickPlay();
|
||||
this.checkForSingleParty();
|
||||
this.checkSsoOptions();
|
||||
}
|
||||
|
||||
@ -109,32 +110,36 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
if (data.indexOf('GitHubAuth') > -1) {
|
||||
this.isGithubConfigured = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async checkForQuickPlay() {
|
||||
if (this.isQuickPlayAllowed) {
|
||||
console.log('Quick play is supported -- skipping party service check');
|
||||
return;
|
||||
async checkForSingleParty() {
|
||||
if (this.isSingleParty) {
|
||||
return;
|
||||
}
|
||||
|
||||
let data: any = await this.http.get(`${environment.API_URL_PARTY}/describe`).toPromise();
|
||||
if (data == null) {
|
||||
console.log('WARNING: Unable to contact party service to determine if quick play is allowed');
|
||||
return;
|
||||
console.log('WARNING: Unable to contact party service to determine if single party mode is enabled');
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isSingleParty === true) {
|
||||
console.log('Quick play is supported');
|
||||
this.ngZone.run(() => {
|
||||
this.isQuickPlayAllowed = true;
|
||||
});
|
||||
console.log('Single party mode enabled');
|
||||
this.party = data.partyId;
|
||||
this.ngZone.run(() => {
|
||||
this.isSingleParty = true;
|
||||
});
|
||||
} else {
|
||||
console.log('Quick play is NOT supported');
|
||||
console.log('Single party mode disabled');
|
||||
}
|
||||
}
|
||||
|
||||
async quickJoin() {
|
||||
if (this.isSingleParty) {
|
||||
this.joinParty();
|
||||
return;
|
||||
}
|
||||
// First get an unstarted round ID
|
||||
let roundID = await this.http.get(`${environment.API_URL_GAME_ROUND}/available`, { responseType: 'text' }).toPromise();
|
||||
// Then join the round
|
||||
@ -248,7 +253,8 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
if (LoginComponent.queueCallback) {
|
||||
LoginComponent.queueCallback.close();
|
||||
}
|
||||
LoginComponent.queueCallback = new EventSourcePolyfill(`${environment.API_URL_PARTY}/${this.party}/queue`, {});
|
||||
let playerId = sessionStorage.getItem('userId');
|
||||
LoginComponent.queueCallback = new EventSourcePolyfill(`${environment.API_URL_PARTY}/${this.party}/queue?playerId=${playerId}`, {});
|
||||
this.setQueueOnMessage();
|
||||
LoginComponent.queueCallback.onerror = msg => {
|
||||
console.log('Error showing queue position: ' + JSON.stringify(msg.data));
|
||||
|
@ -6,7 +6,7 @@
|
||||
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="build/classes/java/main"/>
|
||||
|
@ -521,7 +521,7 @@ public class GameRound implements Runnable {
|
||||
// Give players a 10s grace period before they are removed from a finished game
|
||||
if (exec != null)
|
||||
exec.schedule(() -> {
|
||||
for (Session s : clients.keySet())
|
||||
for (Session s : new HashSet<Session>(clients.keySet()))
|
||||
removeClient(s);
|
||||
}, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
@ -44,8 +44,8 @@ public class Party {
|
||||
return this.currentRound;
|
||||
}
|
||||
|
||||
public void enqueueClient(SseEventSink sink, Sse sse) {
|
||||
queue.add(sink, sse);
|
||||
public void enqueueClient(String playerId, SseEventSink sink, Sse sse) {
|
||||
queue.add(playerId, sink, sse);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.libertybikes.game.party;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
@ -15,15 +16,18 @@ public class PartyQueue {
|
||||
|
||||
private final ConcurrentLinkedDeque<QueuedClient> waitingPlayers = new ConcurrentLinkedDeque<>();
|
||||
private final Party party;
|
||||
private int queueCounter = 0, firstClient = 0;
|
||||
|
||||
public PartyQueue(Party p) {
|
||||
this.party = p;
|
||||
}
|
||||
|
||||
public void add(SseEventSink sink, Sse sse) {
|
||||
QueuedClient client = new QueuedClient(sink, sse);
|
||||
party.log("Adding client " + client.queueNumber + " into the queue in position " + client.queuePosition());
|
||||
public void add(String playerId, SseEventSink sink, Sse sse) {
|
||||
QueuedClient client = new QueuedClient(playerId, sink, sse);
|
||||
// If this client was already in the queue, remove them and add them at the end
|
||||
if (waitingPlayers.removeFirstOccurrence(client)) {
|
||||
party.log("Removed client " + playerId + " from queue before adding at end");
|
||||
}
|
||||
party.log("Adding client " + playerId + " into the queue in position " + client.queuePosition());
|
||||
waitingPlayers.add(client);
|
||||
if (party.getCurrentRound().isOpen())
|
||||
promoteClients();
|
||||
@ -38,7 +42,6 @@ public class PartyQueue {
|
||||
QueuedClient first = waitingPlayers.pollFirst();
|
||||
if (first != null) {
|
||||
first.promoteToGame(newRound.id);
|
||||
firstClient++;
|
||||
}
|
||||
}
|
||||
for (QueuedClient client : waitingPlayers)
|
||||
@ -53,27 +56,35 @@ public class PartyQueue {
|
||||
}
|
||||
|
||||
private class QueuedClient {
|
||||
private final int queueNumber;
|
||||
private final String playerId;
|
||||
private final SseEventSink sink;
|
||||
private final Sse sse;
|
||||
|
||||
public QueuedClient(SseEventSink sink, Sse sse) {
|
||||
public QueuedClient(String playerId, SseEventSink sink, Sse sse) {
|
||||
this.playerId = playerId;
|
||||
this.sink = sink;
|
||||
this.sse = sse;
|
||||
this.queueNumber = PartyQueue.this.queueCounter++;
|
||||
}
|
||||
|
||||
public int queuePosition() {
|
||||
return this.queueNumber - PartyQueue.this.firstClient + 1;
|
||||
int position = 1;
|
||||
for (QueuedClient c : PartyQueue.this.waitingPlayers) {
|
||||
if (this.equals(c))
|
||||
break;
|
||||
else
|
||||
position++;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
public void notifyPosition() {
|
||||
int position = queuePosition();
|
||||
OutboundSseEvent event = sse.newEventBuilder()
|
||||
.mediaType(MediaType.APPLICATION_JSON_TYPE)
|
||||
.data(new OutboundMessage.QueuePosition(queuePosition()))
|
||||
.data(new OutboundMessage.QueuePosition(position))
|
||||
.build();
|
||||
sink.send(event);
|
||||
party.log("Notified queued client " + queueNumber + " who is currently at position " + queuePosition());
|
||||
party.log("Notified queued client " + playerId + " who is currently at position " + position);
|
||||
}
|
||||
|
||||
public void promoteToGame(String roundId) {
|
||||
@ -82,13 +93,25 @@ public class PartyQueue {
|
||||
.data(new OutboundMessage.RequeueGame(roundId))
|
||||
.build();
|
||||
sink.send(event);
|
||||
party.log("Promoted queued client " + queueNumber + " into round " + roundId);
|
||||
party.log("Promoted queued client " + playerId + " into round " + roundId);
|
||||
close();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
sink.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof QueuedClient))
|
||||
return false;
|
||||
QueuedClient other = (QueuedClient) obj;
|
||||
return Objects.equals(this.playerId, other.playerId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -21,6 +22,7 @@ import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.sse.Sse;
|
||||
@ -64,6 +66,7 @@ public class PartyService {
|
||||
public Map<String, Object> describe() {
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("isSingleParty", this.isSingleParty);
|
||||
config.put("partyId", allParties.values().iterator().next().id);
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -109,10 +112,13 @@ public class PartyService {
|
||||
@GET
|
||||
@Path("/{partyId}/queue")
|
||||
@Produces(MediaType.SERVER_SENT_EVENTS)
|
||||
public void joinQueue(@PathParam("partyId") String partyId, @Context SseEventSink sink, @Context Sse sse) {
|
||||
public void joinQueue(@PathParam("partyId") String partyId,
|
||||
@QueryParam("playerId") String playerId,
|
||||
@Context SseEventSink sink, @Context Sse sse) {
|
||||
Objects.requireNonNull(playerId, "Client attemted to queue for a party without providing playerId");
|
||||
Party p = getParty(partyId);
|
||||
if (p != null)
|
||||
p.enqueueClient(sink, sse);
|
||||
p.enqueueClient(playerId, sink, sse);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="build/classes/java/main"/>
|
||||
|
Loading…
Reference in New Issue
Block a user