From 605743c0d2c885102849814894a08b645c86720e Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 2 Jun 2023 23:28:40 +0200 Subject: [PATCH] Introduce api types and some changes. --- lib/api/move.dart | 32 +++++++++++++ lib/api/register.dart | 30 ++++++++++++ lib/chess_bloc/chess_bloc.dart | 12 ++++- lib/chess_bloc/chess_position.dart | 5 +- lib/connection/ws_connection.dart | 56 ++++++++++------------ lib/connection_cubit/connection_cubit.dart | 4 +- lib/models/models.dart | 17 ------- lib/pages/chess_game.dart | 6 ++- lib/pages/prepare_chess_game.dart | 10 ++-- lib/utils/chess_utils.dart | 12 +++++ 10 files changed, 124 insertions(+), 60 deletions(-) create mode 100644 lib/api/move.dart create mode 100644 lib/api/register.dart delete mode 100644 lib/models/models.dart diff --git a/lib/api/move.dart b/lib/api/move.dart new file mode 100644 index 0000000..c269ae4 --- /dev/null +++ b/lib/api/move.dart @@ -0,0 +1,32 @@ +class ApiMove { + final ApiCoordinate startSquare; + final ApiCoordinate endSquare; + + const ApiMove({ + required this.startSquare, + required this.endSquare, + }); + + factory ApiMove.fromJson(Map json) { + final startSquare = ApiCoordinate.fromJson(json['startSquare']); + final endSquare = ApiCoordinate.fromJson(json['endSquare']); + + return ApiMove(startSquare: startSquare, endSquare: endSquare); + } + + Map toJson() => + {'startSquare': startSquare, 'endSquare': endSquare}; +} + +class ApiCoordinate { + final int col; + final int row; + + const ApiCoordinate({required this.col, required this.row}); + + factory ApiCoordinate.fromJson(Map json) { + return ApiCoordinate(col: json['col'], row: json['row']); + } + + Map toJson() => {'col': col, 'row': row}; +} diff --git a/lib/api/register.dart b/lib/api/register.dart new file mode 100644 index 0000000..b423595 --- /dev/null +++ b/lib/api/register.dart @@ -0,0 +1,30 @@ +import 'package:uuid/uuid.dart'; + +class ResponseFromRegisteringGame { + final UuidValue playerID; + final UuidValue lobbyID; + + const ResponseFromRegisteringGame({ + required this.playerID, + required this.lobbyID, + }); + + factory ResponseFromRegisteringGame.fromJson(Map json) { + final playerid = UuidValue(json['playerID']); + final lobbyid = UuidValue(json['lobbyID']); + + return ResponseFromRegisteringGame(playerID: playerid, lobbyID: lobbyid); + } +} + +class WebsocketMessageIdentifyPlayer { + final String playerID; + final String lobbyID; + + const WebsocketMessageIdentifyPlayer({ + required this.playerID, + required this.lobbyID, + }); + + Map toJson() => {'lobbyID': lobbyID, 'playerID': playerID}; +} diff --git a/lib/chess_bloc/chess_bloc.dart b/lib/chess_bloc/chess_bloc.dart index 6285f7f..7426ef6 100644 --- a/lib/chess_bloc/chess_bloc.dart +++ b/lib/chess_bloc/chess_bloc.dart @@ -1,4 +1,7 @@ +import 'dart:convert'; + import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:mchess/api/move.dart'; import 'package:mchess/chess_bloc/chess_events.dart'; import 'package:mchess/chess_bloc/chess_position.dart'; import 'package:mchess/connection/ws_connection.dart'; @@ -62,8 +65,13 @@ class ChessBloc extends Bloc { void ownMoveHandler(OwnPieceMoved event, Emitter emit) { ChessPosition.getInstance().recordMove(event.startSquare, event.endSquare); - ServerConnection.getInstance().send( - 'mv ${event.startSquare.toString()} ${event.endSquare.toString()}'); + var start = ApiCoordinate( + col: event.startSquare.column, row: event.startSquare.row); + var end = + ApiCoordinate(col: event.endSquare.column, row: event.endSquare.row); + var move = ApiMove(startSquare: start, endSquare: end); + + ServerConnection.getInstance().send(jsonEncode(move)); } } diff --git a/lib/chess_bloc/chess_position.dart b/lib/chess_bloc/chess_position.dart index a25b9d7..6ee2c1f 100644 --- a/lib/chess_bloc/chess_position.dart +++ b/lib/chess_bloc/chess_position.dart @@ -64,7 +64,10 @@ class ChessPosition { } ChessPositionType get currentPosition => position; - ChessMove get lastMove => history.last; + ChessMove? get lastMove { + if (history.isEmpty) return null; + return history.last; + } void recordMove(ChessCoordinate from, ChessCoordinate to) { position[to] = position[from] ?? const ChessPiece.none(); diff --git a/lib/connection/ws_connection.dart b/lib/connection/ws_connection.dart index 51319a9..131733f 100644 --- a/lib/connection/ws_connection.dart +++ b/lib/connection/ws_connection.dart @@ -1,8 +1,11 @@ +import 'dart:convert'; import 'dart:developer'; import 'package:flutter/foundation.dart'; +import 'package:mchess/api/move.dart'; import 'package:mchess/chess_bloc/chess_bloc.dart'; import 'package:mchess/chess_bloc/chess_events.dart'; import 'package:mchess/chess_bloc/chess_position.dart'; +import 'package:mchess/api/register.dart'; import 'package:mchess/utils/chess_utils.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; @@ -31,7 +34,7 @@ class ServerConnection { counter++; } - void connect(String playerID) { + void connect(String playerID, lobbyID) { if (wasConnected) channel.sink.close(); if (kDebugMode) { @@ -41,7 +44,8 @@ class ServerConnection { channel = WebSocketChannel.connect(Uri.parse('wss://chess.sw-gross.de:8080')); } - send(playerID); + send(jsonEncode(WebsocketMessageIdentifyPlayer( + playerID: (playerID), lobbyID: (lobbyID)))); log(channel.closeCode.toString()); @@ -49,39 +53,27 @@ class ServerConnection { broadcast = channel.stream.asBroadcastStream(); - broadcast.listen((data) { - log("Data received:"); - log(data); + broadcast.listen(handleIncomingData); + } - var receivedString = data.toString(); - var splitString = receivedString.split(' '); + void handleIncomingData(dynamic data) { + log("Data received:"); + log(data); + var apiMove = ApiMove.fromJson(jsonDecode(data)); - if (splitString[0] == "cl") { - ChessColor onBottom = - splitString[1] == "white" ? ChessColor.white : ChessColor.black; - ChessBloc.getInstance().add(ColorDetermined(myColor: onBottom)); - return; - } +//Todo: Implement status messages +// e.g. to tell the client that both players connected, who is playing which color and so on - if (splitString[0] == "bd") { - if (splitString[1] == "init") ChessBloc.getInstance().add(InitBoard()); - } + var move = ChessMove.fromApiMove(apiMove); + if (move == ChessPosition.getInstance().lastMove) { + //This is our own move that got resent by the server. Do not process. + } else { + log('lastMove: from: ${ChessPosition.getInstance().lastMove?.from} to: ${ChessPosition.getInstance().lastMove?.to}'); + log('constructed move: from: ${move.from} to: ${move.to}'); + log('Move received : ${move.from.toAlphabetical()}->${move.to.toAlphabetical()}'); - if (splitString[0] == ('mv')) { - var startSquare = ChessCoordinate.fromString(splitString[1]); - var endSquare = ChessCoordinate.fromString(splitString[2]); - if (ChessMove(from: startSquare, to: endSquare) == - ChessPosition.getInstance().lastMove) { - //This is our own move that got resent by the server. Do not process. - } else { - log('lastMove: from: ${ChessPosition.getInstance().lastMove.from} to: ${ChessPosition.getInstance().lastMove.to}'); - log('constructed move: from: $startSquare to: $endSquare)}'); - log('Move received : ${startSquare.toAlphabetical()}:${endSquare.toAlphabetical()}'); - - ChessBloc.getInstance().add(OpponentPieceMoved( - startSquare: startSquare, endSquare: endSquare)); - } - } - }); + ChessBloc.getInstance() + .add(OpponentPieceMoved(startSquare: move.from, endSquare: move.to)); + } } } diff --git a/lib/connection_cubit/connection_cubit.dart b/lib/connection_cubit/connection_cubit.dart index 81bdde7..d925cb3 100644 --- a/lib/connection_cubit/connection_cubit.dart +++ b/lib/connection_cubit/connection_cubit.dart @@ -15,8 +15,8 @@ class ConnectionCubit extends Cubit { return _instance; } - void connect(String playerID) { - ServerConnection.getInstance().connect(playerID); + void connect(String playerID, lobbyID) { + ServerConnection.getInstance().connect(playerID, lobbyID); emit(ConnectionCubitState(true)); } } diff --git a/lib/models/models.dart b/lib/models/models.dart deleted file mode 100644 index ec6e9a5..0000000 --- a/lib/models/models.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:uuid/uuid.dart'; - -class ResponseFromRegisteringGame { - final UuidValue playerID; - - const ResponseFromRegisteringGame({ - required this.playerID, - }); - - factory ResponseFromRegisteringGame.fromJson(Map json) { - final uuid = UuidValue(json['playerID']); - - return ResponseFromRegisteringGame( - playerID: uuid, - ); - } -} diff --git a/lib/pages/chess_game.dart b/lib/pages/chess_game.dart index a42702d..a10d185 100644 --- a/lib/pages/chess_game.dart +++ b/lib/pages/chess_game.dart @@ -14,7 +14,8 @@ import 'package:uuid/uuid.dart'; class ChessGame extends StatefulWidget { final UuidValue playerID; - const ChessGame({required this.playerID, super.key}); + final UuidValue lobbyID; + const ChessGame({required this.playerID, required this.lobbyID, super.key}); @override State createState() => _ChessGameState(); @@ -24,7 +25,8 @@ class _ChessGameState extends State { @override void initState() { super.initState(); - ConnectionCubit.getInstance().connect(widget.playerID.uuid); + ConnectionCubit.getInstance() + .connect(widget.playerID.uuid, widget.lobbyID.uuid); } @override diff --git a/lib/pages/prepare_chess_game.dart b/lib/pages/prepare_chess_game.dart index 938847a..48f4843 100644 --- a/lib/pages/prepare_chess_game.dart +++ b/lib/pages/prepare_chess_game.dart @@ -1,7 +1,7 @@ import 'dart:developer'; import 'package:flutter/material.dart'; -import 'package:mchess/models/models.dart'; +import 'package:mchess/api/register.dart'; import 'package:mchess/pages/chess_game.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; @@ -18,6 +18,7 @@ class PrepareChessGameWidget extends StatelessWidget { log('future done ${snapshot.data?.playerID}'); return ChessGame( playerID: snapshot.data!.playerID, + lobbyID: snapshot.data!.lobbyID, ); } return const CircularProgressIndicator(); @@ -26,8 +27,9 @@ class PrepareChessGameWidget extends StatelessWidget { } Future registerForRandomGame() async { - final response = - await http.get(Uri.parse('http://localhost:8080/api/random')); + final response = await http.get( + Uri.parse('http://localhost:8080/api/random'), + headers: {"Accept": "application/json"}); if (response.statusCode == 200) { log(response.body); @@ -35,7 +37,7 @@ class PrepareChessGameWidget extends StatelessWidget { } else { // If the server did not return a 200 OK response, // then throw an exception. - throw Exception('Failed to load album'); + throw Exception('Failed to register for random game'); } } } diff --git a/lib/utils/chess_utils.dart b/lib/utils/chess_utils.dart index 47face4..e2f21e3 100644 --- a/lib/utils/chess_utils.dart +++ b/lib/utils/chess_utils.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:mchess/api/move.dart'; import 'package:quiver/core.dart'; enum ChessPieceName { @@ -65,6 +66,10 @@ class ChessCoordinate { return ChessCoordinate(column, row); } + factory ChessCoordinate.fromApiCoordinate(ApiCoordinate apiCoordinate) { + return ChessCoordinate(apiCoordinate.col, apiCoordinate.row); + } + ChessCoordinate.copyFrom(ChessCoordinate original) : column = original.column, row = original.row; @@ -159,6 +164,13 @@ class ChessMove { ChessMove({required this.from, required this.to}); + factory ChessMove.fromApiMove(ApiMove apiMove) { + final start = ChessCoordinate.fromApiCoordinate(apiMove.startSquare); + final end = ChessCoordinate.fromApiCoordinate(apiMove.endSquare); + + return ChessMove(from: start, to: end); + } + @override operator ==(other) { return other is ChessMove && other.from == from && other.to == to;