Spaces:
Sleeping
Sleeping
| # 🐛 Bug Debug: Notification Doublons | |
| **Date:** 3 octobre 2025, 19h10 | |
| **Issue:** Notifications en doublon (une en anglais, une localisée) | |
| **Status:** 🔍 INVESTIGATION | |
| --- | |
| ## 🔍 Problème Signalé | |
| **Symptômes:** | |
| - Une action génère **deux notifications** | |
| - En interface non-anglaise (FR, ZH-TW): | |
| - Notification 1: Version anglaise | |
| - Notification 2: Version localisée | |
| - Effet: Doublons visuels dans la file de notifications | |
| --- | |
| ## ✅ Corrections Déjà Appliquées | |
| ### 1. Notification de Training (game.js ligne 724) | |
| ```javascript | |
| // AVANT: | |
| this.showNotification(`Training ${unitType}`, 'success'); | |
| // APRÈS: | |
| // Notification sent by server (localized) | |
| ``` | |
| **Status:** ✅ FIXED | |
| ### 2. Notification de Building Placement (game.js ligne 697) | |
| ```javascript | |
| // AVANT: | |
| this.showNotification(`Building ${this.buildingMode}`, 'success'); | |
| // APRÈS: | |
| // Notification sent by server (localized) | |
| ``` | |
| **Status:** ✅ FIXED | |
| ### 3. Notification de Requirement Error (game.js ligne 713-717) | |
| ```javascript | |
| // AVANT: | |
| if (!this.hasBuilding(requiredBuilding)) { | |
| this.showNotification( | |
| `⚠️ Need ${requiredBuilding.replace('_', ' ').toUpperCase()} to train ${unitType}!`, | |
| 'error' | |
| ); | |
| return; | |
| } | |
| // APRÈS: | |
| // Requirement check done server-side | |
| // Server will send localized error notification if needed | |
| ``` | |
| **Status:** ✅ FIXED | |
| --- | |
| ## 🔎 Sources Potentielles Restantes | |
| ### Notifications Côté Client (game.js) | |
| Vérifier chaque `showNotification` pour voir si le serveur envoie aussi la même : | |
| #### ✅ SAFE (Purement locales, pas de doublon serveur) | |
| - Connection errors (ligne 150, 156) ← UI only | |
| - AI analysis (ligne 296, 317) ← Client-initiated | |
| - Nuke UI (ligne 464, 503, 514) ← UI feedback | |
| - Attack feedback (ligne 482) ← Local feedback | |
| - Movement feedback (ligne 490, 764) ← Local feedback | |
| - Control groups (ligne 550, 558, 575, 585, 598) ← Local UI | |
| - Select all (ligne 666) ← Local UI | |
| - Building mode (ligne 679) ← Local UI | |
| - Building cancelled (ligne 470) ← Local UI | |
| #### ⚠️ POTENTIAL DUPLICATES (À vérifier) | |
| Aucune détectée après review | |
| ### Notifications Côté Serveur (app.py) | |
| Liste des broadcasts côté serveur : | |
| 1. **Low power** (ligne 535-540) - Serveur uniquement ✅ | |
| 2. **Insufficient credits - unit** (ligne 1074-1081) - Serveur uniquement ✅ | |
| 3. **Unit training** (ligne 1108-1113) - Serveur uniquement (client supprimé) ✅ | |
| 4. **Unit requires building** (ligne 1120-1128) - Serveur uniquement (client supprimé) ✅ | |
| 5. **Insufficient credits - building** (ligne 1152-1159) - Serveur uniquement ✅ | |
| 6. **Building placed** (ligne 1175-1180) - Serveur uniquement (client supprimé) ✅ | |
| 7. **Nuke launch** (ligne 1223-1228, 1242-1247) - Serveur uniquement ✅ | |
| --- | |
| ## 🧪 Tests à Effectuer | |
| ### Test 1: Unit Training | |
| ``` | |
| 1. Changer langue en Français | |
| 2. Cliquer sur "Infantry" button | |
| 3. Observer notifications | |
| ATTENDU: 1 seule notification en français | |
| ACTUEL: À tester | |
| ``` | |
| ### Test 2: Building Placement | |
| ``` | |
| 1. Changer langue en 繁體中文 | |
| 2. Placer un Power Plant | |
| 3. Observer notifications | |
| ATTENDU: 1 seule notification en chinois | |
| ACTUEL: À tester | |
| ``` | |
| ### Test 3: Insufficient Credits | |
| ``` | |
| 1. Changer langue en Français | |
| 2. Dépenser tous les crédits | |
| 3. Tenter de construire | |
| 4. Observer notifications | |
| ATTENDU: 1 seule notification en français | |
| ACTUEL: À tester | |
| ``` | |
| --- | |
| ## 💡 Hypothèses Alternatives | |
| ### Hypothèse 1: `broadcast()` envoie deux fois? | |
| **Check:** Vérifier si `broadcast()` n'est pas appelé deux fois dans `handle_command` | |
| **Code à vérifier:** | |
| ```python | |
| # app.py ligne 1108-1113 | |
| message = LOCALIZATION.translate(player_language, "notification.unit_training", unit=unit_name) | |
| await self.broadcast({ | |
| "type": "notification", | |
| "message": message, | |
| "level": "success" | |
| }) | |
| ``` | |
| **Test:** Ajouter un `print()` avant chaque `broadcast()` pour tracer les appels | |
| ### Hypothèse 2: Client reçoit message deux fois via WebSocket? | |
| **Check:** Vérifier si le message handler `onmessage` n'est pas enregistré deux fois | |
| **Code à vérifier:** | |
| ```javascript | |
| // game.js ligne 146-158 | |
| this.ws.onmessage = (event) => { | |
| const data = JSON.parse(event.data); | |
| if (data.type === 'notification') { | |
| this.showNotification(data.message, data.level || 'info'); | |
| } | |
| ``` | |
| **Test:** Ajouter un `console.log()` dans `onmessage` pour compter les messages | |
| ### Hypothèse 3: Deux connexions WebSocket actives? | |
| **Check:** Vérifier si le client n'ouvre pas deux connexions | |
| **Code à vérifier:** | |
| ```javascript | |
| // game.js ligne 102-111 | |
| connectWebSocket() { | |
| this.ws = new WebSocket(wsUrl); | |
| // ... | |
| } | |
| ``` | |
| **Test:** Vérifier dans Chrome DevTools → Network → WS combien de connexions | |
| ### Hypothèse 4: Notification en anglais vient d'une autre source? | |
| **Check:** Chercher si du texte anglais hardcodé existe ailleurs | |
| **Search:** | |
| ```bash | |
| grep -r "Training" web/static/ | |
| grep -r "Building" web/static/ | |
| grep -r "Insufficient" web/static/ | |
| ``` | |
| --- | |
| ## 🔧 Debug Commands | |
| ### Chercher toutes les notifications côté client | |
| ```bash | |
| cd /home/luigi/rts/web | |
| grep -n "showNotification" static/game.js | |
| ``` | |
| ### Chercher toutes les notifications côté serveur | |
| ```bash | |
| grep -n "notification" app.py | |
| ``` | |
| ### Tracer les WebSocket messages | |
| Ajouter dans `game.js` ligne 147: | |
| ```javascript | |
| this.ws.onmessage = (event) => { | |
| const data = JSON.parse(event.data); | |
| console.log('WS Message:', data.type, data); // ← DEBUG | |
| if (data.type === 'notification') { | |
| console.log('Notification received:', data.message); // ← DEBUG | |
| this.showNotification(data.message, data.level || 'info'); | |
| } | |
| ``` | |
| ### Tracer les broadcasts serveur | |
| Ajouter dans `app.py` ligne 437: | |
| ```python | |
| async def broadcast(self, message: dict): | |
| """Send message to all connected clients""" | |
| if message.get('type') == 'notification': | |
| print(f'[BROADCAST] Notification: {message.get("message")}') # ← DEBUG | |
| dead_connections = [] | |
| for ws in self.active_connections: | |
| try: | |
| await ws.send_json(message) | |
| ``` | |
| --- | |
| ## 📊 Status | |
| **Client-side notifications:** ✅ Cleaned up (doublons supprimés) | |
| **Server-side notifications:** ✅ Verified (pas de doublons détectés) | |
| **WebSocket handling:** ⏳ À vérifier | |
| **Browser DevTools:** ⏳ À tester | |
| **Next Step:** Tester localement avec traces de debug | |
| --- | |
| ## 🎯 Solution Finale (À confirmer après tests) | |
| Si le problème persiste après les fixes appliqués, ajouter des traces de debug pour identifier la source exacte du doublon. | |
| **Commandes de test:** | |
| ```bash | |
| cd /home/luigi/rts/web | |
| python app.py | |
| # Dans un autre terminal: | |
| # Ouvrir http://localhost:7860 | |
| # Ouvrir Chrome DevTools (F12) | |
| # Onglet Console | |
| # Tester training/building | |
| # Observer les messages | |
| ``` | |
| --- | |
| *Document créé: 3 octobre 2025, 19h10* | |
| *Status: Investigation en cours* | |