From 3807c7321ea11bafbd40d4c95db977dba96fe2fd Mon Sep 17 00:00:00 2001 From: dan63047 Date: Tue, 9 Jan 2024 01:42:49 +0300 Subject: [PATCH] Now data is stored in local DB ToDo: polish things and release of 1.4.0 --- .../tetrio_multiplayer_replay.dart | 30 +++++++++++++++---- lib/services/sqlite_db_controller.dart | 1 + lib/services/tetrio_crud.dart | 22 ++++++++++---- lib/views/tl_match_view.dart | 21 +++++++++++-- 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index d134920..9bc9ad6 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -164,20 +164,20 @@ class ReplayData{ ReplayData.fromJson(Map json){ rawJson = json; - id = json["_id"]; - endcontext = [EndContextMulti.fromJson(json["endcontext"][0]), EndContextMulti.fromJson(json["endcontext"][1])]; + id = json['_id']; + endcontext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])]; roundLengths = []; totalLength = 0; stats = []; roundWinners = []; totalStats = [ReplayStats.createEmpty(), ReplayStats.createEmpty()]; - int firstInEndContext = json["data"][0]["board"].indexWhere((element) => element["id"] == endcontext[0].userId); - int secondInEndContext = json["data"][0]["board"].indexWhere((element) => element["id"] == endcontext[1].userId); + int firstInEndContext = json['data'][0]['board'].indexWhere((element) => element['id'] == endcontext[0].userId); + int secondInEndContext = json['data'][0]['board'].indexWhere((element) => element['id'] == endcontext[1].userId); for(var round in json['data']) { roundLengths.add(max(round['replays'][0]['frames'], round['replays'][1]['frames'])); totalLength = totalLength + max(round['replays'][0]['frames'], round['replays'][1]['frames']); - int winner = round['board'].indexWhere((element) => element["success"] == true); - roundWinners.add([round['board'][winner]["id"], round['board'][winner]["username"]]); + int winner = round['board'].indexWhere((element) => element['success'] == true); + roundWinners.add([round['board'][winner]['id'], round['board'][winner]['username']]); ReplayStats playerOne = ReplayStats.fromJson(round['replays'][firstInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][secondInEndContext]['events'])); // (events contain recived attacks) ReplayStats playerTwo = ReplayStats.fromJson(round['replays'][secondInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][firstInEndContext]['events'])); stats.add([playerOne, playerTwo]); @@ -185,4 +185,22 @@ class ReplayData{ totalStats[1] = totalStats[1] + playerTwo; } } + + Map toJson(){ + final Map data = {}; + data['_id'] = id; + data['endcontext'] = [endcontext[0].toJson(), endcontext[1].toJson()]; + data['data'] = []; + for(var round in rawJson['data']) { + List eventsPlayerOne = round['replays'][0]['events']; + List eventsPlayerTwo = round['replays'][1]['events']; + eventsPlayerOne.removeWhere((v) => (v['type'] == 'ige' && v['data']['data']['type'] != 'interaction') || (v['type'] != 'end' && v['type'] != 'ige')); + eventsPlayerTwo.removeWhere((v) => (v['type'] == 'ige' && v['data']['data']['type'] != 'interaction') || (v['type'] != 'end' && v['type'] != 'ige')); + data['data'].add({'board': round['board'], 'replays': [ + {'frames': round['replays'][0]['frames'], 'events': eventsPlayerOne}, + {'frames': round['replays'][1]['frames'], 'events': eventsPlayerTwo} + ]}); + } + return data; + } } \ No newline at end of file diff --git a/lib/services/sqlite_db_controller.dart b/lib/services/sqlite_db_controller.dart index 0d475b2..f47772e 100644 --- a/lib/services/sqlite_db_controller.dart +++ b/lib/services/sqlite_db_controller.dart @@ -28,6 +28,7 @@ class DB { await db.execute(createTetrioUsersTable); await db.execute(createTetrioUsersToTrack); await db.execute(createTetrioTLRecordsTable); + await db.execute(createTetrioTLReplayStats); } on MissingPlatformDirectoryException { throw UnableToGetDocuments(); } diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index 45103bb..cc0c5bd 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -17,6 +17,7 @@ const String dbName = "TetraStats.db"; const String tetrioUsersTable = "tetrioUsers"; const String tetrioUsersToTrackTable = "tetrioUsersToTrack"; const String tetraLeagueMatchesTable = "tetrioAlphaLeagueMathces"; +const String tetrioTLReplayStatsTable = "tetrioTLReplayStats"; const String idCol = "id"; const String replayID = "replayId"; const String nickCol = "nickname"; @@ -53,10 +54,9 @@ const String createTetrioTLRecordsTable = ''' '''; const String createTetrioTLReplayStats = ''' - CREATE TABLE "tetrioTLReplayStats" ( + CREATE TABLE IF NOT EXISTS "tetrioTLReplayStats" ( "id" TEXT NOT NULL, - "player1" TEXT NOT NULL, - "player2" TEXT NOT NULL, + "data" TEXT NOT NULL, PRIMARY KEY("id") ) '''; @@ -121,6 +121,12 @@ class TetrioService extends DB { } } + Future saveReplayStats(ReplayData replay) async { + await ensureDbIsOpen(); + final db = getDatabaseOrThrow(); + db.insert(tetrioTLReplayStatsTable, {idCol: replay.id, "data": jsonEncode(replay.toJson())}); + } + Future> szyGetReplay(String replayID) async { try{ var cached = _replaysCache.entries.firstWhere((element) => element.key == replayID); @@ -164,7 +170,7 @@ class TetrioService extends DB { } } - Future SaveReplay(String replayID) async { + Future saveReplay(String replayID) async { var downloadPath = await getDownloadsDirectory(); downloadPath ??= Platform.isAndroid ? Directory("/storage/emulated/0/Download") : await getApplicationDocumentsDirectory(); var replayFile = File("${downloadPath.path}/$replayID.ttrm"); @@ -175,8 +181,14 @@ class TetrioService extends DB { } Future analyzeReplay(String replayID) async{ + await ensureDbIsOpen(); + final db = getDatabaseOrThrow(); + final results = await db.query(tetrioTLReplayStatsTable, where: '$idCol = ?', whereArgs: [replayID]); + if (results.isNotEmpty) return ReplayData.fromJson(jsonDecode(results.first["data"].toString())); Map toAnalyze = jsonDecode((await szyGetReplay(replayID))[0]); - return ReplayData.fromJson(toAnalyze); + ReplayData data = ReplayData.fromJson(toAnalyze); + saveReplayStats(data); + return data; } Future fetchTopTR(String id) async { diff --git a/lib/views/tl_match_view.dart b/lib/views/tl_match_view.dart index 14d6972..7149789 100644 --- a/lib/views/tl_match_view.dart +++ b/lib/views/tl_match_view.dart @@ -93,7 +93,7 @@ class TlMatchResultState extends State { //anchor.remove(); } else{ try{ - String path = await teto.SaveReplay(widget.record.replayId); + String path = await teto.saveReplay(widget.record.replayId); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.replaySaved(path: path)))); } on TetrioReplayAlreadyExist{ ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayAlreadySaved))); @@ -264,6 +264,9 @@ class TlMatchResultState extends State { CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][redSidePlayer].linesCleared, label: "Lines Cleared", higherIsBetter: true), + CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].score : snapshot.data!.stats[roundSelector][greenSidePlayer].score, + redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].score : snapshot.data!.stats[roundSelector][redSidePlayer].score, + label: "Score", higherIsBetter: true), CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][greenSidePlayer].finessePercentage * 100, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][redSidePlayer].finessePercentage * 100, label: "Finnese", postfix: "%", fractionDigits: 2, higherIsBetter: true), @@ -293,9 +296,23 @@ class TlMatchResultState extends State { CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.cleared, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.cleared, label: "Cleared", higherIsBetter: true), + const Divider(), + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text("Line Clears", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), + ), + CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.allClears : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.allClears, + redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.allClears : snapshot.data!.stats[roundSelector][redSidePlayer].clears.allClears, + label: "PC", higherIsBetter: true), + CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].tspins : snapshot.data!.stats[roundSelector][greenSidePlayer].tspins, + redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].tspins : snapshot.data!.stats[roundSelector][redSidePlayer].tspins, + label: "T-spins", higherIsBetter: true), + CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.quads, + redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][redSidePlayer].clears.quads, + label: "Quads", higherIsBetter: true), ],); }else{ - return Text("skill issue"); + return Container(); } }