Skip to content
Snippets Groups Projects
Commit 672b1f60 authored by Sander Østrem Fagernes's avatar Sander Østrem Fagernes
Browse files

Resolve "Adapt frontend find game to #36"

parent df9cd571
No related branches found
No related tags found
1 merge request!42Resolve "Adapt frontend find game to #36"
package com.game.tankwars;
import com.badlogic.gdx.Net;
public interface Callback {
// This interface defines two methods to handle the different responses from an HTTP request
// Method to handle a successful response
// Takes a String parameter containing the response body
void onResult(String result);
void onResult(Net.HttpResponse result);
// Method to handle a failed response
// Takes a Throwable parameter containing the exception that caused the failure
......
......@@ -41,7 +41,7 @@ public class HTTPRequestHandler implements Net.HttpResponseListener {
* @param httpResponse The {@link HttpResponse} with the HTTP response values.
*/
public void handleHttpResponse(HttpResponse httpResponse) {
callback.onResult(httpResponse.getResultAsString());
callback.onResult(httpResponse);
}
/**
......
package com.game.tankwars;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.Net.HttpResponse;
import com.game.tankwars.controller.LeaderboardController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ReceiverHandler implements Net.HttpResponseListener {
// This class handles the response from the HTTP request
// It uses the callback interface to handle the different responses
// Declare a Callback instance to handle the different responses
private final Callback callback;
public static final int MAX_RETRIES = 5;
public static final String PROTOCOL = "http";
public static final String HOST = "localhost";
public static final int PORT = 3000;
// Constructor to initialize the Callback instance
public ReceiverHandler(Callback callback) {
this.callback = callback;
}
// Method called if the request was cancelled
public void cancelled() {
System.out.println("cancelled");
}
// Method called if the request failed
public void failed(Throwable t) {
// Call the onFailed() method of the Callback instance
callback.onFailed(t);
// Print the error to the console
System.err.println(t);
}
// Method called if the request was successful and a response was received
public void handleHttpResponse(HttpResponse httpResponse) {
// Call the onResult() method of the Callback instance
// Pass in the response body as a String
callback.onResult(httpResponse.getResultAsString());
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package com.game.tankwars.controller;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.net.HttpRequestBuilder;
import com.badlogic.gdx.net.HttpStatus;
import com.badlogic.gdx.scenes.scene2d.EventListener;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
......@@ -33,7 +34,7 @@ public class FindGameController {
private final FindGameScreen screen;
private final Stage stage;
private final TextField gamePinField;
private final TextButton joinLobbyButton, createLobbyButton, cancelButton;
private final TextButton joinLobbyButton, cancelButton;
private final Button backButton;
private final Label gamePinWaitingLabel;
......@@ -46,22 +47,19 @@ public class FindGameController {
/**
* TODO: Ensure that user is logged in -> e.g. auth method in Auth/Utils class
* Sets the event listeners of the buttons and the text field of the FindGameScreen,
* and allows for transitioning to MainMenuScreen and to GameScreen. Handles communication
* with server to create, join and leave a lobbies.
*/
public FindGameController(final TankWarsGame tankWarsGame, FindGameScreen screen,
TextField gamePinField, TextButton joinLobbyButton,
TextButton createLobbyButton, Button backButton,
TextButton cancelButton, Label gamePinWaitingLabel,
final Stage stage) {
Button backButton, TextButton cancelButton,
Label gamePinWaitingLabel, final Stage stage) {
this.tankWarsGame = tankWarsGame;
this.screen = screen;
this.gamePinField = gamePinField;
this.joinLobbyButton = joinLobbyButton;
this.createLobbyButton = createLobbyButton;
this.backButton = backButton;
this.cancelButton = cancelButton;
this.gamePinWaitingLabel = gamePinWaitingLabel;
......@@ -77,12 +75,26 @@ public class FindGameController {
}
};
defineEventListeners();
setGamePinFieldFilter();
defineEventListenersAndFilters();
setMainListeners();
}
private void defineEventListeners() {
/**
* Game pin field only allows for integers
* and the first integer must be greater than 0
*/
private void setGamePinFieldFilter() {
gamePinField.setTextFieldFilter(new TextField.TextFieldFilter() {
@Override
public boolean acceptChar(TextField textField, char c) {
return Character.isDigit(c) &&
(!textField.getText().isEmpty() || (textField.getText().isEmpty() && c != '0'));
}
});
}
private void defineEventListenersAndFilters() {
/*
* Transition back to MainMenuScreen
*/
......@@ -142,17 +154,6 @@ public class FindGameController {
}
};
/*
* Create new lobby and display waiting window.
* Poll server for lobby status to know when to transition to game screen.
*/
createLobbyButtonInputListener = new InputListener() {
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
createLobby();
return true;
}
};
/*
* Exit from waiting window and render normal FindGameScreen
......@@ -172,7 +173,6 @@ public class FindGameController {
gamePinField.addListener(gamePinFieldInputListener);
gamePinField.addListener(gamePinFieldClickListener);
joinLobbyButton.addListener(joinLobbyButtonInputListener);
createLobbyButton.addListener(createLobbyButtonInputListener);
}
public void removeMainListeners() {
......@@ -180,7 +180,6 @@ public class FindGameController {
gamePinField.removeListener(gamePinFieldInputListener);
gamePinField.removeListener(gamePinFieldClickListener);
joinLobbyButton.removeListener(joinLobbyButtonInputListener);
createLobbyButton.removeListener(createLobbyButtonInputListener);
}
public void setWaitingWindowListeners() {
......@@ -191,20 +190,20 @@ public class FindGameController {
cancelButton.removeListener(cancelButtonInputListener);
}
/**
* Send HTTP request to create a new lobby.
* On success, a waiting window is shown, and polling for
* the lobby status is initiated.
* Send HTTP request to join a lobby using the game pin in the text field.
* On success, poll the server for the fill status of the lobby.
*/
private void createLobby() {
private void joinLobby() {
lobbyId = gamePinField.getText();
new HTTPRequestHandler(new Callback() {
@Override
public void onResult(String result) {
try {
LobbyId lobbyIdClass = new Json().fromJson(LobbyId.class, result);
lobbyId = lobbyIdClass.getLobbyId();
public void onResult(Net.HttpResponse response) {
HttpStatus status = response.getStatus();
if (status.getStatusCode() == HttpStatus.SC_CREATED ||
status.getStatusCode() == HttpStatus.SC_OK) {
removeMainListeners();
setWaitingWindowListeners();
......@@ -212,18 +211,19 @@ public class FindGameController {
screen.showWaitingWindow();
checkLobbyStatus();
} catch (SerializationException e) {
System.err.println("Invalid HTTP response on create lobby");
} else {
System.err.println("Join lobby request failed with status code " +
status.getStatusCode());
}
}
@Override
public void onFailed(Throwable t) {
System.err.println("Create lobby request failed:\n" + t);
System.err.println("Join lobby request failed:\n" + t);
}
}, new HttpRequestBuilder()
.newRequest()
.url(String.format("%s/lobby/create", ConfigReader.getProperty("backend.url")))
.url(String.format("%s/lobby/%s/join", ConfigReader.getProperty("backend.url"), lobbyId))
.method(Net.HttpMethods.POST)
.header("Content-Type", "application/json")
.content(String.format("{\"userId\": \"%s\"}", CurrentUser.getCurrentUser().getUser().id))
......@@ -234,31 +234,29 @@ public class FindGameController {
/**
* Send HTTP request while waiting for lobby to fill,
* polling for the lobby's fill status with a set backoff period between requests.
* Transition to game screen when lobby is full.
* Transition to game screen when lobby is full and set gameId in CurrentUser.
*/
private void checkLobbyStatus() {
if (lobbyId == null) return;
new HTTPRequestHandler(new Callback() {
@Override
public void onResult(String result) {
try {
LobbyStatus lobbyStatus = new Json().fromJson(LobbyStatus.class, result);
if (lobbyStatus.isFull()) {
Gdx.app.postRunnable(gameScreenTransition);
} else if (lobbyId != null) {
System.out.println("Awaiting opponent...");
try {
Thread.sleep(1500);
if (lobbyId != null) checkLobbyStatus();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
exitLobby();
}
public void onResult(Net.HttpResponse response) {
HttpStatus status = response.getStatus();
if (status.getStatusCode() == HttpStatus.SC_OK && !response.getResultAsString().isEmpty()) {
CurrentUser.getCurrentUser().setGameId(response.getResultAsString());
Gdx.app.postRunnable(gameScreenTransition);
} else {
System.out.println("Awaiting opponent...");
try {
Thread.sleep(1500);
if (lobbyId != null) checkLobbyStatus();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
exitLobby();
}
} catch (SerializationException e) {
System.err.println("Invalid HTTP response on check lobby status");
exitLobby();
}
}
......@@ -269,8 +267,7 @@ public class FindGameController {
}
}, new HttpRequestBuilder()
.newRequest()
.url(String.format("%s/lobby/%s/status",
ConfigReader.getProperty("backend.url"), lobbyId))
.url(String.format("%s/game/%s", ConfigReader.getProperty("backend.url"), lobbyId))
.method(Net.HttpMethods.GET)
.build())
.sendRequest();
......@@ -281,9 +278,11 @@ public class FindGameController {
* is not yet full. Hide the waiting window.
*/
private void exitLobby() {
if (lobbyId == null) return;
new HTTPRequestHandler(new Callback() {
@Override
public void onResult(String result) {
public void onResult(Net.HttpResponse response) {
removeWaitingWindowListeners();
setMainListeners();
......@@ -302,40 +301,7 @@ public class FindGameController {
}
}, new HttpRequestBuilder()
.newRequest()
.url(String.format("%s/lobby/%s/leave",
ConfigReader.getProperty("backend.url"), lobbyId))
.method(Net.HttpMethods.POST)
.header("Content-Type", "application/json")
.content(String.format("{\"userId\": \"%s\"}", CurrentUser.getCurrentUser().getUser().id))
.build())
.sendRequest();
}
/**
* Send HTTP request to join a lobby using the game pin in the text field.
* On success, transition to game screen.
*/
private void joinLobby() {
new HTTPRequestHandler(new Callback() {
@Override
public void onResult(String result) {
try {
new Json().fromJson(LobbyId.class, result);
Gdx.app.postRunnable(gameScreenTransition);
} catch (SerializationException e) {
System.out.println(result);
}
}
@Override
public void onFailed(Throwable t) {
System.err.println("Join lobby request failed:\n" + t);
}
}, new HttpRequestBuilder()
.newRequest()
.url(String.format("%s/lobby/%s/join",
ConfigReader.getProperty("backend.url"), gamePinField.getText()))
.url(String.format("%s/lobby/%s/leave", ConfigReader.getProperty("backend.url"), lobbyId))
.method(Net.HttpMethods.POST)
.header("Content-Type", "application/json")
.content(String.format("{\"userId\": \"%s\"}", CurrentUser.getCurrentUser().getUser().id))
......
package com.game.tankwars.controller;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.net.HttpRequestBuilder;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
......@@ -11,7 +10,6 @@ import com.badlogic.gdx.utils.Json;
import com.game.tankwars.Callback;
import com.game.tankwars.ConfigReader;
import com.game.tankwars.HTTPRequestHandler;
import com.game.tankwars.ReceiverHandler;
import com.game.tankwars.TankWarsGame;
import com.game.tankwars.model.User;
import com.game.tankwars.view.LeaderboardScreen;
......@@ -50,10 +48,11 @@ public class LeaderboardController {
new HTTPRequestHandler(
new Callback() {
@Override
public void onResult(String result) {
public void onResult(Net.HttpResponse response) {
Json json = new Json();
// Convert the response body to an Array of User objects using the Json instance
Array<User> leaderboardUsers = json.fromJson(Array.class, User.class, result);
Array<User> leaderboardUsers = json.fromJson(Array.class, User.class, response.getResultAsString());
screen.setLeaderBoard(leaderboardUsers);
}
......@@ -64,7 +63,7 @@ public class LeaderboardController {
},
new HttpRequestBuilder()
.newRequest()
.url(String.format("%s/highscores", ConfigReader.getProperty("backend.url")))
.url(String.format("%s/highscore", ConfigReader.getProperty("backend.url")))
.method(Net.HttpMethods.GET)
.build())
.sendRequest();
......
......@@ -15,12 +15,10 @@ import com.badlogic.gdx.utils.Json;
import com.game.tankwars.Callback;
import com.game.tankwars.ConfigReader;
import com.game.tankwars.HTTPRequestHandler;
import com.game.tankwars.ReceiverHandler;
import com.game.tankwars.ResourceManager;
import com.game.tankwars.TankWarsGame;
import com.game.tankwars.model.CurrentUser;
import com.game.tankwars.model.User;
import com.game.tankwars.view.GameScreen;
import com.game.tankwars.view.MainMenuScreen;
......@@ -106,9 +104,9 @@ public class LoginController {
public void fetchUser(final String username) {
new HTTPRequestHandler(new Callback() {
@Override
public void onResult(String result) {
public void onResult(Net.HttpResponse response) {
Json json = new Json();
User user = json.fromJson(User.class, result);
User user = json.fromJson(User.class, response.getResultAsString());
currentUser.setUser(user);
Gdx.app.postRunnable(mainMenuScreenTransition);
}
......
......@@ -2,8 +2,9 @@ package com.game.tankwars.model;
public class CurrentUser {
User user;
private User user;
private static CurrentUser INSTANCE;
private String gameId;
private CurrentUser() {
}
......@@ -17,10 +18,14 @@ public class CurrentUser {
public User getUser() {
return user;
}
public String getGameId() { return gameId; }
public void setUser(User user) {
this.user = user;
}
public void setGameId(String gameId) { this.gameId = gameId; }
@Override
public String toString() {
return "CurrentUser is: " + user ;
......
......@@ -58,8 +58,6 @@ public class FindGameScreen implements Screen {
TextButton joinLobbyButton = new TextButton("Join lobby",
skin.get("default", TextButton.TextButtonStyle.class));
joinLobbyButton.setDisabled(true);
TextButton createLobbyButton = new TextButton("Create lobby",
skin.get("default", TextButton.TextButtonStyle.class));
Button backButton = new Button(skin.get("default", Button.ButtonStyle.class));
//--- Layout
......@@ -87,14 +85,12 @@ public class FindGameScreen implements Screen {
headerTable.add(findGameLabel).expandX();
rightTable.add(headerTable).fillX().height(stage.getHeight() / 4f);
rightTable.row().expand(1, 0);
rightTable.row().expand(1, 1);
rightTable.add(gamePinLabel).width(2 * rw / 3f).bottom().padLeft(10);
rightTable.row().expand(1, 2);
rightTable.row().expand(1, 0);
rightTable.add(gamePinField).width(2 * rw / 3f).height(42).top();
rightTable.row().expand(1, 1);
rightTable.add(joinLobbyButton).width(2 * rw / 3f).height(28);
rightTable.row().expand(1, 4);
rightTable.add(createLobbyButton).width(2 * rw / 3f).height(28);
rightTable.add(joinLobbyButton).width(2 * rw / 3f).height(28);
rootTable.add(leftGroup).width(lw).height(stage.getHeight());
rootTable.add(rightTable).expandX().height(stage.getHeight());
......@@ -126,8 +122,7 @@ public class FindGameScreen implements Screen {
stage.addActor(layoutGroup);
new FindGameController(tankWarsGame, this, gamePinField,
joinLobbyButton, createLobbyButton,
backButton, cancelButton, gamePinWaitingLabel, stage);
joinLobbyButton, backButton, cancelButton, gamePinWaitingLabel, stage);
}
public void showWaitingWindow() { layoutGroup.addActor(windowTable); }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment