diff --git a/backend/src/index.ts b/backend/src/index.ts index 840d77bf1c69d05f05a1c49ef9f3fa77da6f67b2..439a97f5c8047ba04e5539588ff51175f8f95773 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -26,7 +26,6 @@ app.listen(port, '0.0.0.0', () => { console.log(`Server started on port ${port}`); }); - // establish connection to firebase const admin = require('firebase-admin'); const serviceAccount = path.join(__dirname, '../..', 'keys', 'fb-key.json'); @@ -99,7 +98,10 @@ app.get('/highscores', async (req, res) => { if (querySnapshot.empty) { res.status(204).send('No highscores found'); } else { - const users = querySnapshot.docs.map((doc: any) => doc.data() as User); + const users = querySnapshot.docs.map((doc: any) => ({ + id: doc.id, + ...doc.data(), + })); res.status(200).send(users); } }); diff --git a/frontend/android/AndroidManifest.xml b/frontend/android/AndroidManifest.xml index 572e4823bb3fadb76c7237b528df66a740275ce0..a31d082ec1e82f0d323f663a815c40ac63b7c849 100644 --- a/frontend/android/AndroidManifest.xml +++ b/frontend/android/AndroidManifest.xml @@ -4,6 +4,7 @@ package="com.game.tankwars"> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> + <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" @@ -12,7 +13,8 @@ android:isGame="true" android:appCategory="game" android:label="@string/app_name" - tools:ignore="UnusedAttribute"> + tools:ignore="UnusedAttribute" + android:usesCleartextTraffic="true"> <activity android:name="com.game.tankwars.AndroidLauncher" android:label="@string/app_name" diff --git a/frontend/core/src/com/game/tankwars/Callback.java b/frontend/core/src/com/game/tankwars/Callback.java new file mode 100644 index 0000000000000000000000000000000000000000..700bde129e3c0f6c60e3c55f9c7b1cc368fa691c --- /dev/null +++ b/frontend/core/src/com/game/tankwars/Callback.java @@ -0,0 +1,13 @@ +package com.game.tankwars; + +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); + + // Method to handle a failed response + // Takes a Throwable parameter containing the exception that caused the failure + void onFailed(Throwable t); +} \ No newline at end of file diff --git a/frontend/core/src/com/game/tankwars/ReceiverHandler.java b/frontend/core/src/com/game/tankwars/ReceiverHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..e162baa86e8db900c064289c0fadbb304a44fcb0 --- /dev/null +++ b/frontend/core/src/com/game/tankwars/ReceiverHandler.java @@ -0,0 +1,45 @@ +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; + + // 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 diff --git a/frontend/core/src/com/game/tankwars/controller/LeaderboardController.java b/frontend/core/src/com/game/tankwars/controller/LeaderboardController.java new file mode 100644 index 0000000000000000000000000000000000000000..85becb0b976c1fb16dc86fd36df856b777235353 --- /dev/null +++ b/frontend/core/src/com/game/tankwars/controller/LeaderboardController.java @@ -0,0 +1,52 @@ +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.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.game.tankwars.Callback; +import com.game.tankwars.ReceiverHandler; +import com.game.tankwars.model.User; + +public class LeaderboardController { + Array<User> leaderboardUsers; + private int retries = 0; + + public void fetchLeaderboard() { + // Create a new instance of the Callback interface to handle the response + Callback callback = new Callback() { + // Method called if the response is successful + @Override + public void onResult(String leaderboard) { + // Create a new Json instance to parse the response body + Json json = new Json(); + // Convert the response body to an Array of User objects using the Json instance + leaderboardUsers = json.fromJson(Array.class, User.class, leaderboard); + } + // Method called if the response fails + @Override + public void onFailed(Throwable t){ + // Increment the number of retries + retries += 1; + } + }; + // Define the URL for the HTTP request + String url = "http://localhost:3000/highscores"; + // Create a new HttpRequest using the HttpRequestBuilder class + Net.HttpRequest httpRequest = new HttpRequestBuilder() + .newRequest() + .method(Net.HttpMethods.GET) + .url(url) + .build(); + // Send the HttpRequest and pass in the Callback instance to handle the response + Gdx.net.sendHttpRequest(httpRequest, new ReceiverHandler(callback)); + } + + public Array<User> getLeaderboard() { + if (retries < 5 && leaderboardUsers == null) { + fetchLeaderboard(); + } + return leaderboardUsers; + } +} diff --git a/frontend/core/src/com/game/tankwars/controller/MainMenuController.java b/frontend/core/src/com/game/tankwars/controller/MainMenuController.java index a655aad55d02a4e0a113690bd46a8ee6ee145602..f07836cb05399a96cf4dc90497d46a8e382615b7 100644 --- a/frontend/core/src/com/game/tankwars/controller/MainMenuController.java +++ b/frontend/core/src/com/game/tankwars/controller/MainMenuController.java @@ -7,6 +7,7 @@ import com.badlogic.gdx.utils.Array; import com.game.tankwars.TankWarsGame; import com.game.tankwars.model.MenuButton; import com.game.tankwars.view.GameScreen; +import com.game.tankwars.view.LeaderboardScreen; public class MainMenuController { @@ -41,11 +42,8 @@ public class MainMenuController { touchPos.y >= menuButton.getY() && touchPos.y <= menuButton.getY() + menuButton.getHeight()) { switch (i) { - case 0: - // TODO: Clear resource manager - tankWarsGame.setScreen(new GameScreen(tankWarsGame)); - break; - case 1: System.out.println("Leaderboard button: Not yet functional"); break; + case 0: tankWarsGame.setScreen(new GameScreen(tankWarsGame)); break; + case 1: tankWarsGame.setScreen(new LeaderboardScreen(tankWarsGame)); break; case 2: System.out.println("Settings button: Not yet functional"); break; case 3: System.out.println("Log out button: Not yet functional"); break; } diff --git a/frontend/core/src/com/game/tankwars/model/User.java b/frontend/core/src/com/game/tankwars/model/User.java new file mode 100644 index 0000000000000000000000000000000000000000..9b60990981d1baf0d0f14afacd8e4143954d1981 --- /dev/null +++ b/frontend/core/src/com/game/tankwars/model/User.java @@ -0,0 +1,41 @@ +package com.game.tankwars.model; + +public class User { + int games; + float highscore; + int losses; + public int wins; + public String username; + public String id; + + public User(int games, float highscore, int losses, int wins, String username, String id) { + this.games = games; + this.highscore = highscore; + this.losses = losses; + this.wins = wins; + this.username = username; + this.id = id; + } + + public User() { + // Initialize default values for the fields + games = 0; + highscore = 0.0f; + losses = 0; + wins = 0; + username = null; + id = null; + } + + @Override + public String toString() { + return "User {" + + "games=" + games + + ", highscore=" + highscore + + ", losses=" + losses + + ", wins=" + wins + + ", username='" + username + '\'' + + ", id='" + id + '\'' + + '}'; + } +} diff --git a/frontend/core/src/com/game/tankwars/view/LeaderboardScreen.java b/frontend/core/src/com/game/tankwars/view/LeaderboardScreen.java new file mode 100644 index 0000000000000000000000000000000000000000..62ce0e20958fd1064fac48625f4d19ace99e470e --- /dev/null +++ b/frontend/core/src/com/game/tankwars/view/LeaderboardScreen.java @@ -0,0 +1,96 @@ +package com.game.tankwars.view; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ScreenUtils; +import com.game.tankwars.TankWarsGame; +import com.game.tankwars.controller.LeaderboardController; +import com.game.tankwars.model.User; + +import java.awt.Label; + +public class LeaderboardScreen implements Screen { + + final TankWarsGame tankWarsGame; + OrthographicCamera camera; + SpriteBatch batch; + private BitmapFont font; + + //LibGDX have tables or something, should be investigated + Table table; + + private Array<User> leaderboardUsers; + LeaderboardController leaderboardController; + + + + public LeaderboardScreen (final TankWarsGame tankWarsGame) { + this.tankWarsGame = tankWarsGame; + camera = new OrthographicCamera(); + batch = new SpriteBatch(); + font = new BitmapFont(); + font.getData().setScale(3f); + font.setColor(Color.BLACK); + + leaderboardController = new LeaderboardController(); + } + + @Override + public void render(float delta) { + ScreenUtils.clear(255, 255, 255, 1); + int height = Gdx.graphics.getHeight() - 75; + batch.begin(); + leaderboardUsers = leaderboardController.getLeaderboard(); + + if (leaderboardUsers == null) { + font.draw(batch, "No connection", 50, height); + } + else if (leaderboardUsers.size > 0) { + for (User user : leaderboardUsers) { + font.draw(batch, user.username, (Gdx.graphics.getWidth() >> 1) - 300, height); + font.draw(batch, user.wins + "", (Gdx.graphics.getWidth() >> 1), height); + height = height - 75; + } + } + else { + font.draw(batch, "No users", 50, height); + } + batch.end(); + } + + @Override + public void dispose() { + + } + + @Override + public void show() { + + } + @Override + public void resize(int width, int height) { + + } + + @Override + public void pause() { + + } + + @Override + public void resume() { + + } + + @Override + public void hide() { + + } + +} diff --git a/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java b/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java index bbfe7f30361fe1c37fbc1d18bdd93b4cf6149a57..5f665eca1c8d107a7da082fbd28ae1af64cf14c4 100644 --- a/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java +++ b/frontend/core/src/com/game/tankwars/view/MainMenuScreen.java @@ -25,7 +25,6 @@ public class MainMenuScreen extends InputAdapter implements Screen { private final BitmapFont font; private final Viewport viewport; private final MainMenuController controller; - private final Sprite logo; private final Texture welcomeBox; private final Texture background;