125 lines
No EOL
3.9 KiB
Dart
125 lines
No EOL
3.9 KiB
Dart
// ===========================================================================
|
|
// FILE: lib/services/multiplayer_service.dart
|
|
// ===========================================================================
|
|
|
|
import 'dart:math';
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:share_plus/share_plus.dart';
|
|
|
|
class MultiplayerService {
|
|
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
|
final FirebaseAuth _auth = FirebaseAuth.instance;
|
|
|
|
CollectionReference get _gamesCollection => _firestore.collection('games');
|
|
|
|
Future<String> createGameRoom(int boardRadius, String hostName, String shapeName, bool isTimeMode, {bool isPublic = true}) async {
|
|
String roomCode = _generateRoomCode();
|
|
int randomSeed = Random().nextInt(1000000);
|
|
|
|
await _gamesCollection.doc(roomCode).set({
|
|
'status': 'waiting',
|
|
'radius': boardRadius,
|
|
'createdAt': FieldValue.serverTimestamp(),
|
|
'players': ['host'],
|
|
'turn': 'host',
|
|
'moves': [],
|
|
'seed': randomSeed,
|
|
'hostName': hostName,
|
|
'hostUid': _auth.currentUser?.uid, // NUOVO: Salviamo l'ID univoco del creatore
|
|
'guestName': '',
|
|
'shape': shapeName,
|
|
'timeMode': isTimeMode,
|
|
'isPublic': isPublic,
|
|
'p1_reaction': null,
|
|
'p2_reaction': null,
|
|
'p1_rematch': false,
|
|
'p2_rematch': false,
|
|
});
|
|
|
|
return roomCode;
|
|
}
|
|
|
|
Future<Map<String, dynamic>?> joinGameRoom(String roomCode, String guestName) async {
|
|
DocumentSnapshot doc = await _gamesCollection.doc(roomCode).get();
|
|
|
|
if (doc.exists && doc['status'] == 'waiting') {
|
|
await _gamesCollection.doc(roomCode).update({
|
|
'status': 'playing',
|
|
'players': FieldValue.arrayUnion(['guest']),
|
|
'guestName': guestName,
|
|
});
|
|
return doc.data() as Map<String, dynamic>;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Stream<QuerySnapshot> getPublicRooms() {
|
|
return _gamesCollection
|
|
.where('status', isEqualTo: 'waiting')
|
|
.where('isPublic', isEqualTo: true)
|
|
.snapshots();
|
|
}
|
|
|
|
void shareInviteLink(String roomCode) {
|
|
String message = "Ehi! Giochiamo a TetraQ? 🎮\n\n"
|
|
"Clicca su questo link per entrare direttamente in stanza:\n"
|
|
"tetraq://join?code=$roomCode\n\n"
|
|
"Oppure apri l'app e inserisci manualmente il codice: $roomCode";
|
|
Share.share(message);
|
|
}
|
|
|
|
Stream<DocumentSnapshot> listenToRoom(String roomCode) {
|
|
return _gamesCollection.doc(roomCode).snapshots();
|
|
}
|
|
|
|
String _generateRoomCode() {
|
|
const chars = 'ACDEFGHJKLMNPQRSTUVWXYZ2345679';
|
|
final random = Random();
|
|
return String.fromCharCodes(Iterable.generate(
|
|
5, (_) => chars.codeUnitAt(random.nextInt(chars.length)),
|
|
));
|
|
}
|
|
|
|
Future<void> sendReaction(String roomCode, bool isHost, String reaction) async {
|
|
try {
|
|
String prefix = isHost ? 'p1' : 'p2';
|
|
await _gamesCollection.doc(roomCode).update({
|
|
'${prefix}_reaction': reaction,
|
|
'${prefix}_reaction_time': FieldValue.serverTimestamp(),
|
|
});
|
|
} catch (e) {
|
|
debugPrint("Errore invio reazione: $e");
|
|
}
|
|
}
|
|
|
|
Future<void> requestRematch(String roomCode, bool isHost) async {
|
|
try {
|
|
String prefix = isHost ? 'p1' : 'p2';
|
|
await _gamesCollection.doc(roomCode).update({
|
|
'${prefix}_rematch': true,
|
|
});
|
|
} catch (e) {
|
|
debugPrint("Errore richiesta rivincita: $e");
|
|
}
|
|
}
|
|
|
|
Future<void> resetMatch(String roomCode, int newRadius, String newShape, int newSeed) async {
|
|
try {
|
|
await _gamesCollection.doc(roomCode).update({
|
|
'status': 'playing',
|
|
'moves': [],
|
|
'seed': newSeed,
|
|
'radius': newRadius,
|
|
'shape': newShape,
|
|
'p1_rematch': false,
|
|
'p2_rematch': false,
|
|
'p1_reaction': null,
|
|
'p2_reaction': null,
|
|
});
|
|
} catch (e) {
|
|
debugPrint("Errore reset partita: $e");
|
|
}
|
|
}
|
|
} |