Now data is stored in local DB

ToDo: polish things and release of 1.4.0
This commit is contained in:
dan63047 2024-01-09 01:42:49 +03:00
parent 39569ffe0c
commit 3807c7321e
4 changed files with 61 additions and 13 deletions

View File

@ -164,20 +164,20 @@ class ReplayData{
ReplayData.fromJson(Map<String, dynamic> json){ ReplayData.fromJson(Map<String, dynamic> json){
rawJson = json; rawJson = json;
id = json["_id"]; id = json['_id'];
endcontext = [EndContextMulti.fromJson(json["endcontext"][0]), EndContextMulti.fromJson(json["endcontext"][1])]; endcontext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])];
roundLengths = []; roundLengths = [];
totalLength = 0; totalLength = 0;
stats = []; stats = [];
roundWinners = []; roundWinners = [];
totalStats = [ReplayStats.createEmpty(), ReplayStats.createEmpty()]; totalStats = [ReplayStats.createEmpty(), ReplayStats.createEmpty()];
int firstInEndContext = json["data"][0]["board"].indexWhere((element) => element["id"] == endcontext[0].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); int secondInEndContext = json['data'][0]['board'].indexWhere((element) => element['id'] == endcontext[1].userId);
for(var round in json['data']) { for(var round in json['data']) {
roundLengths.add(max(round['replays'][0]['frames'], round['replays'][1]['frames'])); roundLengths.add(max(round['replays'][0]['frames'], round['replays'][1]['frames']));
totalLength = totalLength + 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); int winner = round['board'].indexWhere((element) => element['success'] == true);
roundWinners.add([round['board'][winner]["id"], round['board'][winner]["username"]]); 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 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'])); ReplayStats playerTwo = ReplayStats.fromJson(round['replays'][secondInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][firstInEndContext]['events']));
stats.add([playerOne, playerTwo]); stats.add([playerOne, playerTwo]);
@ -185,4 +185,22 @@ class ReplayData{
totalStats[1] = totalStats[1] + playerTwo; totalStats[1] = totalStats[1] + playerTwo;
} }
} }
Map<String, dynamic> toJson(){
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = id;
data['endcontext'] = [endcontext[0].toJson(), endcontext[1].toJson()];
data['data'] = [];
for(var round in rawJson['data']) {
List<dynamic> eventsPlayerOne = round['replays'][0]['events'];
List<dynamic> 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;
}
} }

View File

@ -28,6 +28,7 @@ class DB {
await db.execute(createTetrioUsersTable); await db.execute(createTetrioUsersTable);
await db.execute(createTetrioUsersToTrack); await db.execute(createTetrioUsersToTrack);
await db.execute(createTetrioTLRecordsTable); await db.execute(createTetrioTLRecordsTable);
await db.execute(createTetrioTLReplayStats);
} on MissingPlatformDirectoryException { } on MissingPlatformDirectoryException {
throw UnableToGetDocuments(); throw UnableToGetDocuments();
} }

View File

@ -17,6 +17,7 @@ const String dbName = "TetraStats.db";
const String tetrioUsersTable = "tetrioUsers"; const String tetrioUsersTable = "tetrioUsers";
const String tetrioUsersToTrackTable = "tetrioUsersToTrack"; const String tetrioUsersToTrackTable = "tetrioUsersToTrack";
const String tetraLeagueMatchesTable = "tetrioAlphaLeagueMathces"; const String tetraLeagueMatchesTable = "tetrioAlphaLeagueMathces";
const String tetrioTLReplayStatsTable = "tetrioTLReplayStats";
const String idCol = "id"; const String idCol = "id";
const String replayID = "replayId"; const String replayID = "replayId";
const String nickCol = "nickname"; const String nickCol = "nickname";
@ -53,10 +54,9 @@ const String createTetrioTLRecordsTable = '''
'''; ''';
const String createTetrioTLReplayStats = ''' const String createTetrioTLReplayStats = '''
CREATE TABLE "tetrioTLReplayStats" ( CREATE TABLE IF NOT EXISTS "tetrioTLReplayStats" (
"id" TEXT NOT NULL, "id" TEXT NOT NULL,
"player1" TEXT NOT NULL, "data" TEXT NOT NULL,
"player2" TEXT NOT NULL,
PRIMARY KEY("id") PRIMARY KEY("id")
) )
'''; ''';
@ -121,6 +121,12 @@ class TetrioService extends DB {
} }
} }
Future<void> saveReplayStats(ReplayData replay) async {
await ensureDbIsOpen();
final db = getDatabaseOrThrow();
db.insert(tetrioTLReplayStatsTable, {idCol: replay.id, "data": jsonEncode(replay.toJson())});
}
Future<List<dynamic>> szyGetReplay(String replayID) async { Future<List<dynamic>> szyGetReplay(String replayID) async {
try{ try{
var cached = _replaysCache.entries.firstWhere((element) => element.key == replayID); var cached = _replaysCache.entries.firstWhere((element) => element.key == replayID);
@ -164,7 +170,7 @@ class TetrioService extends DB {
} }
} }
Future<String> SaveReplay(String replayID) async { Future<String> saveReplay(String replayID) async {
var downloadPath = await getDownloadsDirectory(); var downloadPath = await getDownloadsDirectory();
downloadPath ??= Platform.isAndroid ? Directory("/storage/emulated/0/Download") : await getApplicationDocumentsDirectory(); downloadPath ??= Platform.isAndroid ? Directory("/storage/emulated/0/Download") : await getApplicationDocumentsDirectory();
var replayFile = File("${downloadPath.path}/$replayID.ttrm"); var replayFile = File("${downloadPath.path}/$replayID.ttrm");
@ -175,8 +181,14 @@ class TetrioService extends DB {
} }
Future<ReplayData> analyzeReplay(String replayID) async{ Future<ReplayData> 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<String, dynamic> toAnalyze = jsonDecode((await szyGetReplay(replayID))[0]); Map<String, dynamic> toAnalyze = jsonDecode((await szyGetReplay(replayID))[0]);
return ReplayData.fromJson(toAnalyze); ReplayData data = ReplayData.fromJson(toAnalyze);
saveReplayStats(data);
return data;
} }
Future<double?> fetchTopTR(String id) async { Future<double?> fetchTopTR(String id) async {

View File

@ -93,7 +93,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
//anchor.remove(); //anchor.remove();
} else{ } else{
try{ 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)))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.replaySaved(path: path))));
} on TetrioReplayAlreadyExist{ } on TetrioReplayAlreadyExist{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayAlreadySaved))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayAlreadySaved)));
@ -264,6 +264,9 @@ class TlMatchResultState extends State<TlMatchResultView> {
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared, 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, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][redSidePlayer].linesCleared,
label: "Lines Cleared", higherIsBetter: true), 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, 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, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][redSidePlayer].finessePercentage * 100,
label: "Finnese", postfix: "%", fractionDigits: 2, higherIsBetter: true), label: "Finnese", postfix: "%", fractionDigits: 2, higherIsBetter: true),
@ -293,9 +296,23 @@ class TlMatchResultState extends State<TlMatchResultView> {
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.cleared, 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, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.cleared,
label: "Cleared", higherIsBetter: true), 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{ }else{
return Text("skill issue"); return Container();
} }
} }