Make games rejoinable
1. Disconnect websocket connection before connecting 2. store playerInfo when hosting a game to reuse it when rejoining
This commit is contained in:
parent
618102dd67
commit
544e0b22c5
@ -12,6 +12,10 @@ class PlayerInfo {
|
|||||||
required this.passphrase,
|
required this.passphrase,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
factory PlayerInfo.empty() {
|
||||||
|
return const PlayerInfo(playerID: null, lobbyID: null, passphrase: null);
|
||||||
|
}
|
||||||
|
|
||||||
factory PlayerInfo.fromJson(Map<String, dynamic> json) {
|
factory PlayerInfo.fromJson(Map<String, dynamic> json) {
|
||||||
final playerid = UuidValue.fromString(json['playerID']);
|
final playerid = UuidValue.fromString(json['playerID']);
|
||||||
final lobbyid = UuidValue.fromString(json['lobbyID']);
|
final lobbyid = UuidValue.fromString(json['lobbyID']);
|
||||||
@ -21,11 +25,24 @@ class PlayerInfo {
|
|||||||
playerID: playerid, lobbyID: lobbyid, passphrase: passphrase);
|
playerID: playerid, lobbyID: lobbyid, passphrase: passphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() {
|
||||||
'playerID': playerID,
|
String? pid;
|
||||||
'lobbyID': lobbyID,
|
String? lid;
|
||||||
|
|
||||||
|
if (playerID != null) {
|
||||||
|
pid = playerID.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lobbyID != null) {
|
||||||
|
lid = lobbyID.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'playerID': pid,
|
||||||
|
'lobbyID': lid,
|
||||||
'passphrase': passphrase,
|
'passphrase': passphrase,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void store() async {
|
void store() async {
|
||||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
@ -42,7 +59,7 @@ class PlayerInfo {
|
|||||||
await prefs.setBool("contains", false);
|
await prefs.setBool("contains", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<PlayerInfo?> get() async {
|
static Future<PlayerInfo?> get() async {
|
||||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
var contains = prefs.getBool("contains");
|
var contains = prefs.getBool("contains");
|
||||||
var playerID = prefs.getString("playerID");
|
var playerID = prefs.getString("playerID");
|
||||||
|
@ -16,7 +16,6 @@ import 'package:web_socket_channel/web_socket_channel.dart';
|
|||||||
|
|
||||||
class ServerConnection {
|
class ServerConnection {
|
||||||
WebSocketChannel? channel;
|
WebSocketChannel? channel;
|
||||||
late bool wasConnected = false;
|
|
||||||
Stream broadcast = const Stream.empty();
|
Stream broadcast = const Stream.empty();
|
||||||
|
|
||||||
static final ServerConnection _instance = ServerConnection._internal();
|
static final ServerConnection _instance = ServerConnection._internal();
|
||||||
@ -42,6 +41,7 @@ class ServerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void connect(String playerID, lobbyID, String? passphrase) {
|
void connect(String playerID, lobbyID, String? passphrase) {
|
||||||
|
disconnectExistingConnection();
|
||||||
channel = WebSocketChannel.connect(Uri.parse(config.getWebsocketURL()));
|
channel = WebSocketChannel.connect(Uri.parse(config.getWebsocketURL()));
|
||||||
|
|
||||||
send(
|
send(
|
||||||
@ -62,6 +62,8 @@ class ServerConnection {
|
|||||||
void disconnectExistingConnection() {
|
void disconnectExistingConnection() {
|
||||||
if (channel == null) return;
|
if (channel == null) return;
|
||||||
channel!.sink.close();
|
channel!.sink.close();
|
||||||
|
|
||||||
|
broadcast = const Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleIncomingData(dynamic data) {
|
void handleIncomingData(dynamic data) {
|
||||||
|
@ -27,9 +27,6 @@ class _HostGameWidgetState extends State<HostGameWidget> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
registerResponse = hostPrivateGame();
|
registerResponse = hostPrivateGame();
|
||||||
registerResponse.then((value) {
|
|
||||||
value?.store();
|
|
||||||
});
|
|
||||||
connectToWebsocket(registerResponse);
|
connectToWebsocket(registerResponse);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
@ -70,6 +67,7 @@ class _HostGameWidgetState extends State<HostGameWidget> {
|
|||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
// We wait for our opponent to connect
|
// We wait for our opponent to connect
|
||||||
if (state.opponentConnected) {
|
if (state.opponentConnected) {
|
||||||
|
snapshot.data?.store();
|
||||||
context.pushReplacement('/game', extra: chessGameArgs);
|
context.pushReplacement('/game', extra: chessGameArgs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -135,7 +133,8 @@ class _HostGameWidgetState extends State<HostGameWidget> {
|
|||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
log(response.body);
|
log(response.body);
|
||||||
return PlayerInfo.fromJson(jsonDecode(response.body));
|
var info = PlayerInfo.fromJson(jsonDecode(response.body));
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:mchess/api/register.dart';
|
import 'package:mchess/api/register.dart';
|
||||||
|
import 'package:mchess/connection/ws_connection.dart';
|
||||||
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
||||||
import 'package:mchess/pages/chess_game.dart';
|
import 'package:mchess/pages/chess_game.dart';
|
||||||
import 'package:mchess/utils/config.dart' as config;
|
import 'package:mchess/utils/config.dart' as config;
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
class LobbySelector extends StatefulWidget {
|
class LobbySelector extends StatefulWidget {
|
||||||
const LobbySelector({super.key});
|
const LobbySelector({super.key});
|
||||||
@ -25,13 +25,6 @@ class _LobbySelectorState extends State<LobbySelector> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
|
||||||
final playerID = prefs.getString("playerID");
|
|
||||||
final lobbyID = prefs.getString("lobbyID");
|
|
||||||
final passphrase = prefs.getString("passphrase");
|
|
||||||
log("lobbyID: $lobbyID and playerID: $playerID and passphrase: $passphrase");
|
|
||||||
});
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -57,6 +50,9 @@ class _LobbySelectorState extends State<LobbySelector> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> buildJoinOrHostDialog(BuildContext context) {
|
Future<void> buildJoinOrHostDialog(BuildContext context) {
|
||||||
|
//TODO: find a better place to disconnect old websocket connection
|
||||||
|
ServerConnection.getInstance().disconnectExistingConnection();
|
||||||
|
|
||||||
return showDialog<void>(
|
return showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@ -170,13 +166,28 @@ class _LobbySelectorState extends State<LobbySelector> {
|
|||||||
Future<PlayerInfo?> joinPrivateGame(BuildContext context) async {
|
Future<PlayerInfo?> joinPrivateGame(BuildContext context) async {
|
||||||
http.Response response;
|
http.Response response;
|
||||||
|
|
||||||
// server expects us to send the passphrase
|
var existingInfo = await PlayerInfo.get();
|
||||||
var info = PlayerInfo(
|
|
||||||
|
log("lobbyID: ${existingInfo?.lobbyID} and playerID: ${existingInfo?.playerID} and passphrase: ${existingInfo?.passphrase}");
|
||||||
|
|
||||||
|
PlayerInfo info;
|
||||||
|
if (existingInfo?.passphrase == phraseController.text) {
|
||||||
|
// We have player info for this exact passphrase
|
||||||
|
info = PlayerInfo(
|
||||||
|
playerID: existingInfo?.playerID,
|
||||||
|
lobbyID: existingInfo?.lobbyID,
|
||||||
|
passphrase: phraseController.text);
|
||||||
|
} else {
|
||||||
|
info = PlayerInfo(
|
||||||
playerID: null, lobbyID: null, passphrase: phraseController.text);
|
playerID: null, lobbyID: null, passphrase: phraseController.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
var decodedInfo = jsonEncode(info);
|
||||||
|
log("decodedInfo: $decodedInfo");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await http.post(Uri.parse(config.getJoinURL()),
|
response = await http.post(Uri.parse(config.getJoinURL()),
|
||||||
body: jsonEncode(info), headers: {"Accept": "application/json"});
|
body: decodedInfo, headers: {"Accept": "application/json"});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
|
|
||||||
@ -206,6 +217,7 @@ class _LobbySelectorState extends State<LobbySelector> {
|
|||||||
|
|
||||||
if (response.statusCode == HttpStatus.ok) {
|
if (response.statusCode == HttpStatus.ok) {
|
||||||
var info = PlayerInfo.fromJson(jsonDecode(response.body));
|
var info = PlayerInfo.fromJson(jsonDecode(response.body));
|
||||||
|
info.store();
|
||||||
log('Player info received from server: ');
|
log('Player info received from server: ');
|
||||||
log('lobbyID: ${info.lobbyID}');
|
log('lobbyID: ${info.lobbyID}');
|
||||||
log('playerID: ${info.playerID}');
|
log('playerID: ${info.playerID}');
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const prodURL = 'chess.sw-gross.de:9999';
|
const prodURL = 'chess.sw-gross.de:9999';
|
||||||
const debugURL = 'localhost:8080';
|
const debugURL = 'localhost:8080';
|
||||||
|
|
||||||
const useDbgUrl = false;
|
const useDbgUrl = true;
|
||||||
|
|
||||||
String getHostURL() {
|
String getHostURL() {
|
||||||
var prot = 'https';
|
var prot = 'https';
|
||||||
|
Loading…
Reference in New Issue
Block a user