Spike counter + caching for szy api + more badges
ToDo: save advanced stats to the DB, polish UI, add interactivity to graphs
This commit is contained in:
parent
8dc2a5bced
commit
39569ffe0c
|
@ -5,6 +5,29 @@ import 'tetrio.dart';
|
||||||
// I want to implement those fancy TWC stats
|
// I want to implement those fancy TWC stats
|
||||||
// So, i'm going to read replay for things
|
// So, i'm going to read replay for things
|
||||||
|
|
||||||
|
int biggestSpikeFromReplay(events){
|
||||||
|
int previousIGEeventFrame = -1;
|
||||||
|
int spikeCounter = 0;
|
||||||
|
int biggestSpike = 0;
|
||||||
|
for (var event in events){
|
||||||
|
if (event["type"] == "ige" && event["data"]["data"]["type"] == "interaction"){
|
||||||
|
if (previousIGEeventFrame.isNegative){
|
||||||
|
spikeCounter = event['data']['data']['data']['amt'];
|
||||||
|
biggestSpike = spikeCounter;
|
||||||
|
}else{
|
||||||
|
if (event['data']['data']['frame'] - previousIGEeventFrame < 60){
|
||||||
|
spikeCounter = spikeCounter + event['data']['data']['data']['amt'] as int;
|
||||||
|
}else{
|
||||||
|
spikeCounter = event['data']['data']['data']['amt'];
|
||||||
|
}
|
||||||
|
biggestSpike = max(biggestSpike, spikeCounter);
|
||||||
|
}
|
||||||
|
previousIGEeventFrame = event['data']['data']['frame'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return biggestSpike;
|
||||||
|
}
|
||||||
|
|
||||||
class Garbage{ // charsys where???
|
class Garbage{ // charsys where???
|
||||||
late int sent;
|
late int sent;
|
||||||
late int recived;
|
late int recived;
|
||||||
|
@ -43,11 +66,11 @@ class ReplayStats{
|
||||||
late int score;
|
late int score;
|
||||||
late int topCombo;
|
late int topCombo;
|
||||||
late int topBtB;
|
late int topBtB;
|
||||||
|
late int topSpike;
|
||||||
late int tspins;
|
late int tspins;
|
||||||
late Clears clears;
|
late Clears clears;
|
||||||
late Garbage garbage;
|
late Garbage garbage;
|
||||||
late Finesse finesse;
|
late Finesse finesse;
|
||||||
late int kills;
|
|
||||||
|
|
||||||
double get finessePercentage => finesse.perfectPieces / piecesPlaced;
|
double get finessePercentage => finesse.perfectPieces / piecesPlaced;
|
||||||
|
|
||||||
|
@ -60,14 +83,14 @@ class ReplayStats{
|
||||||
required this.score,
|
required this.score,
|
||||||
required this.topCombo,
|
required this.topCombo,
|
||||||
required this.topBtB,
|
required this.topBtB,
|
||||||
|
required this.topSpike,
|
||||||
required this.tspins,
|
required this.tspins,
|
||||||
required this.clears,
|
required this.clears,
|
||||||
required this.garbage,
|
required this.garbage,
|
||||||
required this.finesse,
|
required this.finesse,
|
||||||
required this.kills,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ReplayStats.fromJson(Map<String, dynamic> json){
|
ReplayStats.fromJson(Map<String, dynamic> json, int inputTopSpike){
|
||||||
seed = json['seed'];
|
seed = json['seed'];
|
||||||
linesCleared = json['lines'];
|
linesCleared = json['lines'];
|
||||||
piecesPlaced = json['piecesplaced'];
|
piecesPlaced = json['piecesplaced'];
|
||||||
|
@ -76,11 +99,11 @@ class ReplayStats{
|
||||||
score = json['score'];
|
score = json['score'];
|
||||||
topCombo = json['topcombo'];
|
topCombo = json['topcombo'];
|
||||||
topBtB = json['topbtb'];
|
topBtB = json['topbtb'];
|
||||||
|
topSpike = inputTopSpike;
|
||||||
tspins = json['tspins'];
|
tspins = json['tspins'];
|
||||||
clears = Clears.fromJson(json['clears']);
|
clears = Clears.fromJson(json['clears']);
|
||||||
garbage = Garbage.fromJson(json['garbage']);
|
garbage = Garbage.fromJson(json['garbage']);
|
||||||
finesse = Finesse.fromJson(json['finesse']);
|
finesse = Finesse.fromJson(json['finesse']);
|
||||||
kills = json['kills'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplayStats.createEmpty(){
|
ReplayStats.createEmpty(){
|
||||||
|
@ -92,11 +115,11 @@ class ReplayStats{
|
||||||
score = 0;
|
score = 0;
|
||||||
topCombo = 0;
|
topCombo = 0;
|
||||||
topBtB = 0;
|
topBtB = 0;
|
||||||
|
topSpike = 0;
|
||||||
tspins = 0;
|
tspins = 0;
|
||||||
clears = Clears(singles: 0, doubles: 0, triples: 0, quads: 0, pentas: 0, allClears: 0, tSpinZeros: 0, tSpinSingles: 0, tSpinDoubles: 0, tSpinTriples: 0, tSpinPentas: 0, tSpinQuads: 0, tSpinMiniZeros: 0, tSpinMiniSingles: 0, tSpinMiniDoubles: 0);
|
clears = Clears(singles: 0, doubles: 0, triples: 0, quads: 0, pentas: 0, allClears: 0, tSpinZeros: 0, tSpinSingles: 0, tSpinDoubles: 0, tSpinTriples: 0, tSpinPentas: 0, tSpinQuads: 0, tSpinMiniZeros: 0, tSpinMiniSingles: 0, tSpinMiniDoubles: 0);
|
||||||
garbage = Garbage(sent: 0, recived: 0, attack: 0, cleared: 0);
|
garbage = Garbage(sent: 0, recived: 0, attack: 0, cleared: 0);
|
||||||
finesse = Finesse(combo: 0, faults: 0, perfectPieces: 0);
|
finesse = Finesse(combo: 0, faults: 0, perfectPieces: 0);
|
||||||
kills = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplayStats operator + (ReplayStats other){
|
ReplayStats operator + (ReplayStats other){
|
||||||
|
@ -108,11 +131,12 @@ class ReplayStats{
|
||||||
score: score + other.score,
|
score: score + other.score,
|
||||||
topCombo: max(topCombo, other.topCombo),
|
topCombo: max(topCombo, other.topCombo),
|
||||||
topBtB: max(topBtB, other.topBtB),
|
topBtB: max(topBtB, other.topBtB),
|
||||||
|
topSpike: max(topSpike, other.topSpike),
|
||||||
tspins: tspins + other.tspins,
|
tspins: tspins + other.tspins,
|
||||||
clears: clears + other.clears,
|
clears: clears + other.clears,
|
||||||
garbage: garbage + other.garbage,
|
garbage: garbage + other.garbage,
|
||||||
finesse: finesse + other.finesse,
|
finesse: finesse + other.finesse
|
||||||
kills: kills + other.kills);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +146,7 @@ class ReplayData{
|
||||||
late List<EndContextMulti> endcontext;
|
late List<EndContextMulti> endcontext;
|
||||||
late List<List<ReplayStats>> stats;
|
late List<List<ReplayStats>> stats;
|
||||||
late List<ReplayStats> totalStats;
|
late List<ReplayStats> totalStats;
|
||||||
|
late List<List<String>> roundWinners;
|
||||||
late List<int> roundLengths; // in frames
|
late List<int> roundLengths; // in frames
|
||||||
late int totalLength; // in frames
|
late int totalLength; // in frames
|
||||||
|
|
||||||
|
@ -130,6 +155,7 @@ class ReplayData{
|
||||||
required this.endcontext,
|
required this.endcontext,
|
||||||
required this.stats,
|
required this.stats,
|
||||||
required this.totalStats,
|
required this.totalStats,
|
||||||
|
required this.roundWinners,
|
||||||
required this.roundLengths,
|
required this.roundLengths,
|
||||||
required this.totalLength
|
required this.totalLength
|
||||||
}){
|
}){
|
||||||
|
@ -143,24 +169,20 @@ class ReplayData{
|
||||||
roundLengths = [];
|
roundLengths = [];
|
||||||
totalLength = 0;
|
totalLength = 0;
|
||||||
stats = [];
|
stats = [];
|
||||||
|
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 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']);
|
||||||
ReplayStats playerOne = ReplayStats.fromJson(round['replays'][0]['events'].last['data']['export']['stats']);
|
int winner = round['board'].indexWhere((element) => element["success"] == true);
|
||||||
ReplayStats playerTwo = ReplayStats.fromJson(round['replays'][1]['events'].last['data']['export']['stats']);
|
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]);
|
stats.add([playerOne, playerTwo]);
|
||||||
totalStats[0] = totalStats[0] + playerOne;
|
totalStats[0] = totalStats[0] + playerOne;
|
||||||
totalStats[1] = totalStats[1] + playerTwo;
|
totalStats[1] = totalStats[1] + playerTwo;
|
||||||
// print(round['replays'][0]['events'].last['data']['export']['stats']);
|
|
||||||
// for (var event in round['replays'][0]['events']){
|
|
||||||
// if (event["type"] == "ige" && event["data"]["data"]["type"] == "interaction_confirm"){
|
|
||||||
// print(event['data']["data"]["data"]); // lol
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
// Сами по себе эти ивенты ничего не дают,
|
|
||||||
// Хотя можно попробовать вычислить biggest spike
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -65,6 +65,7 @@ class TetrioService extends DB {
|
||||||
Map<String, List<TetrioPlayer>> _players = {};
|
Map<String, List<TetrioPlayer>> _players = {};
|
||||||
final Map<String, TetrioPlayer> _playersCache = {};
|
final Map<String, TetrioPlayer> _playersCache = {};
|
||||||
final Map<String, Map<String, dynamic>> _recordsCache = {};
|
final Map<String, Map<String, dynamic>> _recordsCache = {};
|
||||||
|
final Map<String, dynamic> _replaysCache = {};
|
||||||
final Map<String, TetrioPlayersLeaderboard> _leaderboardsCache = {};
|
final Map<String, TetrioPlayersLeaderboard> _leaderboardsCache = {};
|
||||||
final Map<String, List<News>> _newsCache = {};
|
final Map<String, List<News>> _newsCache = {};
|
||||||
final Map<String, Map<String, double?>> _topTRcache = {};
|
final Map<String, Map<String, double?>> _topTRcache = {};
|
||||||
|
@ -121,6 +122,12 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<dynamic>> szyGetReplay(String replayID) async {
|
Future<List<dynamic>> szyGetReplay(String replayID) async {
|
||||||
|
try{
|
||||||
|
var cached = _replaysCache.entries.firstWhere((element) => element.key == replayID);
|
||||||
|
return cached.value;
|
||||||
|
}catch (e){
|
||||||
|
// actually going to obtain
|
||||||
|
}
|
||||||
Uri url = Uri.https('inoue.szy.lol', '/api/replay/$replayID');
|
Uri url = Uri.https('inoue.szy.lol', '/api/replay/$replayID');
|
||||||
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();
|
||||||
|
@ -132,6 +139,7 @@ class TetrioService extends DB {
|
||||||
switch (response.statusCode) {
|
switch (response.statusCode) {
|
||||||
case 200:
|
case 200:
|
||||||
developer.log("szyDownload: Replay downloaded", name: "services/tetrio_crud", error: response.statusCode);
|
developer.log("szyDownload: Replay downloaded", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
|
_replaysCache[replayID] = [response.body, response.bodyBytes];
|
||||||
return [response.body, response.bodyBytes];
|
return [response.body, response.bodyBytes];
|
||||||
case 404:
|
case 404:
|
||||||
throw SzyNotFound();
|
throw SzyNotFound();
|
||||||
|
@ -157,7 +165,6 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> SaveReplay(String replayID) async {
|
Future<String> SaveReplay(String replayID) async {
|
||||||
Uri url = Uri.https('inoue.szy.lol', '/api/replay/$replayID');
|
|
||||||
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");
|
||||||
|
|
|
@ -801,6 +801,7 @@ class CompareThingy extends StatelessWidget {
|
||||||
final bool higherIsBetter;
|
final bool higherIsBetter;
|
||||||
final int? fractionDigits;
|
final int? fractionDigits;
|
||||||
final String? postfix;
|
final String? postfix;
|
||||||
|
final String? prefix;
|
||||||
const CompareThingy(
|
const CompareThingy(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.greenSide,
|
required this.greenSide,
|
||||||
|
@ -808,6 +809,7 @@ class CompareThingy extends StatelessWidget {
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.higherIsBetter,
|
required this.higherIsBetter,
|
||||||
this.fractionDigits,
|
this.fractionDigits,
|
||||||
|
this.prefix,
|
||||||
this.postfix});
|
this.postfix});
|
||||||
|
|
||||||
String verdict(num greenSide, num redSide, int fraction) {
|
String verdict(num greenSide, num redSide, int fraction) {
|
||||||
|
@ -845,7 +847,7 @@ class CompareThingy extends StatelessWidget {
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
child: Text(
|
child: Text(
|
||||||
f.format(greenSide) + (postfix ?? ""),
|
(prefix ?? "") + f.format(greenSide) + (postfix ?? ""),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
shadows: <Shadow>[
|
shadows: <Shadow>[
|
||||||
|
@ -899,7 +901,7 @@ class CompareThingy extends StatelessWidget {
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
child: Text(
|
child: Text(
|
||||||
f.format(redSide) + (postfix ?? ""),
|
(prefix ?? "") + f.format(redSide) + (postfix ?? ""),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
shadows: <Shadow>[
|
shadows: <Shadow>[
|
||||||
|
|
|
@ -269,10 +269,6 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
||||||
value: "history",
|
value: "history",
|
||||||
child: Text(t.fetchAndsaveTLHistory),
|
child: Text(t.fetchAndsaveTLHistory),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
|
||||||
value: "test",
|
|
||||||
child: Text("Test replay reading"),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
value: "/states",
|
value: "/states",
|
||||||
child: Text(t.showStoredData),
|
child: Text(t.showStoredData),
|
||||||
|
@ -294,11 +290,6 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
||||||
case "history":
|
case "history":
|
||||||
changePlayer(_searchFor, fetchHistory: true);
|
changePlayer(_searchFor, fetchHistory: true);
|
||||||
break;
|
break;
|
||||||
case "test":
|
|
||||||
var replayfile = File("/home/dan63047/Загрузки/659337dd1eef65e513c5dc8d.ttrm").readAsStringSync();
|
|
||||||
var testObject = ReplayData.fromJson(jsonDecode(replayfile));
|
|
||||||
print("lol");
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
context.go(value);
|
context.go(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,13 +201,18 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
case ConnectionState.waiting:
|
case ConnectionState.waiting:
|
||||||
case ConnectionState.active:
|
case ConnectionState.active:
|
||||||
return CircularProgressIndicator();
|
return const LinearProgressIndicator();
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
if (!snapshot.hasError){
|
if (!snapshot.hasError){
|
||||||
var time = framesToTime(snapshot.data!.totalLength);
|
if (roundSelector.isNegative){
|
||||||
return Center(child: Text("Match Length: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}"));
|
var time = framesToTime(snapshot.data!.totalLength);
|
||||||
|
return Center(child: Text("Match Length: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}", textAlign: TextAlign.center));
|
||||||
|
}else{
|
||||||
|
var time = framesToTime(snapshot.data!.roundLengths[roundSelector]);
|
||||||
|
return Center(child: Text("Round Length: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\nWinner: ${snapshot.data!.roundWinners[roundSelector][1]}", textAlign: TextAlign.center,));
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
return Text("skill issue");
|
return const Text("skill issue", textAlign: TextAlign.center);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -247,27 +252,47 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
case ConnectionState.waiting:
|
case ConnectionState.waiting:
|
||||||
case ConnectionState.active:
|
case ConnectionState.active:
|
||||||
return LinearProgressIndicator();
|
return const LinearProgressIndicator();
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
if (!snapshot.hasError){
|
if (!snapshot.hasError){
|
||||||
var greenSidePlayer = snapshot.data!.endcontext.indexWhere(((element) => element.userId == widget.initPlayerId));
|
var greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId);
|
||||||
var redSidePlayer = snapshot.data!.endcontext.indexWhere(((element) => element.userId != widget.initPlayerId));
|
var redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId);
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
CompareThingy(greenSide: snapshot.data!.totalStats[greenSidePlayer].piecesPlaced,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][greenSidePlayer].piecesPlaced,
|
||||||
redSide: snapshot.data!.totalStats[redSidePlayer].piecesPlaced,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][redSidePlayer].piecesPlaced,
|
||||||
label: "Pieces Placed", higherIsBetter: true),
|
label: "Pieces Placed", higherIsBetter: true),
|
||||||
CompareThingy(greenSide: snapshot.data!.totalStats[greenSidePlayer].linesCleared,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared,
|
||||||
redSide: snapshot.data!.totalStats[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: snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][greenSidePlayer].finessePercentage * 100,
|
||||||
redSide: snapshot.data!.totalStats[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),
|
||||||
CompareThingy(greenSide: snapshot.data!.totalStats[greenSidePlayer].topCombo,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topSpike : snapshot.data!.stats[roundSelector][greenSidePlayer].topSpike,
|
||||||
redSide: snapshot.data!.totalStats[redSidePlayer].topCombo,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topSpike : snapshot.data!.stats[roundSelector][redSidePlayer].topSpike,
|
||||||
|
label: "Best Spike", higherIsBetter: true),
|
||||||
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topCombo : snapshot.data!.stats[roundSelector][greenSidePlayer].topCombo,
|
||||||
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topCombo : snapshot.data!.stats[roundSelector][redSidePlayer].topCombo,
|
||||||
label: "Best Combo", higherIsBetter: true),
|
label: "Best Combo", higherIsBetter: true),
|
||||||
CompareThingy(greenSide: snapshot.data!.totalStats[greenSidePlayer].topBtB,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topBtB : snapshot.data!.stats[roundSelector][greenSidePlayer].topBtB,
|
||||||
redSide: snapshot.data!.totalStats[redSidePlayer].topBtB,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topBtB : snapshot.data!.stats[roundSelector][redSidePlayer].topBtB,
|
||||||
label: "Best BtB", higherIsBetter: true),
|
label: "Best BtB", higherIsBetter: true),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16),
|
||||||
|
child: Text("Garbage", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||||
|
),
|
||||||
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.sent : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.sent,
|
||||||
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.sent : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.sent,
|
||||||
|
label: "Sent", higherIsBetter: true),
|
||||||
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.recived,
|
||||||
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.recived,
|
||||||
|
label: "Recived", higherIsBetter: true),
|
||||||
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.attack,
|
||||||
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.attack,
|
||||||
|
label: "Attack", higherIsBetter: true),
|
||||||
|
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),
|
||||||
],);
|
],);
|
||||||
}else{
|
}else{
|
||||||
return Text("skill issue");
|
return Text("skill issue");
|
||||||
|
@ -412,17 +437,17 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.das,
|
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.das,
|
||||||
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.das,
|
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.das,
|
||||||
label: "DAS", fractionDigits: 1,
|
label: "DAS", fractionDigits: 1, postfix: "F",
|
||||||
higherIsBetter: false),
|
higherIsBetter: false),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.arr,
|
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.arr,
|
||||||
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.arr,
|
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.arr,
|
||||||
label: "ARR", fractionDigits: 1,
|
label: "ARR", fractionDigits: 1, postfix: "F",
|
||||||
higherIsBetter: false),
|
higherIsBetter: false),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.sdf,
|
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.sdf,
|
||||||
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.sdf,
|
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.sdf,
|
||||||
label: "SDF",
|
label: "SDF", prefix: "x",
|
||||||
higherIsBetter: true),
|
higherIsBetter: true),
|
||||||
CompareBoolThingy(
|
CompareBoolThingy(
|
||||||
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.safeLock,
|
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.safeLock,
|
||||||
|
|
|
@ -166,6 +166,7 @@ flutter:
|
||||||
- res/tetrio_badges/sfu_raccoon_1.png
|
- res/tetrio_badges/sfu_raccoon_1.png
|
||||||
- res/tetrio_badges/sfu_raccoon_2.png
|
- res/tetrio_badges/sfu_raccoon_2.png
|
||||||
- res/tetrio_badges/sfu_raccoon_3.png
|
- res/tetrio_badges/sfu_raccoon_3.png
|
||||||
|
- res/tetrio_badges/streamersuperlobby.png
|
||||||
- res/tetrio_badges/superlobby.png
|
- res/tetrio_badges/superlobby.png
|
||||||
- res/tetrio_badges/superlobby2.png
|
- res/tetrio_badges/superlobby2.png
|
||||||
- res/tetrio_badges/taws_u50_1.png
|
- res/tetrio_badges/taws_u50_1.png
|
||||||
|
@ -185,6 +186,10 @@ flutter:
|
||||||
- res/tetrio_badges/ttsdtc_1.png
|
- res/tetrio_badges/ttsdtc_1.png
|
||||||
- res/tetrio_badges/ttsdtc_2.png
|
- res/tetrio_badges/ttsdtc_2.png
|
||||||
- res/tetrio_badges/ttsdtc_3.png
|
- res/tetrio_badges/ttsdtc_3.png
|
||||||
|
- res/tetrio_badges/twc23_1.png
|
||||||
|
- res/tetrio_badges/twc23_2.png
|
||||||
|
- res/tetrio_badges/twc23_3.png
|
||||||
|
- res/tetrio_badges/twc23_4.png
|
||||||
- res/tetrio_badges/ubcea_1.png
|
- res/tetrio_badges/ubcea_1.png
|
||||||
- res/tetrio_badges/ubcea_2.png
|
- res/tetrio_badges/ubcea_2.png
|
||||||
- res/tetrio_badges/ubcea_3.png
|
- res/tetrio_badges/ubcea_3.png
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Loading…
Reference in New Issue