feat: Implémentation connexion REST initiale pour le multijoueur

Implémente les modifications nécessaires côté client Android pour établir une connexion de base avec l'API REST du serveur multijoueur.

Changements principaux :
- Ajout de la permission INTERNET dans AndroidManifest.xml.
- Correction de l'URL de base (BASE_URL) dans ApiClient pour utiliser HTTPS.
- Déclaration de MultiplayerActivity dans AndroidManifest.xml.
- Correction de l'appel API createOrJoinGame (ApiService et MultiplayerActivity) pour envoyer le playerId dans le corps de la requête (@Body) au lieu d'un paramètre de requête (@Query).
- Utilisation d'un UUID aléatoire temporaire comme playerId côté client.
- Mise à jour de GameStateResponse.java pour inclure targetScore et corriger la logique getMyScore/getOpponentScore.
This commit is contained in:
Augustin ROUX 2025-04-05 10:45:09 +02:00
parent 1977d2de3f
commit 1dc439c186
7 changed files with 72 additions and 3593 deletions

View File

@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application
@ -25,6 +26,12 @@
</intent-filter>
</activity>
<activity
android:name=".MultiplayerActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Best2048" />
<service
android:name=".NotificationService"
android:enabled="true"

View File

@ -22,6 +22,7 @@ import java.util.Objects; // Pour la comparaison d'ID
import legion.muyue.best2048.data.GameInfo;
import legion.muyue.best2048.data.GameStateResponse;
import legion.muyue.best2048.data.MoveRequest;
import legion.muyue.best2048.data.PlayerIdRequest;
import legion.muyue.best2048.network.ApiClient;
import legion.muyue.best2048.network.ApiService;
import retrofit2.Call;
@ -97,23 +98,36 @@ public class MultiplayerActivity extends AppCompatActivity {
private void initMultiplayerGame() {
showLoading(true);
statusTextMulti.setText("Recherche d'une partie...");
// TODO: Implémenter la logique d'obtention de myPlayerId
// Appel API pour créer/rejoindre
apiService.createOrJoinGame(myPlayerId).enqueue(new Callback<GameInfo>() {
// !!! IMPORTANT: Générer un ID unique ici !!!
// myPlayerId = "Player1_Temp"; // À REMPLACER
myPlayerId = java.util.UUID.randomUUID().toString(); // Exemple simple d'ID unique
Log.i(TAG, "Utilisation du Player ID: " + myPlayerId);
// Crée l'objet pour le corps de la requête
PlayerIdRequest requestBody = new PlayerIdRequest(myPlayerId);
// Utilise requestBody dans l'appel API
apiService.createOrJoinGame(requestBody).enqueue(new Callback<GameInfo>() {
@Override
public void onResponse(@NonNull Call<GameInfo> call, @NonNull Response<GameInfo> response) {
if (response.isSuccessful() && response.body() != null) {
GameInfo gameInfo = response.body();
currentGameId = gameInfo.getGameId();
// TODO: Déterminer opponentPlayerId basé sur gameInfo.getPlayer1Id/getPlayer2Id
opponentPlayerId = myPlayerId.equals(gameInfo.getPlayer1Id()) ? gameInfo.getPlayer2Id() : gameInfo.getPlayer1Id();
Log.i(TAG, "Partie rejointe/créée: ID=" + currentGameId + ", Adversaire=" + opponentPlayerId);
statusTextMulti.setText("Partie trouvée ! ID: " + currentGameId);
// Détermine correctement l'ID de l'adversaire
if (myPlayerId.equals(gameInfo.getPlayer1Id())) {
opponentPlayerId = gameInfo.getPlayer2Id();
} else {
opponentPlayerId = gameInfo.getPlayer1Id(); // Si je suis P2, l'autre est P1
}
Log.i(TAG, "Partie rejointe/créée: ID=" + currentGameId + ", Moi=" + myPlayerId + ", Adversaire=" + opponentPlayerId);
statusTextMulti.setText("Partie trouvée ! ID: " + currentGameId.substring(0, 8) + "..."); // Affiche début ID
fetchGameState(); // Récupère l'état initial
} else {
Log.e(TAG, "Erreur création/rejoindre partie: " + response.code());
handleNetworkError("Impossible de créer ou rejoindre une partie.");
handleNetworkError("Impossible de créer ou rejoindre une partie (Code: " + response.code() + ")");
}
}

View File

@ -19,6 +19,12 @@ public class GameStateResponse {
private String winnerId;
@SerializedName("status")
private String status;
@SerializedName("player1Id") // Ajoute ce champ s'il manque
private String player1Id;
@SerializedName("player2Id") // Ajoute ce champ s'il manque
private String player2Id;
@SerializedName("targetScore") // Ajoute ce champ
private int targetScore;
// --- Getters ---
public String getGameId() { return gameId; }
@ -29,19 +35,30 @@ public class GameStateResponse {
public boolean isGameOver() { return isGameOver; }
public String getWinnerId() { return winnerId; }
public String getStatus() { return status; }
public String getPlayer1Id() { return player1Id; }
public String getPlayer2Id() { return player2Id; }
public int getTargetScore() { return targetScore; }
// --- Méthode utilitaire pour obtenir le score de l'adversaire ---
public int getOpponentScore(String myPlayerId) {
if (myPlayerId == null) return 0;
// TODO: Logique pour déterminer qui est player1/player2 basée sur l'API
// Supposons pour l'instant que player1 est l'hôte, player2 l'invité
// Et que l'API nous donne l'ID de player1/player2 dans un autre champ (ex: GameInfo)
// Placeholder:
return (myPlayerId.equals("player1_placeholder")) ? player2Score : player1Score;
public int getOpponentScore(String myActualPlayerId) {
if (myActualPlayerId == null) return 0;
if (myActualPlayerId.equals(player1Id)) {
// Si je suis P1, le score de l'adversaire est P2
return player2Score;
} else if (myActualPlayerId.equals(player2Id)) {
// Si je suis P2, le score de l'adversaire est P1
return player1Score;
}
return 0; // Mon ID ne correspond à aucun joueur ?
}
public int getMyScore(String myPlayerId) {
if (myPlayerId == null) return 0;
// Placeholder:
return (myPlayerId.equals("player1_placeholder")) ? player1Score : player2Score;
public int getMyScore(String myActualPlayerId) {
if (myActualPlayerId == null) return 0;
if (myActualPlayerId.equals(player1Id)) {
return player1Score;
} else if (myActualPlayerId.equals(player2Id)) {
return player2Score;
}
return 0; // Mon ID ne correspond à aucun joueur ?
}
}

View File

@ -0,0 +1,10 @@
package legion.muyue.best2048.data;
public class PlayerIdRequest {
private String playerId;
public PlayerIdRequest(String playerId) {
this.playerId = playerId;
}
// Pas besoin de getters si seulement utilisé pour l'envoi avec Gson
}

View File

@ -8,7 +8,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClient {
// URL de base de votre API serveur
private static final String BASE_URL = "http://best2048.legion-muyue.fr/api/"; // Assurez-vous que le chemin est correct
private static final String BASE_URL = "https://best2048.legion-muyue.fr/api/";
private static Retrofit retrofit = null;

View File

@ -9,6 +9,7 @@ import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query; // Pour éventuels paramètres de création
import legion.muyue.best2048.data.PlayerIdRequest;
public interface ApiService {
@ -18,14 +19,14 @@ public interface ApiService {
* @return Informations sur la partie créée/rejointe.
*/
@POST("games") // Endpoint: /api/games (POST)
Call<GameInfo> createOrJoinGame(@Query("playerId") String playerId); // Exemple avec ID joueur en query param
Call<GameInfo> createOrJoinGame(@Body PlayerIdRequest playerIdRequest);
/**
* Récupère l'état actuel complet d'une partie spécifique.
* @param gameId L'identifiant unique de la partie.
* @return L'état actuel du jeu.
*/
@GET("games/{gameId}") // Endpoint: /api/games/{gameId} (GET)
@GET("games/{gameId}")
Call<GameStateResponse> getGameState(@Path("gameId") String gameId);
/**
@ -35,7 +36,7 @@ public interface ApiService {
* @param moveRequest L'objet contenant la direction du mouvement et l'ID du joueur.
* @return Le nouvel état du jeu après application du mouvement (ou un message d'erreur).
*/
@POST("games/{gameId}/moves") // Endpoint: /api/games/{gameId}/moves (POST)
@POST("games/{gameId}/moves")
Call<GameStateResponse> makeMove(@Path("gameId") String gameId, @Body MoveRequest moveRequest);
}

3570
sortie.txt

File diff suppressed because it is too large Load Diff