From e403b0cbee60dbd4f7dc9732a8647e57c98f07ab Mon Sep 17 00:00:00 2001 From: dan63047 Date: Fri, 6 Sep 2024 00:42:21 +0300 Subject: [PATCH] big and scary refactoring --- analysis_options.yaml | 5 +- lib/data_objects/achievement.dart | 98 + lib/data_objects/aggregate_stats.dart | 29 + lib/data_objects/badge.dart | 34 + .../beta_league_leaderboard_entry.dart | 21 + lib/data_objects/beta_league_results.dart | 24 + lib/data_objects/beta_league_round.dart | 25 + lib/data_objects/beta_league_stats.dart | 43 + lib/data_objects/beta_record.dart | 25 + lib/data_objects/clears.dart | 102 + lib/data_objects/connections.dart | 43 + lib/data_objects/cutoff_tetrio.dart | 42 + lib/data_objects/distinguishment.dart | 29 + lib/data_objects/end_context_multi.dart | 97 + lib/data_objects/est_tr.dart | 39 + lib/data_objects/finesse.dart | 29 + lib/data_objects/handling.dart | 32 + lib/data_objects/leaderboard_position.dart | 8 + lib/data_objects/nerd_stats.dart | 28 + lib/data_objects/news.dart | 15 + lib/data_objects/news_entry.dart | 15 + .../{tetra_stats.dart => p1nkl0bst3r.dart} | 0 .../player_leaderboard_position.dart | 63 + lib/data_objects/playstyle.dart | 25 + lib/data_objects/record_extras.dart | 15 + lib/data_objects/record_single.dart | 50 + lib/data_objects/results_stats.dart | 82 + lib/data_objects/singleplayer_stream.dart | 18 + lib/data_objects/summaries.dart | 39 + lib/data_objects/tetra_league.dart | 139 + .../tetra_league_alpha_record.dart | 39 + .../tetra_league_alpha_stream.dart | 16 + .../tetra_league_beta_stream.dart | 111 + lib/data_objects/tetrio.dart | 2600 ----------------- lib/data_objects/tetrio_constants.dart | 188 ++ .../tetrio_multiplayer_replay.dart | 7 +- lib/data_objects/tetrio_player.dart | 150 + .../tetrio_player_from_leaderboard.dart | 145 + .../tetrio_players_leaderboard.dart | 759 +++++ lib/data_objects/tetrio_zen.dart | 24 + lib/data_objects/user_records.dart | 13 + lib/data_objects/zenith_results.dart | 36 + lib/main.dart | 2 +- lib/services/tetrio_crud.dart | 21 +- lib/views/calc_view.dart | 4 +- lib/views/compare_view.dart | 5 +- lib/views/main_view.dart | 25 +- lib/views/main_view_tiles.dart | 105 +- lib/views/rank_averages_view.dart | 4 +- lib/views/ranks_averages_view.dart | 3 +- lib/views/settings_view.dart | 2 +- lib/views/singleplayer_record_view.dart | 2 +- lib/views/sprint_and_blitz_averages.dart | 2 +- lib/views/state_view.dart | 9 +- lib/views/states_view.dart | 2 +- lib/views/tl_leaderboard_view.dart | 2 +- lib/views/tl_match_view.dart | 4 +- lib/views/tracked_players_view.dart | 2 - lib/views/zenith_record_view.dart | 2 +- lib/widgets/finesse_thingy.dart | 2 +- lib/widgets/gauget_num.dart | 2 +- lib/widgets/graphs.dart | 4 +- lib/widgets/lineclears_thingy.dart | 2 +- lib/widgets/recent_sp_games.dart | 3 +- lib/widgets/singleplayer_record.dart | 4 +- lib/widgets/sp_trailing_stats.dart | 2 +- lib/widgets/stat_sell_num.dart | 2 +- lib/widgets/tl_progress_bar.dart | 2 +- lib/widgets/tl_rating_thingy.dart | 2 +- lib/widgets/tl_thingy.dart | 12 +- lib/widgets/user_thingy.dart | 2 +- lib/widgets/vs_graphs.dart | 4 +- lib/widgets/zenith_thingy.dart | 3 +- 73 files changed, 2869 insertions(+), 2675 deletions(-) create mode 100644 lib/data_objects/achievement.dart create mode 100644 lib/data_objects/aggregate_stats.dart create mode 100644 lib/data_objects/badge.dart create mode 100644 lib/data_objects/beta_league_leaderboard_entry.dart create mode 100644 lib/data_objects/beta_league_results.dart create mode 100644 lib/data_objects/beta_league_round.dart create mode 100644 lib/data_objects/beta_league_stats.dart create mode 100644 lib/data_objects/beta_record.dart create mode 100644 lib/data_objects/clears.dart create mode 100644 lib/data_objects/connections.dart create mode 100644 lib/data_objects/cutoff_tetrio.dart create mode 100644 lib/data_objects/distinguishment.dart create mode 100644 lib/data_objects/end_context_multi.dart create mode 100644 lib/data_objects/est_tr.dart create mode 100644 lib/data_objects/finesse.dart create mode 100644 lib/data_objects/handling.dart create mode 100644 lib/data_objects/leaderboard_position.dart create mode 100644 lib/data_objects/nerd_stats.dart create mode 100644 lib/data_objects/news.dart create mode 100644 lib/data_objects/news_entry.dart rename lib/data_objects/{tetra_stats.dart => p1nkl0bst3r.dart} (100%) create mode 100644 lib/data_objects/player_leaderboard_position.dart create mode 100644 lib/data_objects/playstyle.dart create mode 100644 lib/data_objects/record_extras.dart create mode 100644 lib/data_objects/record_single.dart create mode 100644 lib/data_objects/results_stats.dart create mode 100644 lib/data_objects/singleplayer_stream.dart create mode 100644 lib/data_objects/summaries.dart create mode 100644 lib/data_objects/tetra_league.dart create mode 100644 lib/data_objects/tetra_league_alpha_record.dart create mode 100644 lib/data_objects/tetra_league_alpha_stream.dart create mode 100644 lib/data_objects/tetra_league_beta_stream.dart delete mode 100644 lib/data_objects/tetrio.dart create mode 100644 lib/data_objects/tetrio_constants.dart create mode 100644 lib/data_objects/tetrio_player.dart create mode 100644 lib/data_objects/tetrio_player_from_leaderboard.dart create mode 100644 lib/data_objects/tetrio_players_leaderboard.dart create mode 100644 lib/data_objects/tetrio_zen.dart create mode 100644 lib/data_objects/user_records.dart create mode 100644 lib/data_objects/zenith_results.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index a7acf24..f3cece1 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -7,7 +7,10 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml +analyzer: + errors: + use_build_context_synchronously: ignore +in ignoreclude: package:flutter_lints/flutter.yaml linter: # The lint rules applied to this project can be customized in the diff --git a/lib/data_objects/achievement.dart b/lib/data_objects/achievement.dart new file mode 100644 index 0000000..d3794a3 --- /dev/null +++ b/lib/data_objects/achievement.dart @@ -0,0 +1,98 @@ +// ignore_for_file: hash_and_equals + +class Achievement { + late int k; + int? o; + late int rt; + late int vt; + late int min; + late int deci; + late String name; + late String object; + late String category; + late bool hidden; + late int art; + late bool nolb; + late String desc; + late String n; + String? sId; + double? v; + late int? a; + DateTime? t; + int? pos; + int? total; + int? rank; + + Achievement( + {required this.k, + this.o, + required this.rt, + required this.vt, + required this.min, + required this.deci, + required this.name, + required this.object, + required this.category, + required this.hidden, + required this.art, + required this.nolb, + required this.desc, + required this.n, + this.sId, + this.v, + required this.a, + this.t, + this.pos, + this.total, + this.rank}); + + Achievement.fromJson(Map json) { + k = json['k']; + o = json['o']; + rt = json['rt']; + vt = json['vt']; + min = json['min']; + deci = json['deci']; + name = json['name']; + object = json['object']; + category = json['category']; + hidden = json['hidden']; + art = json['art']; + nolb = json['nolb']; + desc = json['desc']; + n = json['n']; + sId = json['_id']; + v = json['v']?.toDouble(); + a = json['a']; + t = json['t'] != null ? DateTime.parse(json['t']) : null; + pos = json['pos']; + total = json['total']; + rank = json['rank']; + } + + Map toJson() { + final Map data = {}; + data['k'] = k; + data['o'] = o; + data['rt'] = rt; + data['vt'] = vt; + data['min'] = min; + data['deci'] = deci; + data['name'] = name; + data['object'] = object; + data['category'] = category; + data['hidden'] = hidden; + data['art'] = art; + data['nolb'] = nolb; + data['desc'] = desc; + data['n'] = n; + data['_id'] = sId; + data['v'] = v; + data['a'] = a; + data['t'] = t.toString(); + data['pos'] = pos; + data['total'] = total; + data['rank'] = rank; + return data; + } +} diff --git a/lib/data_objects/aggregate_stats.dart b/lib/data_objects/aggregate_stats.dart new file mode 100644 index 0000000..2e16afe --- /dev/null +++ b/lib/data_objects/aggregate_stats.dart @@ -0,0 +1,29 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; + +class AggregateStats{ + late double apm; + late double pps; + late double vs; + late NerdStats nerdStats; + late EstTr estTr; + late Playstyle playstyle; + + AggregateStats(this.apm, this.pps, this.vs){ + nerdStats = NerdStats(apm, pps, vs); + estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + } + + AggregateStats.fromJson(Map json){ + apm = json['apm'] != null ? json['apm'].toDouble() : 0.00; + pps = json['apm'] != null ? json['pps'].toDouble() : 0.00; + vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00; + nerdStats = NerdStats(apm, pps, vs); + estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + } +} diff --git a/lib/data_objects/badge.dart b/lib/data_objects/badge.dart new file mode 100644 index 0000000..69976e6 --- /dev/null +++ b/lib/data_objects/badge.dart @@ -0,0 +1,34 @@ +// ignore_for_file: hash_and_equals + +class Badge { + late String badgeId; + late String label; + DateTime? ts; + + Badge({required this.badgeId, required this.label, this.ts}); + + Badge.fromJson(Map json) { + badgeId = json['id']; + label = json['label']; + ts = (json['ts'] != null && json['ts'] is String) ? DateTime.parse(json['ts']) : null; // man i love osk + } + + Map toJson() { + final Map data = {}; + data['id'] = badgeId; + data['label'] = label; + data['ts'] = ts?.toString(); + return data; + } + + @override + String toString() { + return "Badge $label ($badgeId)"; + } + + @override + int get hashCode => badgeId.hashCode; + + @override + bool operator ==(covariant Badge other) => badgeId == other.badgeId; +} diff --git a/lib/data_objects/beta_league_leaderboard_entry.dart b/lib/data_objects/beta_league_leaderboard_entry.dart new file mode 100644 index 0000000..34672b4 --- /dev/null +++ b/lib/data_objects/beta_league_leaderboard_entry.dart @@ -0,0 +1,21 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/beta_league_stats.dart'; + +class BetaLeagueLeaderboardEntry{ + late String id; + late String username; + late int naturalorder; + late int wins; + late BetaLeagueStats stats; + + BetaLeagueLeaderboardEntry({required this.id, required this.username, required this.naturalorder, required this.wins, required this.stats}); + + BetaLeagueLeaderboardEntry.fromJson(Map json){ + id = json['id']; + username = json['username']; + naturalorder = json['naturalorder']; + wins = json['wins']; + stats = BetaLeagueStats.fromJson(json['stats']); + } +} diff --git a/lib/data_objects/beta_league_results.dart b/lib/data_objects/beta_league_results.dart new file mode 100644 index 0000000..2d4ad50 --- /dev/null +++ b/lib/data_objects/beta_league_results.dart @@ -0,0 +1,24 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/beta_league_leaderboard_entry.dart'; +import 'package:tetra_stats/data_objects/beta_league_round.dart'; + +class BetaLeagueResults{ + List leaderboard = []; + List> rounds = []; + + BetaLeagueResults({required this.leaderboard, required this.rounds}); + + BetaLeagueResults.fromJson(Map json){ + for (var lbEntry in json['leaderboard']) { + leaderboard.add(BetaLeagueLeaderboardEntry.fromJson(lbEntry)); + } + for (var roundEntry in json['rounds']){ + List round = []; + for (var r in roundEntry) { + round.add(BetaLeagueRound.fromJson(r)); + } + rounds.add(round); + } + } +} diff --git a/lib/data_objects/beta_league_round.dart b/lib/data_objects/beta_league_round.dart new file mode 100644 index 0000000..fdaf81b --- /dev/null +++ b/lib/data_objects/beta_league_round.dart @@ -0,0 +1,25 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/beta_league_stats.dart'; + +class BetaLeagueRound{ + late String id; + late String username; + late bool active; + late int naturalorder; + late bool alive; + late Duration lifetime; + late BetaLeagueStats stats; + + BetaLeagueRound({required this.id, required this.username, required this.active, required this.naturalorder, required this.alive, required this.lifetime, required this.stats}); + + BetaLeagueRound.fromJson(Map json){ + id = json['id']; + username = json['username']; + active = json['active']; + naturalorder = json['naturalorder']; + alive = json['alive']; + lifetime = Duration(milliseconds: json['lifetime']); + stats = BetaLeagueStats.fromJson(json['stats']); + } +} diff --git a/lib/data_objects/beta_league_stats.dart b/lib/data_objects/beta_league_stats.dart new file mode 100644 index 0000000..88e1c56 --- /dev/null +++ b/lib/data_objects/beta_league_stats.dart @@ -0,0 +1,43 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; + +class BetaLeagueStats{ + late double apm; + late double pps; + late double vs; + late int garbageSent; + late int garbageReceived; + late int kills; + late double altitude; + late int rank; + int? targetingFactor; + int? targetingRace; + late NerdStats nerdStats; + late EstTr estTr; + late Playstyle playstyle; + + BetaLeagueStats({required this.apm, required this.pps, required this.vs, required this.garbageSent, required this.garbageReceived, required this.kills, required this.altitude, required this.rank}){ + nerdStats = NerdStats(apm, pps, vs); + estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + } + + BetaLeagueStats.fromJson(Map json){ + apm = json['apm'] != null ? json['apm'].toDouble() : 0.00; + pps = json['apm'] != null ? json['pps'].toDouble() : 0.00; + vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00; + garbageSent = json['garbagesent']; + garbageReceived = json['garbagereceived']; + kills = json['kills']; + altitude = json['altitude'].toDouble(); + rank = json['rank']; + targetingFactor = json['targetingfactor']; + targetingRace = json['targetinggrace']; + nerdStats = NerdStats(apm, pps, vs); + estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + } +} diff --git a/lib/data_objects/beta_record.dart b/lib/data_objects/beta_record.dart new file mode 100644 index 0000000..d50bba5 --- /dev/null +++ b/lib/data_objects/beta_record.dart @@ -0,0 +1,25 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/beta_league_results.dart'; + +class BetaRecord{ + late String id; + late String replayID; + late String gamemode; + late DateTime ts; + late String enemyUsername; + late String enemyID; + late BetaLeagueResults results; + + BetaRecord({required this.id, required this.replayID, required this.gamemode, required this.ts, required this.enemyUsername, required this.enemyID, required this.results}); + + BetaRecord.fromJson(Map json){ + id = json['_id']; + replayID = json['replayid']; + gamemode = json['gamemode']; + ts = DateTime.parse(json['ts']); + enemyUsername = json['otherusers'][0]['username']; + enemyID = json['otherusers'][0]['id']; + results = BetaLeagueResults.fromJson(json['results']); + } +} diff --git a/lib/data_objects/clears.dart b/lib/data_objects/clears.dart new file mode 100644 index 0000000..c63a72a --- /dev/null +++ b/lib/data_objects/clears.dart @@ -0,0 +1,102 @@ +// ignore_for_file: hash_and_equals + +class Clears { + late int singles; + late int doubles; + late int triples; + late int quads; + late int pentas; + late int allClears; + late int tSpinZeros; + late int tSpinSingles; + late int tSpinDoubles; + late int tSpinTriples; + late int tSpinQuads; + late int tSpinPentas; + late int tSpinMiniZeros; + late int tSpinMiniSingles; + late int tSpinMiniDoubles; + late int tSpinMiniTriples; + late int tSpinMiniQuads; + + Clears( + {required this.singles, + required this.doubles, + required this.triples, + required this.quads, + required this.pentas, + required this.allClears, + required this.tSpinZeros, + required this.tSpinSingles, + required this.tSpinDoubles, + required this.tSpinTriples, + required this.tSpinPentas, + required this.tSpinQuads, + required this.tSpinMiniZeros, + required this.tSpinMiniSingles, + required this.tSpinMiniDoubles, + required this.tSpinMiniTriples, + required this.tSpinMiniQuads}); + + Clears.fromJson(Map json) { + singles = json['singles']; + doubles = json['doubles']; + triples = json['triples']; + quads = json['quads']; + pentas = json['pentas']??0; + tSpinZeros = json['realtspins']; + tSpinMiniZeros = json['minitspins']; + tSpinMiniSingles = json['minitspinsingles']; + tSpinSingles = json['tspinsingles']; + tSpinMiniDoubles = json['minitspindoubles']; + tSpinDoubles = json['tspindoubles']; + tSpinMiniTriples = json['minitspintriples']??0; + tSpinTriples = json['tspintriples']; + tSpinMiniQuads = json['minitspinquads']??0; + tSpinQuads = json['tspinquads']; + tSpinPentas = json['tspinpentas']??0; + allClears = json['allclear']; + } + + Clears operator + (Clears other){ + return Clears( + singles: singles + other.singles, + doubles: doubles + other.doubles, + triples: triples + other.triples, + quads: quads + other.quads, + pentas: pentas + other.pentas, + allClears: allClears + other.allClears, + tSpinZeros: tSpinZeros + other.tSpinZeros, + tSpinSingles: tSpinSingles + other.tSpinSingles, + tSpinDoubles: tSpinDoubles + other.tSpinDoubles, + tSpinTriples: tSpinTriples + other.tSpinTriples, + tSpinPentas: tSpinPentas + other.tSpinPentas, + tSpinQuads: tSpinQuads + other.tSpinQuads, + tSpinMiniZeros: tSpinMiniZeros + other.tSpinMiniZeros, + tSpinMiniSingles: tSpinMiniSingles + other.tSpinMiniSingles, + tSpinMiniDoubles: tSpinMiniDoubles + other.tSpinMiniDoubles, + tSpinMiniTriples: tSpinMiniTriples + other.tSpinMiniTriples, + tSpinMiniQuads: tSpinMiniQuads + other.tSpinMiniQuads + ); + } + + Map toJson() { + final Map data = {}; + data['singles'] = singles; + data['doubles'] = doubles; + data['triples'] = triples; + data['quads'] = quads; + data['pentas'] = pentas; + data['realtspins'] = tSpinZeros; + data['minitspins'] = tSpinMiniZeros; + data['minitspinsingles'] = tSpinMiniSingles; + data['tspinsingles'] = tSpinSingles; + data['minitspindoubles'] = tSpinMiniDoubles; + data['tspindoubles'] = tSpinDoubles; + data['tspintriples'] = tSpinTriples; + data['tspinquads'] = tSpinQuads; + data['tspinpentas'] = tSpinPentas; + data['allclear'] = allClears; + return data; + } +} diff --git a/lib/data_objects/connections.dart b/lib/data_objects/connections.dart new file mode 100644 index 0000000..ca0ae83 --- /dev/null +++ b/lib/data_objects/connections.dart @@ -0,0 +1,43 @@ +// ignore_for_file: hash_and_equals + +class Connections { + Discord? discord; + + Connections({this.discord}); + + Connections.fromJson(Map json) { + discord = json['discord'] != null ? Discord.fromJson(json['discord']) : null; + } + @override + bool operator ==(covariant Connections other) => discord == other.discord; + + Map toJson() { + final Map data = {}; + if (discord != null) { + data['discord'] = discord!.toJson(); + } + return data; + } +} + +class Discord { + late String id; + late String username; + + Discord({required this.id, required this.username}); + + Discord.fromJson(Map json) { + id = json['id']; + username = json['username']; + } + + @override + bool operator ==(covariant Discord other) => id == other.id; + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['username'] = username; + return data; + } +} diff --git a/lib/data_objects/cutoff_tetrio.dart b/lib/data_objects/cutoff_tetrio.dart new file mode 100644 index 0000000..586192a --- /dev/null +++ b/lib/data_objects/cutoff_tetrio.dart @@ -0,0 +1,42 @@ +// ignore_for_file: hash_and_equals + +class CutoffTetrio { + late int pos; + late double percentile; + late double tr; + late double targetTr; + late double apm; + late double pps; + late double vs; + late int count; + late double countPercentile; + + CutoffTetrio.fromJson(Map json, int total){ + pos = json['pos']; + percentile = json['percentile'].toDouble(); + tr = json['tr'].toDouble(); + targetTr = json['targettr'].toDouble(); + apm = json['apm'].toDouble(); + pps = json['pps'].toDouble(); + vs = json['vs'].toDouble(); + count = json['count']; + countPercentile = count / total; + } +} + +class CutoffsTetrio { + late String id; + late DateTime timestamp; + late int total; + Map data = {}; + + CutoffsTetrio.fromJson(Map json){ + id = json['s']; + timestamp = DateTime.parse(json['t']); + total = json['data']['total']; + json['data'].remove("total"); + for (String rank in json['data'].keys){ + data[rank] = CutoffTetrio.fromJson(json['data'][rank], total); + } + } +} \ No newline at end of file diff --git a/lib/data_objects/distinguishment.dart b/lib/data_objects/distinguishment.dart new file mode 100644 index 0000000..143ad17 --- /dev/null +++ b/lib/data_objects/distinguishment.dart @@ -0,0 +1,29 @@ +// ignore_for_file: hash_and_equals + +class Distinguishment { + late String type; + String? detail; + String? header; + String? footer; + + Distinguishment({required this.type, this.detail, this.header, this.footer}); + + Distinguishment.fromJson(Map json) { + type = json['type']; + detail = json['detail']; + header = json['header']; + footer = json['footer']; + } + + @override + bool operator ==(covariant Distinguishment other) => type == other.type && detail == other.detail && header == other.header && footer == other.footer; + + Map toJson() { + final Map data = {}; + data['type'] = type; + data['detail'] = detail; + data['header'] = header; + data['footer'] = footer; + return data; + } +} diff --git a/lib/data_objects/end_context_multi.dart b/lib/data_objects/end_context_multi.dart new file mode 100644 index 0000000..d92c2d3 --- /dev/null +++ b/lib/data_objects/end_context_multi.dart @@ -0,0 +1,97 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/handling.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; + +class EndContextMulti { + late String userId; + late String username; + late int naturalOrder; + late int inputs; + late int piecesPlaced; + late Handling handling; + late int points; + late int wins; + late double secondary; + late List secondaryTracking; + late double tertiary; + late List tertiaryTracking; + late double extra; + late List extraTracking; + late bool success; + late NerdStats nerdStats; + late List nerdStatsTracking; + late EstTr estTr; + late List estTrTracking; + late Playstyle playstyle; + late List playstyleTracking; + + EndContextMulti( + {required this.userId, + required this.username, + required this.naturalOrder, + required this.inputs, + required this.piecesPlaced, + required this.handling, + required this.points, + required this.wins, + required this.secondary, + required this.secondaryTracking, + required this.tertiary, + required this.tertiaryTracking, + required this.extra, + required this.extraTracking, + required this.success}){ + nerdStats = NerdStats(secondary, tertiary, extra); + nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])]; + estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)]; + playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)]; + } + + EndContextMulti.fromJson(Map json) { + userId = json['id'] ?? json['user']['_id']; + username = json['username'] ?? json['user']['username']; + handling = json['handling'] != null ? Handling.fromJson(json['handling']) : Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true); + success = json['success']; + inputs = json['inputs'] ?? -1; + piecesPlaced = json['piecesplaced'] ?? -1; + naturalOrder = json['naturalorder']; + wins = json['wins']; + points = json['points']['primary']; + secondary = json['points']['secondary'].toDouble(); + tertiary = json['points']['tertiary'].toDouble(); + secondaryTracking = json['points']['secondaryAvgTracking'] != null ? json['points']['secondaryAvgTracking'].map((e) => e.toDouble()).toList() : []; + tertiaryTracking = json['points']['tertiaryAvgTracking'] != null ? json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList() : []; + extra = json['points']['extra']['vs'].toDouble(); + extraTracking = json['points']['extraAvgTracking'] != null ? json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList() : []; + nerdStats = NerdStats(secondary, tertiary, extra); + nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])]; + estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)]; + playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)]; + } + + @override + bool operator == (covariant EndContextMulti other){ + if (userId != other.userId) return false; + return true; + } + + Map toJson() { + final Map data = {}; + data['user'] = {'_id': userId, 'username': username}; + data['handling'] = handling.toJson(); + data['success'] = success; + data['inputs'] = inputs; + data['piecesplaced'] = piecesPlaced; + data['naturalorder'] = naturalOrder; + data['wins'] = wins; + data['points'] = {'primary': points, 'secondary': secondary, 'tertiary':tertiary, 'extra': {'vs': extra}, 'secondaryAvgTracking': secondaryTracking, 'tertiaryAvgTracking': tertiaryTracking, 'extraAvgTracking': {'aggregatestats___vsscore': extraTracking}}; + return data; + } +} diff --git a/lib/data_objects/est_tr.dart b/lib/data_objects/est_tr.dart new file mode 100644 index 0000000..d378a4a --- /dev/null +++ b/lib/data_objects/est_tr.dart @@ -0,0 +1,39 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; + +class EstTr { + late double esttr; + late double srarea; + late double statrank; + late double estglicko; + + EstTr(double apm, double pps, double vs, double app, double dss, double dsp, double gbe) { + srarea = (apm * 0) + (pps * 135) + (vs * 0) + (app * 290) + (dss * 0) + (dsp * 700) + (gbe * 0); + statrank = 11.2 * atan((srarea - 93) / 130) + 1; + if (statrank <= 0) statrank = 0.001; + //estglicko = (4.0867 * srarea + 186.68); + double ntemp = pps*(150+(((vs/apm) - 1.66)*35))+app*290+dsp*700; + estglicko = 0.000013*pow(ntemp, 3) - 0.0196 *pow(ntemp, 2) + (12.645*ntemp)-1005.4; + esttr = 25000 / + ( + 1 + pow(10, ( + ( + ( + 1500-estglicko + )*pi + )/sqrt( + ( + ( + 3*pow(ln10, 2) + )*pow(60, 2) + )+( + 2500*( + (64*pow(pi,2))+(147*pow(ln10, 2)) + ) + ) + ) + )) + ); + } +} diff --git a/lib/data_objects/finesse.dart b/lib/data_objects/finesse.dart new file mode 100644 index 0000000..6e982b5 --- /dev/null +++ b/lib/data_objects/finesse.dart @@ -0,0 +1,29 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; + +class Finesse { + late int combo; + late int faults; + late int perfectPieces; + + Finesse({required this.combo, required this.faults, required this.perfectPieces}); + + Finesse.fromJson(Map json) { + combo = json['combo']; + faults = json['faults']; + perfectPieces = json['perfectpieces']; + } + + Finesse operator + (Finesse other){ + return Finesse(combo: max(combo, other.combo), faults: faults + other.faults, perfectPieces: perfectPieces + other.perfectPieces); + } + + Map toJson() { + final Map data = {}; + data['combo'] = combo; + data['faults'] = faults; + data['perfectpieces'] = perfectPieces; + return data; + } +} diff --git a/lib/data_objects/handling.dart b/lib/data_objects/handling.dart new file mode 100644 index 0000000..345f3e7 --- /dev/null +++ b/lib/data_objects/handling.dart @@ -0,0 +1,32 @@ +// ignore_for_file: hash_and_equals + +class Handling { + late num arr; + late num das; + late num sdf; + late num dcd; + late bool cancel; + late bool safeLock; + + Handling({required this.arr, required this.das, required this.sdf, required this.dcd, required this.cancel, required this.safeLock}); + + Handling.fromJson(Map json) { + arr = json['arr']; + das = json['das']; + dcd = json['dcd']; + sdf = json['sdf']; + safeLock = json['safelock']; + cancel = json['cancel']; + } + + Map toJson() { + final Map data = {}; + data['arr'] = arr.toDouble(); + data['das'] = das.toDouble(); + data['dcd'] = dcd.toDouble(); + data['sdf'] = sdf.toDouble(); + data['safelock'] = safeLock; + data['cancel'] = cancel; + return data; + } +} diff --git a/lib/data_objects/leaderboard_position.dart b/lib/data_objects/leaderboard_position.dart new file mode 100644 index 0000000..3d9e76f --- /dev/null +++ b/lib/data_objects/leaderboard_position.dart @@ -0,0 +1,8 @@ +// ignore_for_file: hash_and_equals + +class LeaderboardPosition{ + int position; + double percentage; + + LeaderboardPosition(this.position, this.percentage); +} diff --git a/lib/data_objects/nerd_stats.dart b/lib/data_objects/nerd_stats.dart new file mode 100644 index 0000000..6ad8730 --- /dev/null +++ b/lib/data_objects/nerd_stats.dart @@ -0,0 +1,28 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; +import 'package:vector_math/vector_math.dart'; + +class NerdStats { + late double app; + late double vsapm; + late double dss; + late double dsp; + late double appdsp; + late double cheese; + late double gbe; + late double nyaapp; + late double area; + + NerdStats(double apm, double pps, double vs) { + app = apm / (pps * 60); + vsapm = vs / apm; + dss = (vs / 100) - (apm / 60); + dsp = ((vs / 100) - (apm / 60)) / pps; + appdsp = app + dsp; + cheese = (dsp * 150) + ((vsapm - 2) * 50) + (0.6 - app) * 125; + gbe = app * dsp * 2; + nyaapp = app - 5 * tan(radians((cheese / -30) + 1)); + area = apm * 1 + pps * 45 + vs * 0.444 + app * 185 + dss * 175 + dsp * 450 + gbe * 315; + } +} diff --git a/lib/data_objects/news.dart b/lib/data_objects/news.dart new file mode 100644 index 0000000..ccbca45 --- /dev/null +++ b/lib/data_objects/news.dart @@ -0,0 +1,15 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/news_entry.dart'; + +class News{ + late String id; + late List news; + + News(this.id, this.news); + + News.fromJson(Map json, String? userID){ + id = userID != null ? "user_$userID" : json['news'].first['stream']; + news = [for (var entry in json['news']) NewsEntry.fromJson(entry)]; + } +} diff --git a/lib/data_objects/news_entry.dart b/lib/data_objects/news_entry.dart new file mode 100644 index 0000000..6d125f1 --- /dev/null +++ b/lib/data_objects/news_entry.dart @@ -0,0 +1,15 @@ +// ignore_for_file: hash_and_equals + +class NewsEntry { + late String type; + late Map data; + late DateTime timestamp; + + NewsEntry({required this.type, required this.data, required this.timestamp}); + + NewsEntry.fromJson(Map json){ + type = json["type"]; + data = json["data"]; + timestamp = DateTime.parse(json['ts']); + } +} diff --git a/lib/data_objects/tetra_stats.dart b/lib/data_objects/p1nkl0bst3r.dart similarity index 100% rename from lib/data_objects/tetra_stats.dart rename to lib/data_objects/p1nkl0bst3r.dart diff --git a/lib/data_objects/player_leaderboard_position.dart b/lib/data_objects/player_leaderboard_position.dart new file mode 100644 index 0000000..4a79fa9 --- /dev/null +++ b/lib/data_objects/player_leaderboard_position.dart @@ -0,0 +1,63 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/leaderboard_position.dart'; + +class PlayerLeaderboardPosition{ + late LeaderboardPosition? apm; + late LeaderboardPosition? pps; + late LeaderboardPosition? vs; + late LeaderboardPosition? gamesPlayed; + late LeaderboardPosition? gamesWon; + late LeaderboardPosition? winrate; + late LeaderboardPosition? app; + late LeaderboardPosition? vsapm; + late LeaderboardPosition? dss; + late LeaderboardPosition? dsp; + late LeaderboardPosition? appdsp; + late LeaderboardPosition? cheese; + late LeaderboardPosition? gbe; + late LeaderboardPosition? nyaapp; + late LeaderboardPosition? area; + late LeaderboardPosition? estTr; + late LeaderboardPosition? accOfEst; + + PlayerLeaderboardPosition({ + required this.apm, + required this.pps, + required this.vs, + required this.gamesPlayed, + required this.gamesWon, + required this.winrate, + required this.app, + required this.vsapm, + required this.dss, + required this.dsp, + required this.appdsp, + required this.cheese, + required this.gbe, + required this.nyaapp, + required this.area, + required this.estTr, + required this.accOfEst + }); + + PlayerLeaderboardPosition.fromSearchResults(List results){ + apm = results[0]; + pps = results[1]; + vs = results[2]; + gamesPlayed = results[3]; + gamesWon = results[4]; + winrate = results[5]; + app = results[6]; + vsapm = results[7]; + dss = results[8]; + dsp = results[9]; + appdsp = results[10]; + cheese = results[11]; + gbe = results[12]; + nyaapp = results[13]; + area = results[14]; + estTr = results[15]; + accOfEst = results[16]; + } +} diff --git a/lib/data_objects/playstyle.dart b/lib/data_objects/playstyle.dart new file mode 100644 index 0000000..89cf43e --- /dev/null +++ b/lib/data_objects/playstyle.dart @@ -0,0 +1,25 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; + +class Playstyle { + late double opener; + late double plonk; + late double stride; + late double infds; + + Playstyle(double apm, double pps, double app, double vsapm, double dsp, double gbe, double srarea, double statrank) { + double nmapm = ((apm / srarea) / ((0.069 * pow(1.0017, (pow(statrank, 5) / 4700))) + statrank / 360)) - 1; + double nmpps = ((pps / srarea) / (0.0084264 * pow(2.14, (-2 * (statrank / 2.7 + 1.03))) - statrank / 5750 + 0.0067)) - 1; + //double nmvs = ((vs / srarea) / (0.1333 * pow(1.0021, ((pow(statrank, 7) * (statrank / 16.5)) / 1400000)) + statrank / 133)) - 1; + double nmapp = (app / (0.1368803292 * pow(1.0024, (pow(statrank, 5) / 2800)) + statrank / 54)) - 1; + //double nmdss = (dss / (0.01436466667 * pow(4.1, ((statrank - 9.6) / 2.9)) + statrank / 140 + 0.01)) - 1; + double nmdsp = (dsp / (0.02136327583 * pow(14, ((statrank - 14.75) / 3.9)) + statrank / 152 + 0.022)) - 1; + double nmgbe = (gbe / (statrank / 350 + 0.005948424455 * pow(3.8, ((statrank - 6.1) / 4)) + 0.006)) - 1; + double nmvsapm = (vsapm / (-pow(((statrank - 16) / 36), 2) + 2.133)) - 1; + opener = ((nmapm + nmpps * 0.75 + nmvsapm * -10 + nmapp * 0.75 + nmdsp * -0.25) / 3.5) + 0.5; + plonk = ((nmgbe + nmapp + nmdsp * 0.75 + nmpps * -1) / 2.73) + 0.5; + stride = ((nmapm * -0.25 + nmpps + nmapp * -2 + nmdsp * -0.5) * 0.79) + 0.5; + infds = ((nmdsp + nmapp * -0.75 + nmapm * 0.5 + nmvsapm * 1.5 + nmpps * 0.5) * 0.9) + 0.5; + } +} diff --git a/lib/data_objects/record_extras.dart b/lib/data_objects/record_extras.dart new file mode 100644 index 0000000..4b85b7d --- /dev/null +++ b/lib/data_objects/record_extras.dart @@ -0,0 +1,15 @@ +// ignore_for_file: hash_and_equals + +class RecordExtras{ + +} + +class ZenithExtras extends RecordExtras{ + List mods = []; + + ZenithExtras.fromJson(Map json){ + for (var mod in json["mods"]) { + mods.add(mod); + } + } +} diff --git a/lib/data_objects/record_single.dart b/lib/data_objects/record_single.dart new file mode 100644 index 0000000..92eb304 --- /dev/null +++ b/lib/data_objects/record_single.dart @@ -0,0 +1,50 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/aggregate_stats.dart'; +import 'package:tetra_stats/data_objects/record_extras.dart'; +import 'package:tetra_stats/data_objects/results_stats.dart'; + +class RecordSingle { + late String? userId; + late String replayId; + late String ownId; + late String gamemode; + late DateTime timestamp; + late ResultsStats stats; + late int rank; + late int countryRank; + late AggregateStats aggregateStats; + late RecordExtras extras; + + RecordSingle({required this.userId, required this.replayId, required this.ownId, required this.timestamp, required this.stats, required this.rank, required this.countryRank, required this.aggregateStats}); + + RecordSingle.fromJson(Map json, int ran, int cran) { + ownId = json['_id']; + gamemode = json['gamemode']; + stats = ResultsStats.fromJson(json['results']['stats']); + replayId = json['replayid']; + timestamp = DateTime.parse(json['ts']); + if (json['user'] != null) userId = json['user']['id']; + rank = ran; + countryRank = cran; + aggregateStats = AggregateStats.fromJson(json['results']['aggregatestats']); + var ex = json['extras'] as Map; + switch (ex.keys.firstOrNull){ + case "zenith": + extras = ZenithExtras.fromJson(json['extras']['zenith']); + default: + break; + } + } + + Map toJson() { + final Map data = {}; + data['_id'] = ownId; + data['results']['stats'] = stats.toJson(); + data['ismulti'] = false; + data['replayid'] = replayId; + data['ts'] = timestamp; + data['user_id'] = userId; + return data; + } +} diff --git a/lib/data_objects/results_stats.dart b/lib/data_objects/results_stats.dart new file mode 100644 index 0000000..328da53 --- /dev/null +++ b/lib/data_objects/results_stats.dart @@ -0,0 +1,82 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/clears.dart'; +import 'package:tetra_stats/data_objects/finesse.dart'; +import 'package:tetra_stats/data_objects/zenith_results.dart'; + +class ResultsStats { + late int topBtB; + late int topCombo; + late int holds; + late int inputs; + late int level; + late int piecesPlaced; + late int lines; + late int score; + double? seed; + late Duration finalTime; + late int tSpins; + late Clears clears; + late int kills; + Finesse? finesse; + ZenithResults? zenith; + + double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000); + double get kpp => inputs / piecesPlaced; + double get spp => score / piecesPlaced; + double get kps => inputs / (finalTime.inMicroseconds / 1000000); + double get finessePercentage => finesse != null ? finesse!.perfectPieces / piecesPlaced : 0; + double get cps => zenith != null ? zenith!.avgrankpts / (finalTime.inMilliseconds / 1000 * 60) : 0; + + ResultsStats( + { + required this.topBtB, + required this.topCombo, + required this.holds, + required this.inputs, + required this.level, + required this.piecesPlaced, + required this.lines, + required this.score, + required this.seed, + required this.finalTime, + required this.tSpins, + required this.clears, + required this.finesse}); + + ResultsStats.fromJson(Map json) { + seed = json['seed']?.toDouble(); + lines = json['lines']; + inputs = json['inputs']; + holds = json['holds'] ?? 0; + finalTime = Duration(microseconds: (json['finaltime'].toDouble() * 1000).floor()); + score = json['score']; + level = json['level']; + topCombo = json['topcombo']; + topBtB = json['topbtb']; + tSpins = json['tspins']; + piecesPlaced = json['piecesplaced']; + clears = Clears.fromJson(json['clears']); + kills = json['kills']; + if (json.containsKey("finesse")) finesse = Finesse.fromJson(json['finesse']); + if (json.containsKey("zenith")) zenith = ZenithResults.fromJson(json['zenith']); + } + + Map toJson() { + final Map data = {}; + data['seed'] = seed; + data['lines'] = lines; + data['inputs'] = inputs; + data['holds'] = holds; + data['score'] = score; + data['level'] = level; + data['topcombo'] = topCombo; + data['topbtb'] = topBtB; + data['tspins'] = tSpins; + data['piecesplaced'] = piecesPlaced; + data['clears'] = clears.toJson(); + if (finesse != null) data['finesse'] = finesse!.toJson(); + data['finalTime'] = finalTime; + return data; + } +} diff --git a/lib/data_objects/singleplayer_stream.dart b/lib/data_objects/singleplayer_stream.dart new file mode 100644 index 0000000..a59f74b --- /dev/null +++ b/lib/data_objects/singleplayer_stream.dart @@ -0,0 +1,18 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/record_single.dart'; + +class SingleplayerStream{ + late String userId; + late String type; + late List records; + + SingleplayerStream({required this.userId, required this.records, required this.type}); + + SingleplayerStream.fromJson(List json, String userID, String tp) { + userId = userID; + type = tp; + records = []; + for (var value in json) {records.add(RecordSingle.fromJson(value, -1, -1));} + } +} diff --git a/lib/data_objects/summaries.dart b/lib/data_objects/summaries.dart new file mode 100644 index 0000000..08f5db6 --- /dev/null +++ b/lib/data_objects/summaries.dart @@ -0,0 +1,39 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/achievement.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_zen.dart'; + +class Summaries{ + late String id; + RecordSingle? sprint; + RecordSingle? blitz; + RecordSingle? zenith; + RecordSingle? zenithCareerBest; // leaderboard best, not overall + RecordSingle? zenithEx; + RecordSingle? zenithExCareerBest; // leaderboard best, not overall + late List achievements; + late TetraLeague league; + Map pastLeague = {}; + late TetrioZen zen; + + Summaries(this.id, this.league, this.zen); + + Summaries.fromJson(Map json, String i){ + id = i; + if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']); + if (json['blitz']['record'] != null) blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank'], json['40l']['rank_local']); + if (json['zenith']['record'] != null) zenith = RecordSingle.fromJson(json['zenith']['record'], json['zenith']['rank'], json['zenith']['rank_local']); + if (json['zenith']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenith']['best']['record'], json['zenith']['best']['rank'], -1); + if (json['zenithex']['record'] != null) zenithEx = RecordSingle.fromJson(json['zenithex']['record'], json['zenithex']['rank'], json['zenithex']['rank_local']); + if (json['zenithex']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenithex']['best']['record'], json['zenith']['best']['rank'], -1); + achievements = [for (var achievement in json['achievements']) Achievement.fromJson(achievement)]; + league = TetraLeague.fromJson(json['league'], DateTime.now(), currentSeason, i); + if (json['league']['past'].isNotEmpty) for (var key in json['league']['past'].keys){ + pastLeague[int.parse(key)] = TetraLeague.fromJson(json['league']['past'][key], DateTime(1970), int.parse(json['league']['past'][key]['season']), i); + } + zen = TetrioZen.fromJson(json['zen']); + } +} diff --git a/lib/data_objects/tetra_league.dart b/lib/data_objects/tetra_league.dart new file mode 100644 index 0000000..0419fd8 --- /dev/null +++ b/lib/data_objects/tetra_league.dart @@ -0,0 +1,139 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart'; + +class TetraLeague { + late String id; + late DateTime timestamp; + late int gamesPlayed; + late int gamesWon; + late String bestRank; + late bool decaying; + late double tr; + late double gxe; + late String rank; + double? glicko; + double? rd; + late String percentileRank; + late double percentile; + late int standing; + late int standingLocal; + String? nextRank; + late int nextAt; + String? prevRank; + late int prevAt; + double? apm; + double? pps; + double? vs; + NerdStats? nerdStats; + EstTr? estTr; + Playstyle? playstyle; + late int season; + + TetraLeague( + {required this.id, + required this.timestamp, + required this.gamesPlayed, + required this.gamesWon, + required this.bestRank, + required this.decaying, + required this.tr, + required this.gxe, + required this.rank, + this.glicko, + this.rd, + required this.percentileRank, + required this.percentile, + required this.standing, + required this.standingLocal, + this.nextRank, + required this.nextAt, + this.prevRank, + required this.prevAt, + this.apm, + this.pps, + this.vs, + required this.season}){ + nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null; + estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null; + playstyle =(nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null; + } + + double get winrate => gamesWon / gamesPlayed; + double get s1tr => gxe * 250; + + TetraLeague.fromJson(Map json, ts, int s, String i) { + timestamp = ts; + season = s; + id = i; + gamesPlayed = json['gamesplayed'] ?? 0; + gamesWon = json['gameswon'] ?? 0; + tr = json['tr'] != null ? json['tr'].toDouble() : json['rating'] != null ? json['rating'].toDouble() : -1; + glicko = json['glicko']?.toDouble(); + rd = json['rd'] != null ? json['rd']!.toDouble() : noTrRd; + gxe = json['gxe'] != null ? json['gxe'].toDouble() : -1; + rank = json['rank'] != null ? json['rank']!.toString() : 'z'; + bestRank = json['bestrank'] != null ? json['bestrank']!.toString() : 'z'; + apm = json['apm']?.toDouble(); + pps = json['pps']?.toDouble(); + vs = json['vs']?.toDouble(); + decaying = switch(json['decaying'].runtimeType){ + int => json['decaying'] == 1, + bool => json['decaying'], + _ => false + }; + standing = json['standing'] ?? json['placement'] ?? -1; + percentile = json['percentile'] != null ? json['percentile'].toDouble() : rankCutoffs[rank]; + standingLocal = json['standing_local'] ?? -1; + prevRank = json['prev_rank']; + prevAt = json['prev_at'] ?? -1; + nextRank = json['next_rank']; + nextAt = json['next_at'] ?? -1; + percentileRank = json['percentile_rank'] ?? rank; + nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null; + estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null; + playstyle = (nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null; + } + + @override + bool operator ==(covariant TetraLeague other) => gamesPlayed == other.gamesPlayed && rd == other.rd; + + bool lessStrictCheck (covariant TetraLeague other) => gamesPlayed == other.gamesPlayed && glicko == other.glicko; + + double? get esttracc => (estTr != null) ? estTr!.esttr - tr : null; + + TetrioPlayerFromLeaderboard convertToPlayerFromLeaderboard(String id) => TetrioPlayerFromLeaderboard( + id, "", "user", -1, null, timestamp, gamesPlayed, gamesWon, + tr, gxe, glicko??0, rd??noTrRd, rank, bestRank, apm??0, pps??0, vs??0, decaying); + + Map toJson() { + final Map data = {}; + data['id'] = id+timestamp.millisecondsSinceEpoch.toRadixString(16); + if (gamesPlayed > 0) data['gamesplayed'] = gamesPlayed; + if (gamesWon > 0) data['gameswon'] = gamesWon; + if (tr >= 0) data['tr'] = tr; + if (glicko != null) data['glicko'] = glicko; + if (gxe != -1) data['gxe'] = gxe; + if (rd != null && rd != noTrRd) data['rd'] = rd; + if (rank != 'z') data['rank'] = rank; + if (bestRank != 'z') data['bestrank'] = bestRank; + if (apm != null) data['apm'] = apm; + if (pps != null) data['pps'] = pps; + if (vs != null) data['vs'] = vs; + if (decaying) data['decaying'] = decaying ? 1 : 0; + if (standing >= 0) data['standing'] = standing; + data['percentile'] = percentile; + if (standingLocal >= 0) data['standing_local'] = standingLocal; + if (prevRank != null) data['prev_rank'] = prevRank; + if (prevAt >= 0) data['prev_at'] = prevAt; + if (nextRank != null) data['next_rank'] = nextRank; + if (nextAt >= 0) data['next_at'] = nextAt; + data['percentile_rank'] = percentileRank; + data['season'] = season; + return data; + } +} diff --git a/lib/data_objects/tetra_league_alpha_record.dart b/lib/data_objects/tetra_league_alpha_record.dart new file mode 100644 index 0000000..ad59825 --- /dev/null +++ b/lib/data_objects/tetra_league_alpha_record.dart @@ -0,0 +1,39 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/end_context_multi.dart'; + +class TetraLeagueAlphaRecord{ + late String replayId; + late String ownId; + late DateTime timestamp; + late bool replayAvalable; + late List endContext; + + TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext, required this.replayAvalable}); + + TetraLeagueAlphaRecord.fromJson(Map json) { + endContext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])]; + replayId = json['replayid']; + ownId = json['_id']??replayId; + timestamp = DateTime.parse(json['ts']); + replayAvalable = ownId != replayId; + } + + Map toJson() { + final Map data = {}; + data['_id'] = ownId; + data['endcontext'][0] = endContext[0].toJson(); + data['endcontext'][1] = endContext[1].toJson(); + data['replayid'] = replayId; + data['ts'] = timestamp; + return data; + } + + @override + bool operator ==(covariant TetraLeagueAlphaRecord other) => (ownId == other.ownId) || (replayId == other.replayId); + + @override + String toString() { + return "TetraLeagueAlphaRecord: ${endContext.first.userId} vs ${endContext.last.userId}"; + } +} diff --git a/lib/data_objects/tetra_league_alpha_stream.dart b/lib/data_objects/tetra_league_alpha_stream.dart new file mode 100644 index 0000000..ebce2ac --- /dev/null +++ b/lib/data_objects/tetra_league_alpha_stream.dart @@ -0,0 +1,16 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart'; + +class TetraLeagueAlphaStream{ + late String userId; + late List records; + + TetraLeagueAlphaStream({required this.userId, required this.records}); + + TetraLeagueAlphaStream.fromJson(List json, String userID) { + userId = userID; + records = []; + for (var value in json) {records.add(TetraLeagueAlphaRecord.fromJson(value));} + } +} diff --git a/lib/data_objects/tetra_league_beta_stream.dart b/lib/data_objects/tetra_league_beta_stream.dart new file mode 100644 index 0000000..f51a135 --- /dev/null +++ b/lib/data_objects/tetra_league_beta_stream.dart @@ -0,0 +1,111 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/beta_league_leaderboard_entry.dart'; +import 'package:tetra_stats/data_objects/beta_league_results.dart'; +import 'package:tetra_stats/data_objects/beta_league_round.dart'; +import 'package:tetra_stats/data_objects/beta_league_stats.dart'; +import 'package:tetra_stats/data_objects/beta_record.dart'; +import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart'; + +class TetraLeagueBetaStream{ + late String id; + List records = []; + + TetraLeagueBetaStream({required this.id, required this.records}); + + TetraLeagueBetaStream.fromJson(List json, String userID) { + id = userID; + for (var entry in json) { + records.add(BetaRecord.fromJson(entry)); + } + } + + addFromAlphaStream(List r){ + for (var entry in r) { + records.add( + BetaRecord( + id: entry.ownId, + replayID: entry.replayId, + ts: entry.timestamp, + enemyID: entry.endContext[1].userId, + enemyUsername: entry.endContext[1].username, + gamemode: "oldleague", + results: BetaLeagueResults( + leaderboard: [ + BetaLeagueLeaderboardEntry( + id: entry.endContext[0].userId, + username: entry.endContext[0].username, + naturalorder: entry.endContext[0].naturalOrder, + wins: entry.endContext[0].points, + stats: BetaLeagueStats( + apm: entry.endContext[0].secondary, + pps: entry.endContext[0].tertiary, + vs: entry.endContext[0].extra, + garbageSent: -1, + garbageReceived: -1, + kills: entry.endContext[0].points, + altitude: 0.0, + rank: -1 + ) + ), + BetaLeagueLeaderboardEntry( + id: entry.endContext[1].userId, + username: entry.endContext[1].username, + naturalorder: entry.endContext[1].naturalOrder, + wins: entry.endContext[1].points, + stats: BetaLeagueStats( + apm: entry.endContext[1].secondary, + pps: entry.endContext[1].tertiary, + vs: entry.endContext[1].extra, + garbageSent: -1, + garbageReceived: -1, + kills: entry.endContext[1].points, + altitude: 0.0, + rank: -1 + ) + ) + ], + rounds: [ + for (int i=0; i ranks = [ - "d", "d+", "c-", "c", "c+", "b-", "b", "b+", "a-", "a", "a+", "s-", "s", "s+", "ss", "u", "x", "x+" -]; -const Map rankCutoffs = { - "x+": 0.002, - "x": 0.01, - "u": 0.05, - "ss": 0.11, - "s+": 0.17, - "s": 0.23, - "s-": 0.3, - "a+": 0.38, - "a": 0.46, - "a-": 0.54, - "b+": 0.62, - "b": 0.7, - "b-": 0.78, - "c+": 0.84, - "c": 0.9, - "c-": 0.95, - "d+": 0.975, - "d": 1, - "z": -1, - "": 0.5 -}; -const Map rankTargets = { - "x+": 24000.00, - "x": 22500.00, - "u": 20000.00, - "ss": 18000.00, - "s+": 16500.00, - "s": 15200.00, - "s-": 13800.00, - "a+": 12000.00, - "a": 10500.00, - "a-": 9000.00, - "b+": 7400.00, - "b": 5700.00, - "b-": 4200.00, - "c+": 3000.00, - "c": 2000.00, - "c-": 1300.00, - "d+": 800.00, - "d": 0.00, -}; -// DateTime seasonStart = DateTime.utc(2024, 08, 16, 18); -//DateTime seasonEnd = DateTime.utc(2024, 07, 26, 15); -enum Stats { - tr, - glicko, - gxe, - s1tr, - rd, - gp, - gw, - wr, - apm, - pps, - vs, - app, - dss, - dsp, - appdsp, - vsapm, - cheese, - gbe, - nyaapp, - area, - eTR, - acceTR, - acceTRabs, - opener, - plonk, - infDS, - stride, - stridemMinusPlonk, - openerMinusInfDS - } - -const Map chartsShortTitles = { - Stats.tr: "TR", - Stats.gxe: "Glixare", - Stats.s1tr: "S1 TR", - Stats.glicko: "Glicko", - Stats.rd: "RD", - Stats.gp: "GP", - Stats.gw: "GW", - Stats.wr: "WR%", - Stats.apm: "APM", - Stats.pps: "PPS", - Stats.vs: "VS", - Stats.app: "APP", - Stats.dss: "DS/S", - Stats.dsp: "DS/P", - Stats.appdsp: "APP + DS/P", - Stats.vsapm: "VS/APM", - Stats.cheese: "Cheese", - Stats.gbe: "GbE", - Stats.nyaapp: "wAPP", - Stats.area: "Area", - Stats.eTR: "eTR", - Stats.acceTR: "±eTR", - Stats.acceTRabs: "+eTR absolute", - Stats.opener: "Opener", - Stats.plonk: "Plonk", - Stats.infDS: "Inf. DS", - Stats.stride: "Stride", - Stats.stridemMinusPlonk: "Stride - Plonk", - Stats.openerMinusInfDS: "Opener - Inf. DS" - }; - -const Map rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:458 - 'x+': Color(0xFF643C8D), - 'x': Color(0xFFFF45FF), - 'u': Color(0xFFFF3813), - 'ss': Color(0xFFDB8B1F), - 's+': Color(0xFFD8AF0E), - 's': Color(0xFFE0A71B), - 's-': Color(0xFFB2972B), - 'a+': Color(0xFF1FA834), - 'a': Color(0xFF46AD51), - 'a-': Color(0xFF3BB687), - 'b+': Color(0xFF4F99C0), - 'b': Color(0xFF4F64C9), - 'b-': Color(0xFF5650C7), - 'c+': Color(0xFF552883), - 'c': Color(0xFF733E8F), - 'c-': Color(0xFF79558C), - 'd+': Color(0xFF8E6091), - 'd': Color(0xFF907591), - 'z': Color(0xFF375433) -}; - -const Map sprintAverages = { // based on https://discord.com/channels/673303546107658242/674421736162197515/1244287342965952562 - 'x': Duration(seconds: 25, milliseconds: 144), - 'u': Duration(seconds: 36, milliseconds: 115), - 'ss': Duration(seconds: 46, milliseconds: 396), - 's+': Duration(seconds: 55, milliseconds: 056), - 's': Duration(seconds: 61, milliseconds: 892), - 's-': Duration(seconds: 68, milliseconds: 918), - 'a+': Duration(seconds: 76, milliseconds: 187), - 'a': Duration(seconds: 83, milliseconds: 529), - 'a-': Duration(seconds: 88, milliseconds: 608), - 'b+': Duration(seconds: 97, milliseconds: 626), - 'b': Duration(seconds: 104, milliseconds: 687), - 'b-': Duration(seconds: 113, milliseconds: 372), - 'c+': Duration(seconds: 123, milliseconds: 461), - 'c': Duration(seconds: 135, milliseconds: 326), - 'c-': Duration(seconds: 147, milliseconds: 056), - 'd+': Duration(seconds: 156, milliseconds: 757), - 'd': Duration(seconds: 167, milliseconds: 393), - //'z': Duration(seconds: 66, milliseconds: 802) -}; - -const Map blitzAverages = { - 'x': 600715, - 'u': 379418, - 'ss': 233740, - 's+': 158295, - 's': 125164, - 's-': 100933, - 'a+': 83593, - 'a': 68613, - 'a-': 60219, - 'b+': 51197, - 'b': 44171, - 'b-': 39045, - 'c+': 34130, - 'c': 28931, - 'c-': 25095, - 'd+': 22944, - 'd': 20728, - //'z': 72084 -}; - -String getStatNameByEnum(Stats stat){ - return t[stat.name]; -} - -Duration doubleSecondsToDuration(double value) { - value = value * 1000000; - return Duration(microseconds: value.floor()); -} - -Duration doubleMillisecondsToDuration(double value) { - value = value * 1000; - return Duration(microseconds: value.floor()); -} - -class TetrioPlayer { - late String userId; - late String username; - late DateTime state; - late String role; - int? avatarRevision; - int? bannerRevision; - DateTime? registrationTime; - List badges = []; - String? bio; - String? country; - late int friendCount; - late int gamesPlayed; - late int gamesWon; - late Duration gameTime; - late double xp; - late int supporterTier; - late bool verified; - bool? badstanding; - String? botmaster; - Connections? connections; - TetrioZen? zen; - Distinguishment? distinguishment; - DateTime? cachedUntil; - - TetrioPlayer({ - required this.userId, - required this.username, - required this.role, - required this.state, - this.avatarRevision, - this.bannerRevision, - this.registrationTime, - required this.badges, - this.bio, - this.country, - required this.friendCount, - required this.gamesPlayed, - required this.gamesWon, - required this.gameTime, - required this.xp, - required this.supporterTier, - required this.verified, - this.badstanding, - this.botmaster, - required this.connections, - this.zen, - this.distinguishment, - this.cachedUntil - }); - - double get level => pow((xp / 500), 0.6) + (xp / (5000 + (max(0, xp - 4 * pow(10, 6)) / 5000))) + 1; - - TetrioPlayer.fromJson(Map json, DateTime stateTime, String id, String nick, [DateTime? cUntil]) { - //developer.log("TetrioPlayer.fromJson $stateTime: $json", name: "data_objects/tetrio"); - userId = id; - username = nick; - state = stateTime; - role = json['role']; - registrationTime = json['ts'] != null ? DateTime.parse(json['ts']) : DateTime.fromMillisecondsSinceEpoch(int.parse(id.substring(0, 8), radix: 16) * 1000); - if (json['badges'] != null) { - json['badges'].forEach((v) { - badges.add(Badge.fromJson(v)); - }); - } - xp = json['xp'] != null ? json['xp'].toDouble() : -1; - gamesPlayed = json['gamesplayed'] ?? -1; - gamesWon = json['gameswon'] ?? -1; - gameTime = json['gametime'] != null && json['gametime'] != -1 ? doubleSecondsToDuration(json['gametime'].toDouble()) : const Duration(seconds: -1); - country = json['country']; - supporterTier = json['supporter_tier'] ?? 0; - verified = json['verified'] ?? false; - avatarRevision = json['avatar_revision']; - bannerRevision = json['banner_revision']; - bio = json['bio']; - if (json['connections'] != null && json['connections'].isNotEmpty) connections = Connections.fromJson(json['connections']); - distinguishment = json['distinguishment'] != null ? Distinguishment.fromJson(json['distinguishment']) : null; - friendCount = json['friend_count'] ?? 0; - badstanding = json['badstanding']; - botmaster = json['botmaster']; - cachedUntil = cUntil; - } - - Map toJson() { - final Map data = {}; - // data['_id'] = userId; - // data['username'] = username; - data['role'] = role; - if (registrationTime != null) data['ts'] = registrationTime?.toString(); - if (badges.isNotEmpty) data['badges'] = badges.map((v) => v.toJson()).toList(); - if (xp >= 0) data['xp'] = xp; - if (gamesPlayed >= 0) data['gamesplayed'] = gamesPlayed; - if (gamesWon >= 0) data['gameswon'] = gamesWon; - if (!gameTime.isNegative) data['gametime'] = gameTime.inMicroseconds / 1000000; - if (country != null) data['country'] = country; - if (supporterTier > 0) data['supporter_tier'] = supporterTier; - if (verified) data['verified'] = verified; - if (distinguishment != null) data['distinguishment'] = distinguishment?.toJson(); - if (avatarRevision != null) data['avatar_revision'] = avatarRevision; - if (bannerRevision != null) data['banner_revision'] = bannerRevision; - if (bio != null) data['bio'] = bio; - if (connections != null) data['connections'] = connections!.toJson(); - if (friendCount > 0) data['friend_count'] = friendCount; - if (badstanding != null) data['badstanding'] = badstanding; - if (botmaster != null) data['botmaster'] = botmaster; - //developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio"); - return data; - } - - bool isSameState(covariant TetrioPlayer other) { - if (userId != other.userId) return false; - if (username != other.username) return false; - if (role != other.role) return false; - if (listEquals(badges, other.badges) == false) return false; - //if (bio != other.bio) return false; - if (country != other.country) return false; - if (friendCount != other.friendCount) return false; - if (gamesPlayed != other.gamesPlayed) return false; - if (gamesWon != other.gamesWon) return false; - if (gameTime != other.gameTime) return false; - if (xp != other.xp) return false; - if (supporterTier != other.supporterTier) return false; - if (verified != other.verified) return false; - if (badstanding != other.badstanding) return false; - if (botmaster != other.botmaster) return false; - if (connections != other.connections) return false; - if (distinguishment != other.distinguishment) return false; - return true; - } - - @override - String toString() { - return "$username ($state)"; - } - - @override - int get hashCode => state.hashCode; - - @override - bool operator ==(covariant TetrioPlayer other) => isSameState(other) && state.isAtSameMomentAs(other.state); -} - -class Summaries{ - late String id; - RecordSingle? sprint; - RecordSingle? blitz; - RecordSingle? zenith; - RecordSingle? zenithCareerBest; // leaderboard best, not overall - RecordSingle? zenithEx; - RecordSingle? zenithExCareerBest; // leaderboard best, not overall - late List achievements; - late TetraLeague league; - late TetrioZen zen; - - Summaries(this.id, this.league, this.zen); - - Summaries.fromJson(Map json, String i){ - id = i; - if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']); - if (json['blitz']['record'] != null) blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank'], json['40l']['rank_local']); - if (json['zenith']['record'] != null) zenith = RecordSingle.fromJson(json['zenith']['record'], json['zenith']['rank'], json['zenith']['rank_local']); - if (json['zenith']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenith']['best']['record'], json['zenith']['best']['rank'], -1); - if (json['zenithex']['record'] != null) zenithEx = RecordSingle.fromJson(json['zenithex']['record'], json['zenithex']['rank'], json['zenithex']['rank_local']); - if (json['zenithex']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenithex']['best']['record'], json['zenith']['best']['rank'], -1); - achievements = [for (var achievement in json['achievements']) Achievement.fromJson(achievement)]; - league = TetraLeague.fromJson(json['league'], DateTime.now(), currentSeason, i); - zen = TetrioZen.fromJson(json['zen']); - } -} - -class Badge { - late String badgeId; - late String label; - DateTime? ts; - - Badge({required this.badgeId, required this.label, this.ts}); - - Badge.fromJson(Map json) { - badgeId = json['id']; - label = json['label']; - ts = (json['ts'] != null && json['ts'] is String) ? DateTime.parse(json['ts']) : null; // man i love osk - } - - Map toJson() { - final Map data = {}; - data['id'] = badgeId; - data['label'] = label; - data['ts'] = ts?.toString(); - return data; - } - - @override - String toString() { - return "Badge $label ($badgeId)"; - } - - @override - int get hashCode => badgeId.hashCode; - - @override - bool operator ==(covariant Badge other) => badgeId == other.badgeId; -} - -class Connections { - Discord? discord; - - Connections({this.discord}); - - Connections.fromJson(Map json) { - discord = json['discord'] != null ? Discord.fromJson(json['discord']) : null; - } - @override - bool operator ==(covariant Connections other) => discord == other.discord; - - Map toJson() { - final Map data = {}; - if (discord != null) { - data['discord'] = discord!.toJson(); - } - return data; - } -} - -class Clears { - late int singles; - late int doubles; - late int triples; - late int quads; - late int pentas; - late int allClears; - late int tSpinZeros; - late int tSpinSingles; - late int tSpinDoubles; - late int tSpinTriples; - late int tSpinQuads; - late int tSpinPentas; - late int tSpinMiniZeros; - late int tSpinMiniSingles; - late int tSpinMiniDoubles; - late int tSpinMiniTriples; - late int tSpinMiniQuads; - - Clears( - {required this.singles, - required this.doubles, - required this.triples, - required this.quads, - required this.pentas, - required this.allClears, - required this.tSpinZeros, - required this.tSpinSingles, - required this.tSpinDoubles, - required this.tSpinTriples, - required this.tSpinPentas, - required this.tSpinQuads, - required this.tSpinMiniZeros, - required this.tSpinMiniSingles, - required this.tSpinMiniDoubles, - required this.tSpinMiniTriples, - required this.tSpinMiniQuads}); - - Clears.fromJson(Map json) { - singles = json['singles']; - doubles = json['doubles']; - triples = json['triples']; - quads = json['quads']; - pentas = json['pentas']??0; - tSpinZeros = json['realtspins']; - tSpinMiniZeros = json['minitspins']; - tSpinMiniSingles = json['minitspinsingles']; - tSpinSingles = json['tspinsingles']; - tSpinMiniDoubles = json['minitspindoubles']; - tSpinDoubles = json['tspindoubles']; - tSpinMiniTriples = json['minitspintriples']??0; - tSpinTriples = json['tspintriples']; - tSpinMiniQuads = json['minitspinquads']??0; - tSpinQuads = json['tspinquads']; - tSpinPentas = json['tspinpentas']??0; - allClears = json['allclear']; - } - - Clears operator + (Clears other){ - return Clears( - singles: singles + other.singles, - doubles: doubles + other.doubles, - triples: triples + other.triples, - quads: quads + other.quads, - pentas: pentas + other.pentas, - allClears: allClears + other.allClears, - tSpinZeros: tSpinZeros + other.tSpinZeros, - tSpinSingles: tSpinSingles + other.tSpinSingles, - tSpinDoubles: tSpinDoubles + other.tSpinDoubles, - tSpinTriples: tSpinTriples + other.tSpinTriples, - tSpinPentas: tSpinPentas + other.tSpinPentas, - tSpinQuads: tSpinQuads + other.tSpinQuads, - tSpinMiniZeros: tSpinMiniZeros + other.tSpinMiniZeros, - tSpinMiniSingles: tSpinMiniSingles + other.tSpinMiniSingles, - tSpinMiniDoubles: tSpinMiniDoubles + other.tSpinMiniDoubles, - tSpinMiniTriples: tSpinMiniTriples + other.tSpinMiniTriples, - tSpinMiniQuads: tSpinMiniQuads + other.tSpinMiniQuads - ); - } - - Map toJson() { - final Map data = {}; - data['singles'] = singles; - data['doubles'] = doubles; - data['triples'] = triples; - data['quads'] = quads; - data['pentas'] = pentas; - data['realtspins'] = tSpinZeros; - data['minitspins'] = tSpinMiniZeros; - data['minitspinsingles'] = tSpinMiniSingles; - data['tspinsingles'] = tSpinSingles; - data['minitspindoubles'] = tSpinMiniDoubles; - data['tspindoubles'] = tSpinDoubles; - data['tspintriples'] = tSpinTriples; - data['tspinquads'] = tSpinQuads; - data['tspinpentas'] = tSpinPentas; - data['allclear'] = allClears; - return data; - } -} - -class Discord { - late String id; - late String username; - - Discord({required this.id, required this.username}); - - Discord.fromJson(Map json) { - id = json['id']; - username = json['username']; - } - - @override - bool operator ==(covariant Discord other) => id == other.id; - - Map toJson() { - final Map data = {}; - data['id'] = id; - data['username'] = username; - return data; - } -} - -class Finesse { - late int combo; - late int faults; - late int perfectPieces; - - Finesse({required this.combo, required this.faults, required this.perfectPieces}); - - Finesse.fromJson(Map json) { - combo = json['combo']; - faults = json['faults']; - perfectPieces = json['perfectpieces']; - } - - Finesse operator + (Finesse other){ - return Finesse(combo: max(combo, other.combo), faults: faults + other.faults, perfectPieces: perfectPieces + other.perfectPieces); - } - - Map toJson() { - final Map data = {}; - data['combo'] = combo; - data['faults'] = faults; - data['perfectpieces'] = perfectPieces; - return data; - } -} - -class ResultsStats { - late int topBtB; - late int topCombo; - late int holds; - late int inputs; - late int level; - late int piecesPlaced; - late int lines; - late int score; - double? seed; - late Duration finalTime; - late int tSpins; - late Clears clears; - late int kills; - Finesse? finesse; - ZenithResults? zenith; - - double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000); - double get kpp => inputs / piecesPlaced; - double get spp => score / piecesPlaced; - double get kps => inputs / (finalTime.inMicroseconds / 1000000); - double get finessePercentage => finesse != null ? finesse!.perfectPieces / piecesPlaced : 0; - double get cps => zenith != null ? zenith!.avgrankpts / (finalTime.inMilliseconds / 1000 * 60) : 0; - - ResultsStats( - { - required this.topBtB, - required this.topCombo, - required this.holds, - required this.inputs, - required this.level, - required this.piecesPlaced, - required this.lines, - required this.score, - required this.seed, - required this.finalTime, - required this.tSpins, - required this.clears, - required this.finesse}); - - ResultsStats.fromJson(Map json) { - seed = json['seed']?.toDouble(); - lines = json['lines']; - inputs = json['inputs']; - holds = json['holds'] ?? 0; - finalTime = doubleMillisecondsToDuration(json['finaltime'].toDouble()); - score = json['score']; - level = json['level']; - topCombo = json['topcombo']; - topBtB = json['topbtb']; - tSpins = json['tspins']; - piecesPlaced = json['piecesplaced']; - clears = Clears.fromJson(json['clears']); - kills = json['kills']; - if (json.containsKey("finesse")) finesse = Finesse.fromJson(json['finesse']); - if (json.containsKey("zenith")) zenith = ZenithResults.fromJson(json['zenith']); - } - - Map toJson() { - final Map data = {}; - data['seed'] = seed; - data['lines'] = lines; - data['inputs'] = inputs; - data['holds'] = holds; - data['score'] = score; - data['level'] = level; - data['topcombo'] = topCombo; - data['topbtb'] = topBtB; - data['tspins'] = tSpins; - data['piecesplaced'] = piecesPlaced; - data['clears'] = clears.toJson(); - if (finesse != null) data['finesse'] = finesse!.toJson(); - data['finalTime'] = finalTime; - return data; - } -} - -class ZenithResults{ - late double altitude; - late double rank; - late double peakrank; - late double avgrankpts; - late int floor; - late double targetingfactor; - late double targetinggrace; - late double totalbonus; - late int revives; - late int revivesTotal; - late bool speedrun; - late bool speedrunSeen; - late List splits; - - ZenithResults.fromJson(Map json){ - altitude = json['altitude'].toDouble(); - rank = json['rank'].toDouble(); - peakrank = json['peakrank'].toDouble(); - avgrankpts = json['avgrankpts'].toDouble(); - floor = json['floor']; - targetingfactor = json['targetingfactor'].toDouble(); - targetinggrace = json['targetinggrace'].toDouble(); - totalbonus = json['totalbonus'].toDouble(); - revives = json['revives']; - revivesTotal = json['revivesTotal']; - speedrun = json['speedrun']; - speedrunSeen = json['speedrun_seen']; - splits = []; - for (int ms in json['splits']) { - splits.add(Duration(milliseconds: ms)); - } - } -} - -class Handling { - late num arr; - late num das; - late num sdf; - late num dcd; - late bool cancel; - late bool safeLock; - - Handling({required this.arr, required this.das, required this.sdf, required this.dcd, required this.cancel, required this.safeLock}); - - Handling.fromJson(Map json) { - arr = json['arr']; - das = json['das']; - dcd = json['dcd']; - sdf = json['sdf']; - safeLock = json['safelock']; - cancel = json['cancel']; - } - - Map toJson() { - final Map data = {}; - data['arr'] = arr.toDouble(); - data['das'] = das.toDouble(); - data['dcd'] = dcd.toDouble(); - data['sdf'] = sdf.toDouble(); - data['safelock'] = safeLock; - data['cancel'] = cancel; - return data; - } -} - -class NerdStats { - final double _apm; - final double _pps; - final double _vs; - late double app; - late double vsapm; - late double dss; - late double dsp; - late double appdsp; - late double cheese; - late double gbe; - late double nyaapp; - late double area; - - NerdStats(this._apm, this._pps, this._vs) { - app = _apm / (_pps * 60); - vsapm = _vs / _apm; - dss = (_vs / 100) - (_apm / 60); - dsp = ((_vs / 100) - (_apm / 60)) / _pps; - appdsp = app + dsp; - cheese = (dsp * 150) + ((vsapm - 2) * 50) + (0.6 - app) * 125; - gbe = app * dsp * 2; - nyaapp = app - 5 * tan(radians((cheese / -30) + 1)); - area = _apm * 1 + _pps * 45 + _vs * 0.444 + app * 185 + dss * 175 + dsp * 450 + gbe * 315; - } -} - -class EstTr { - final double _apm; - final double _pps; - final double _vs; - final double _app; - final double _dss; - final double _dsp; - final double _gbe; - late double esttr; - late double srarea; - late double statrank; - late double estglicko; - - EstTr(this._apm, this._pps, this._vs, this._app, this._dss, this._dsp, this._gbe) { - srarea = (_apm * 0) + (_pps * 135) + (_vs * 0) + (_app * 290) + (_dss * 0) + (_dsp * 700) + (_gbe * 0); - statrank = 11.2 * atan((srarea - 93) / 130) + 1; - if (statrank <= 0) statrank = 0.001; - //estglicko = (4.0867 * srarea + 186.68); - double ntemp = _pps*(150+(((_vs/_apm) - 1.66)*35))+_app*290+_dsp*700; - estglicko = 0.000013*pow(ntemp, 3) - 0.0196 *pow(ntemp, 2) + (12.645*ntemp)-1005.4; - esttr = 25000 / - ( - 1 + pow(10, ( - ( - ( - 1500-estglicko - )*pi - )/sqrt( - ( - ( - 3*pow(ln10, 2) - )*pow(60, 2) - )+( - 2500*( - (64*pow(pi,2))+(147*pow(ln10, 2)) - ) - ) - ) - )) - ); - } -} - -class Achievement { - late int k; - int? o; - late int rt; - late int vt; - late int min; - late int deci; - late String name; - late String object; - late String category; - late bool hidden; - late int art; - late bool nolb; - late String desc; - late String n; - String? sId; - double? v; - late int? a; - DateTime? t; - int? pos; - int? total; - int? rank; - - Achievement( - {required this.k, - this.o, - required this.rt, - required this.vt, - required this.min, - required this.deci, - required this.name, - required this.object, - required this.category, - required this.hidden, - required this.art, - required this.nolb, - required this.desc, - required this.n, - this.sId, - this.v, - required this.a, - this.t, - this.pos, - this.total, - this.rank}); - - Achievement.fromJson(Map json) { - k = json['k']; - o = json['o']; - rt = json['rt']; - vt = json['vt']; - min = json['min']; - deci = json['deci']; - name = json['name']; - object = json['object']; - category = json['category']; - hidden = json['hidden']; - art = json['art']; - nolb = json['nolb']; - desc = json['desc']; - n = json['n']; - sId = json['_id']; - v = json['v']?.toDouble(); - a = json['a']; - t = json['t'] != null ? DateTime.parse(json['t']) : null; - pos = json['pos']; - total = json['total']; - rank = json['rank']; - } - - Map toJson() { - final Map data = {}; - data['k'] = k; - data['o'] = o; - data['rt'] = rt; - data['vt'] = vt; - data['min'] = min; - data['deci'] = deci; - data['name'] = name; - data['object'] = object; - data['category'] = category; - data['hidden'] = hidden; - data['art'] = art; - data['nolb'] = nolb; - data['desc'] = desc; - data['n'] = n; - data['_id'] = sId; - data['v'] = v; - data['a'] = a; - data['t'] = t.toString(); - data['pos'] = pos; - data['total'] = total; - data['rank'] = rank; - return data; - } -} - - -class Playstyle { - final double _apm; - final double _pps; - //final double _vs; - final double _app; - final double _vsapm; - //final double _dss; - final double _dsp; - final double _gbe; - final double _srarea; - final double _statrank; - late double opener; - late double plonk; - late double stride; - late double infds; - - Playstyle(this._apm, this._pps, this._app, this._vsapm, this._dsp, this._gbe, this._srarea, this._statrank) { - double nmapm = ((_apm / _srarea) / ((0.069 * pow(1.0017, (pow(_statrank, 5) / 4700))) + _statrank / 360)) - 1; - double nmpps = ((_pps / _srarea) / (0.0084264 * pow(2.14, (-2 * (_statrank / 2.7 + 1.03))) - _statrank / 5750 + 0.0067)) - 1; - //double nmvs = ((_vs / _srarea) / (0.1333 * pow(1.0021, ((pow(_statrank, 7) * (_statrank / 16.5)) / 1400000)) + _statrank / 133)) - 1; - double nmapp = (_app / (0.1368803292 * pow(1.0024, (pow(_statrank, 5) / 2800)) + _statrank / 54)) - 1; - //double nmdss = (_dss / (0.01436466667 * pow(4.1, ((_statrank - 9.6) / 2.9)) + _statrank / 140 + 0.01)) - 1; - double nmdsp = (_dsp / (0.02136327583 * pow(14, ((_statrank - 14.75) / 3.9)) + _statrank / 152 + 0.022)) - 1; - double nmgbe = (_gbe / (_statrank / 350 + 0.005948424455 * pow(3.8, ((_statrank - 6.1) / 4)) + 0.006)) - 1; - double nmvsapm = (_vsapm / (-pow(((_statrank - 16) / 36), 2) + 2.133)) - 1; - opener = ((nmapm + nmpps * 0.75 + nmvsapm * -10 + nmapp * 0.75 + nmdsp * -0.25) / 3.5) + 0.5; - plonk = ((nmgbe + nmapp + nmdsp * 0.75 + nmpps * -1) / 2.73) + 0.5; - stride = ((nmapm * -0.25 + nmpps + nmapp * -2 + nmdsp * -0.5) * 0.79) + 0.5; - infds = ((nmdsp + nmapp * -0.75 + nmapm * 0.5 + nmvsapm * 1.5 + nmpps * 0.5) * 0.9) + 0.5; - } -} - -class TetraLeagueAlphaStream{ - late String userId; - late List records; - - TetraLeagueAlphaStream({required this.userId, required this.records}); - - TetraLeagueAlphaStream.fromJson(List json, String userID) { - userId = userID; - records = []; - for (var value in json) {records.add(TetraLeagueAlphaRecord.fromJson(value));} - } -} - -class TetraLeagueBetaStream{ - late String id; - List records = []; - - TetraLeagueBetaStream({required this.id, required this.records}); - - TetraLeagueBetaStream.fromJson(List json, String userID) { - id = userID; - for (var entry in json) { - records.add(BetaRecord.fromJson(entry)); - } - } - - addFromAlphaStream(List r){ - for (var entry in r) { - records.add( - BetaRecord( - id: entry.ownId, - replayID: entry.replayId, - ts: entry.timestamp, - enemyID: entry.endContext[1].userId, - enemyUsername: entry.endContext[1].username, - gamemode: "oldleague", - results: BetaLeagueResults( - leaderboard: [ - BetaLeagueLeaderboardEntry( - id: entry.endContext[0].userId, - username: entry.endContext[0].username, - naturalorder: entry.endContext[0].naturalOrder, - wins: entry.endContext[0].points, - stats: BetaLeagueStats( - apm: entry.endContext[0].secondary, - pps: entry.endContext[0].tertiary, - vs: entry.endContext[0].extra, - garbageSent: -1, - garbageReceived: -1, - kills: entry.endContext[0].points, - altitude: 0.0, - rank: -1 - ) - ), - BetaLeagueLeaderboardEntry( - id: entry.endContext[1].userId, - username: entry.endContext[1].username, - naturalorder: entry.endContext[1].naturalOrder, - wins: entry.endContext[1].points, - stats: BetaLeagueStats( - apm: entry.endContext[1].secondary, - pps: entry.endContext[1].tertiary, - vs: entry.endContext[1].extra, - garbageSent: -1, - garbageReceived: -1, - kills: entry.endContext[1].points, - altitude: 0.0, - rank: -1 - ) - ) - ], - rounds: [ - for (int i=0; i records; - - SingleplayerStream({required this.userId, required this.records, required this.type}); - - SingleplayerStream.fromJson(List json, String userID, String tp) { - userId = userID; - type = tp; - records = []; - for (var value in json) {records.add(RecordSingle.fromJson(value, -1, -1));} - } -} - -class BetaRecord{ - late String id; - late String replayID; - late String gamemode; - late DateTime ts; - late String enemyUsername; - late String enemyID; - late BetaLeagueResults results; - - BetaRecord({required this.id, required this.replayID, required this.gamemode, required this.ts, required this.enemyUsername, required this.enemyID, required this.results}); - - BetaRecord.fromJson(Map json){ - id = json['_id']; - replayID = json['replayid']; - gamemode = json['gamemode']; - ts = DateTime.parse(json['ts']); - enemyUsername = json['otherusers'][0]['username']; - enemyID = json['otherusers'][0]['id']; - results = BetaLeagueResults.fromJson(json['results']); - } -} - -class BetaLeagueResults{ - List leaderboard = []; - List> rounds = []; - - BetaLeagueResults({required this.leaderboard, required this.rounds}); - - BetaLeagueResults.fromJson(Map json){ - for (var lbEntry in json['leaderboard']) { - leaderboard.add(BetaLeagueLeaderboardEntry.fromJson(lbEntry)); - } - for (var roundEntry in json['rounds']){ - List round = []; - for (var r in roundEntry) { - round.add(BetaLeagueRound.fromJson(r)); - } - rounds.add(round); - } - } -} - -class BetaLeagueLeaderboardEntry{ - late String id; - late String username; - late int naturalorder; - late int wins; - late BetaLeagueStats stats; - - BetaLeagueLeaderboardEntry({required this.id, required this.username, required this.naturalorder, required this.wins, required this.stats}); - - BetaLeagueLeaderboardEntry.fromJson(Map json){ - id = json['id']; - username = json['username']; - naturalorder = json['naturalorder']; - wins = json['wins']; - stats = BetaLeagueStats.fromJson(json['stats']); - } -} - -class BetaLeagueStats{ - late double apm; - late double pps; - late double vs; - late int garbageSent; - late int garbageReceived; - late int kills; - late double altitude; - late int rank; - int? targetingFactor; - int? targetingRace; - late NerdStats nerdStats; - late EstTr estTr; - late Playstyle playstyle; - - BetaLeagueStats({required this.apm, required this.pps, required this.vs, required this.garbageSent, required this.garbageReceived, required this.kills, required this.altitude, required this.rank}){ - nerdStats = NerdStats(apm, pps, vs); - estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - } - - BetaLeagueStats.fromJson(Map json){ - apm = json['apm'] != null ? json['apm'].toDouble() : 0.00; - pps = json['apm'] != null ? json['pps'].toDouble() : 0.00; - vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00; - garbageSent = json['garbagesent']; - garbageReceived = json['garbagereceived']; - kills = json['kills']; - altitude = json['altitude'].toDouble(); - rank = json['rank']; - targetingFactor = json['targetingfactor']; - targetingRace = json['targetinggrace']; - nerdStats = NerdStats(apm, pps, vs); - estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - } -} - -class BetaLeagueRound{ - late String id; - late String username; - late bool active; - late int naturalorder; - late bool alive; - late Duration lifetime; - late BetaLeagueStats stats; - - BetaLeagueRound({required this.id, required this.username, required this.active, required this.naturalorder, required this.alive, required this.lifetime, required this.stats}); - - BetaLeagueRound.fromJson(Map json){ - id = json['id']; - username = json['username']; - active = json['active']; - naturalorder = json['naturalorder']; - alive = json['alive']; - lifetime = Duration(milliseconds: json['lifetime']); - stats = BetaLeagueStats.fromJson(json['stats']); - } -} - -class TetraLeagueAlphaRecord{ - late String replayId; - late String ownId; - late DateTime timestamp; - late bool replayAvalable; - late List endContext; - - TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext, required this.replayAvalable}); - - TetraLeagueAlphaRecord.fromJson(Map json) { - endContext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])]; - replayId = json['replayid']; - ownId = json['_id']??replayId; - timestamp = DateTime.parse(json['ts']); - replayAvalable = ownId != replayId; - } - - Map toJson() { - final Map data = {}; - data['_id'] = ownId; - data['endcontext'][0] = endContext[0].toJson(); - data['endcontext'][1] = endContext[1].toJson(); - data['replayid'] = replayId; - data['ts'] = timestamp; - return data; - } - - @override - bool operator ==(covariant TetraLeagueAlphaRecord other) => (ownId == other.ownId) || (replayId == other.replayId); - - @override - String toString() { - return "TetraLeagueAlphaRecord: ${endContext.first.userId} vs ${endContext.last.userId}"; - } -} - -class EndContextMulti { - late String userId; - late String username; - late int naturalOrder; - late int inputs; - late int piecesPlaced; - late Handling handling; - late int points; - late int wins; - late double secondary; - late List secondaryTracking; - late double tertiary; - late List tertiaryTracking; - late double extra; - late List extraTracking; - late bool success; - late NerdStats nerdStats; - late List nerdStatsTracking; - late EstTr estTr; - late List estTrTracking; - late Playstyle playstyle; - late List playstyleTracking; - - EndContextMulti( - {required this.userId, - required this.username, - required this.naturalOrder, - required this.inputs, - required this.piecesPlaced, - required this.handling, - required this.points, - required this.wins, - required this.secondary, - required this.secondaryTracking, - required this.tertiary, - required this.tertiaryTracking, - required this.extra, - required this.extraTracking, - required this.success}){ - nerdStats = NerdStats(secondary, tertiary, extra); - nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])]; - estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)]; - playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)]; - } - - EndContextMulti.fromJson(Map json) { - userId = json['id'] ?? json['user']['_id']; - username = json['username'] ?? json['user']['username']; - handling = json['handling'] != null ? Handling.fromJson(json['handling']) : Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true); - success = json['success']; - inputs = json['inputs'] ?? -1; - piecesPlaced = json['piecesplaced'] ?? -1; - naturalOrder = json['naturalorder']; - wins = json['wins']; - points = json['points']['primary']; - secondary = json['points']['secondary'].toDouble(); - tertiary = json['points']['tertiary'].toDouble(); - secondaryTracking = json['points']['secondaryAvgTracking'] != null ? json['points']['secondaryAvgTracking'].map((e) => e.toDouble()).toList() : []; - tertiaryTracking = json['points']['tertiaryAvgTracking'] != null ? json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList() : []; - extra = json['points']['extra']['vs'].toDouble(); - extraTracking = json['points']['extraAvgTracking'] != null ? json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList() : []; - nerdStats = NerdStats(secondary, tertiary, extra); - nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])]; - estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)]; - playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)]; - } - - @override - bool operator == (covariant EndContextMulti other){ - if (userId != other.userId) return false; - return true; - } - - Map toJson() { - final Map data = {}; - data['user'] = {'_id': userId, 'username': username}; - data['handling'] = handling.toJson(); - data['success'] = success; - data['inputs'] = inputs; - data['piecesplaced'] = piecesPlaced; - data['naturalorder'] = naturalOrder; - data['wins'] = wins; - data['points'] = {'primary': points, 'secondary': secondary, 'tertiary':tertiary, 'extra': {'vs': extra}, 'secondaryAvgTracking': secondaryTracking, 'tertiaryAvgTracking': tertiaryTracking, 'extraAvgTracking': {'aggregatestats___vsscore': extraTracking}}; - return data; - } -} - -class TetraLeague { - late String id; - late DateTime timestamp; - late int gamesPlayed; - late int gamesWon; - late String bestRank; - late bool decaying; - late double tr; - late double gxe; - late String rank; - double? glicko; - double? rd; - late String percentileRank; - late double percentile; - late int standing; - late int standingLocal; - String? nextRank; - late int nextAt; - String? prevRank; - late int prevAt; - double? apm; - double? pps; - double? vs; - NerdStats? nerdStats; - EstTr? estTr; - Playstyle? playstyle; - late int season; - - TetraLeague( - {required this.id, - required this.timestamp, - required this.gamesPlayed, - required this.gamesWon, - required this.bestRank, - required this.decaying, - required this.tr, - required this.gxe, - required this.rank, - this.glicko, - this.rd, - required this.percentileRank, - required this.percentile, - required this.standing, - required this.standingLocal, - this.nextRank, - required this.nextAt, - this.prevRank, - required this.prevAt, - this.apm, - this.pps, - this.vs, - required this.season}){ - nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null; - estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null; - playstyle =(nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null; - } - - double get winrate => gamesWon / gamesPlayed; - double get s1tr => gxe * 250; - - TetraLeague.fromJson(Map json, ts, int s, String i) { - timestamp = ts; - season = s; - id = i; - gamesPlayed = json['gamesplayed'] ?? 0; - gamesWon = json['gameswon'] ?? 0; - tr = json['tr'] != null ? json['tr'].toDouble() : json['rating'] != null ? json['rating'].toDouble() : -1; - glicko = json['glicko']?.toDouble(); - rd = json['rd'] != null ? json['rd']!.toDouble() : noTrRd; - gxe = json['gxe'] != null ? json['gxe'].toDouble() : -1; - rank = json['rank'] != null ? json['rank']!.toString() : 'z'; - bestRank = json['bestrank'] != null ? json['bestrank']!.toString() : 'z'; - apm = json['apm']?.toDouble(); - pps = json['pps']?.toDouble(); - vs = json['vs']?.toDouble(); - decaying = switch(json['decaying'].runtimeType){ - int => json['decaying'] == 1, - bool => json['decaying'], - _ => false - }; - standing = json['standing'] ?? -1; - percentile = json['percentile'] != null ? json['percentile'].toDouble() : rankCutoffs[rank]; - standingLocal = json['standing_local'] ?? -1; - prevRank = json['prev_rank']; - prevAt = json['prev_at'] ?? -1; - nextRank = json['next_rank']; - nextAt = json['next_at'] ?? -1; - percentileRank = json['percentile_rank'] ?? rank; - nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null; - estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null; - playstyle = (nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null; - } - - @override - bool operator ==(covariant TetraLeague other) => gamesPlayed == other.gamesPlayed && rd == other.rd; - - bool lessStrictCheck (covariant TetraLeague other) => gamesPlayed == other.gamesPlayed && glicko == other.glicko; - - double? get esttracc => (estTr != null) ? estTr!.esttr - tr : null; - - TetrioPlayerFromLeaderboard convertToPlayerFromLeaderboard(String id) => TetrioPlayerFromLeaderboard( - id, "", "user", -1, null, timestamp, gamesPlayed, gamesWon, - tr, gxe, glicko??0, rd??noTrRd, rank, bestRank, apm??0, pps??0, vs??0, decaying); - - Map toJson() { - final Map data = {}; - data['id'] = id+timestamp.millisecondsSinceEpoch.toRadixString(16); - if (gamesPlayed > 0) data['gamesplayed'] = gamesPlayed; - if (gamesWon > 0) data['gameswon'] = gamesWon; - if (tr >= 0) data['tr'] = tr; - if (glicko != null) data['glicko'] = glicko; - if (gxe != -1) data['gxe'] = gxe; - if (rd != null && rd != noTrRd) data['rd'] = rd; - if (rank != 'z') data['rank'] = rank; - if (bestRank != 'z') data['bestrank'] = bestRank; - if (apm != null) data['apm'] = apm; - if (pps != null) data['pps'] = pps; - if (vs != null) data['vs'] = vs; - if (decaying) data['decaying'] = decaying ? 1 : 0; - if (standing >= 0) data['standing'] = standing; - data['percentile'] = percentile; - if (standingLocal >= 0) data['standing_local'] = standingLocal; - if (prevRank != null) data['prev_rank'] = prevRank; - if (prevAt >= 0) data['prev_at'] = prevAt; - if (nextRank != null) data['next_rank'] = nextRank; - if (nextAt >= 0) data['next_at'] = nextAt; - data['percentile_rank'] = percentileRank; - data['season'] = season; - return data; - } -} - -class RecordSingle { - late String? userId; - late String replayId; - late String ownId; - late String gamemode; - late DateTime timestamp; - late ResultsStats stats; - late int rank; - late int countryRank; - late AggregateStats aggregateStats; - late RecordExtras extras; - - RecordSingle({required this.userId, required this.replayId, required this.ownId, required this.timestamp, required this.stats, required this.rank, required this.countryRank, required this.aggregateStats}); - - RecordSingle.fromJson(Map json, int ran, int cran) { - ownId = json['_id']; - gamemode = json['gamemode']; - stats = ResultsStats.fromJson(json['results']['stats']); - replayId = json['replayid']; - timestamp = DateTime.parse(json['ts']); - if (json['user'] != null) userId = json['user']['id']; - rank = ran; - countryRank = cran; - aggregateStats = AggregateStats.fromJson(json['results']['aggregatestats']); - var ex = json['extras'] as Map; - switch (ex.keys.firstOrNull){ - case "zenith": - extras = ZenithExtras.fromJson(json['extras']['zenith']); - default: - break; - } - } - - Map toJson() { - final Map data = {}; - data['_id'] = ownId; - data['results']['stats'] = stats.toJson(); - data['ismulti'] = false; - data['replayid'] = replayId; - data['ts'] = timestamp; - data['user_id'] = userId; - return data; - } -} - -class AggregateStats{ - late double apm; - late double pps; - late double vs; - late NerdStats nerdStats; - late EstTr estTr; - late Playstyle playstyle; - - AggregateStats(this.apm, this.pps, this.vs){ - nerdStats = NerdStats(apm, pps, vs); - estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - } - - AggregateStats.fromJson(Map json){ - apm = json['apm'] != null ? json['apm'].toDouble() : 0.00; - pps = json['apm'] != null ? json['pps'].toDouble() : 0.00; - vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00; - nerdStats = NerdStats(apm, pps, vs); - estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - } -} - -class RecordExtras{ - -} - -class ZenithExtras extends RecordExtras{ - List mods = []; - - ZenithExtras.fromJson(Map json){ - for (var mod in json["mods"]) { - mods.add(mod); - } - } -} - -class TetrioZen { - late int level; - late int score; - - TetrioZen({required this.level, required this.score}); - - double get scoreRequirement => (10000 + 10000 * ((log(level + 1) / log(2)) - 1)); - - TetrioZen.fromJson(Map json) { - level = json['level']; - score = json['score']; - } - - Map toJson() { - final Map data = {}; - data['level'] = level; - data['score'] = score; - return data; - } -} - -class UserRecords{ - String id; - RecordSingle? sprint; - RecordSingle? blitz; - TetrioZen zen; - - UserRecords(this.id, this.sprint, this.blitz, this.zen); -} - -class Distinguishment { - late String type; - String? detail; - String? header; - String? footer; - - Distinguishment({required this.type, this.detail, this.header, this.footer}); - - Distinguishment.fromJson(Map json) { - type = json['type']; - detail = json['detail']; - header = json['header']; - footer = json['footer']; - } - - @override - bool operator ==(covariant Distinguishment other) => type == other.type && detail == other.detail && header == other.header && footer == other.footer; - - Map toJson() { - final Map data = {}; - data['type'] = type; - data['detail'] = detail; - data['header'] = header; - data['footer'] = footer; - return data; - } -} - -class News{ - late String id; - late List news; - - News(this.id, this.news); - - News.fromJson(Map json, String? userID){ - id = userID != null ? "user_$userID" : json['news'].first['stream']; - news = [for (var entry in json['news']) NewsEntry.fromJson(entry)]; - } -} - -class NewsEntry { - //late String id; do i need it? - late String type; - late Map data; - late DateTime timestamp; - - NewsEntry({required this.type, required this.data, required this.timestamp}); - - NewsEntry.fromJson(Map json){ - //id = json["_id"]; - type = json["type"]; - data = json["data"]; - timestamp = DateTime.parse(json['ts']); - } -} - -class PlayerLeaderboardPosition{ - late LeaderboardPosition? apm; - late LeaderboardPosition? pps; - late LeaderboardPosition? vs; - late LeaderboardPosition? gamesPlayed; - late LeaderboardPosition? gamesWon; - late LeaderboardPosition? winrate; - late LeaderboardPosition? app; - late LeaderboardPosition? vsapm; - late LeaderboardPosition? dss; - late LeaderboardPosition? dsp; - late LeaderboardPosition? appdsp; - late LeaderboardPosition? cheese; - late LeaderboardPosition? gbe; - late LeaderboardPosition? nyaapp; - late LeaderboardPosition? area; - late LeaderboardPosition? estTr; - late LeaderboardPosition? accOfEst; - - PlayerLeaderboardPosition({ - required this.apm, - required this.pps, - required this.vs, - required this.gamesPlayed, - required this.gamesWon, - required this.winrate, - required this.app, - required this.vsapm, - required this.dss, - required this.dsp, - required this.appdsp, - required this.cheese, - required this.gbe, - required this.nyaapp, - required this.area, - required this.estTr, - required this.accOfEst - }); - - PlayerLeaderboardPosition.fromSearchResults(List results){ - apm = results[0]; - pps = results[1]; - vs = results[2]; - gamesPlayed = results[3]; - gamesWon = results[4]; - winrate = results[5]; - app = results[6]; - vsapm = results[7]; - dss = results[8]; - dsp = results[9]; - appdsp = results[10]; - cheese = results[11]; - gbe = results[12]; - nyaapp = results[13]; - area = results[14]; - estTr = results[15]; - accOfEst = results[16]; - } -} - -class LeaderboardPosition{ - int position; - double percentage; - - LeaderboardPosition(this.position, this.percentage); -} - -class TetrioPlayersLeaderboard { - late String type; - late DateTime timestamp; - late List leaderboard; - - TetrioPlayersLeaderboard(this.type, this.leaderboard); - - @override - String toString(){ - return "$type leaderboard: ${leaderboard.length} players"; - } - - List getStatRanking(List leaderboard, Stats stat, {bool reversed = false, String country = ""}){ - List lb = List.from(leaderboard); - if (country.isNotEmpty){ - lb.removeWhere((element) => element.country != country); - } - lb.sort(((a, b) { - if (a.getStatByEnum(stat).isNaN) return 1; - if (b.getStatByEnum(stat).isNaN) return -1; - if (a.getStatByEnum(stat) > b.getStatByEnum(stat)){ - return reversed ? 1 : -1; - }else if (a.getStatByEnum(stat) == b.getStatByEnum(stat)){ - return 0; - }else{ - return reversed ? -1 : 1; - } - })); - return lb; - } - - List getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible - if (rank.isNotEmpty && !rankCutoffs.keys.contains(rank)) throw Exception("Invalid rank"); - List filtredLeaderboard = List.from(leaderboard); - if (rank.isNotEmpty) { - filtredLeaderboard.removeWhere((element) => element.rank != rank); - } - if (filtredLeaderboard.isNotEmpty){ - double avgAPM = 0, - avgPPS = 0, - avgVS = 0, - avgTR = 0, - avgGlixare = 0, - avgGlicko = 0, - avgRD = 0, - avgAPP = 0, - avgVSAPM = 0, - avgDSS = 0, - avgDSP = 0, - avgAPPDSP = 0, - avgCheese = 0, - avgGBE = 0, - avgNyaAPP = 0, - avgArea = 0, - avgEstTR = 0, - avgEstAcc = 0, - avgOpener = 0, - avgPlonk = 0, - avgStride = 0, - avgInfDS = 0, - lowestTR = 25000, - lowestGlixare = double.infinity, - lowestGlicko = double.infinity, - lowestRD = double.infinity, - lowestWinrate = double.infinity, - lowestAPM = double.infinity, - lowestPPS = double.infinity, - lowestVS = double.infinity, - lowestAPP = double.infinity, - lowestVSAPM = double.infinity, - lowestDSS = double.infinity, - lowestDSP = double.infinity, - lowestAPPDSP = double.infinity, - lowestCheese = double.infinity, - lowestGBE = double.infinity, - lowestNyaAPP = double.infinity, - lowestArea = double.infinity, - lowestEstTR = double.infinity, - lowestEstAcc = double.infinity, - lowestOpener = double.infinity, - lowestPlonk = double.infinity, - lowestStride = double.infinity, - lowestInfDS = double.infinity, - highestTR = double.negativeInfinity, - highestGlixare = double.negativeInfinity, - highestGlicko = double.negativeInfinity, - highestRD = double.negativeInfinity, - highestWinrate = double.negativeInfinity, - highestAPM = double.negativeInfinity, - highestPPS = double.negativeInfinity, - highestVS = double.negativeInfinity, - highestAPP = double.negativeInfinity, - highestVSAPM = double.negativeInfinity, - highestDSS = double.negativeInfinity, - highestDSP = double.negativeInfinity, - highestAPPDSP = double.negativeInfinity, - highestCheese = double.negativeInfinity, - highestGBE = double.negativeInfinity, - highestNyaAPP = double.negativeInfinity, - highestArea = double.negativeInfinity, - highestEstTR = double.negativeInfinity, - highestEstAcc = double.negativeInfinity, - highestOpener = double.negativeInfinity, - highestPlonk = double.negativeInfinity, - highestStride = double.negativeInfinity, - highestInfDS = double.negativeInfinity; - int avgGamesPlayed = 0, - avgGamesWon = 0, - totalGamesPlayed = 0, - totalGamesWon = 0, - lowestGamesPlayed = pow(2, 53) as int, - lowestGamesWon = pow(2, 53) as int, - highestGamesPlayed = 0, - highestGamesWon = 0; - String lowestTRid = "", lowestTRnick = "", - lowestGlixareID = "", lowestGlixareNick = "", - lowestGlickoID = "", lowestGlickoNick = "", - lowestRdID = "", lowestRdNick = "", - lowestGamesPlayedID = "", lowestGamesPlayedNick = "", - lowestGamesWonID = "", lowestGamesWonNick = "", - lowestWinrateID = "", lowestWinrateNick = "", - lowestAPMid = "", lowestAPMnick = "", - lowestPPSid = "", lowestPPSnick = "", - lowestVSid = "", lowestVSnick = "", - lowestAPPid = "", lowestAPPnick = "", - lowestVSAPMid = "", lowestVSAPMnick = "", - lowestDSSid = "", lowestDSSnick = "", - lowestDSPid = "", lowestDSPnick = "", - lowestAPPDSPid = "", lowestAPPDSPnick = "", - lowestCheeseID = "", lowestCheeseNick = "", - lowestGBEid = "", lowestGBEnick = "", - lowestNyaAPPid = "", lowestNyaAPPnick = "", - lowestAreaID = "", lowestAreaNick = "", - lowestEstTRid = "", lowestEstTRnick = "", - lowestEstAccID = "", lowestEstAccNick = "", - lowestOpenerID = "", lowestOpenerNick = "", - lowestPlonkID = "", lowestPlonkNick = "", - lowestStrideID = "", lowestStrideNick = "", - lowestInfDSid = "", lowestInfDSnick = "", - highestTRid = "", highestTRnick = "", - highestGlixareID = "", highestGlixareNick = "", - highestGlickoID = "", highestGlickoNick = "", - highestRdID = "", highestRdNick = "", - highestGamesPlayedID = "", highestGamesPlayedNick = "", - highestGamesWonID = "", highestGamesWonNick = "", - highestWinrateID = "", highestWinrateNick = "", - highestAPMid = "", highestAPMnick = "", - highestPPSid = "", highestPPSnick = "", - highestVSid = "", highestVSnick = "", - highestAPPid = "", highestAPPnick = "", - highestVSAPMid = "", highestVSAPMnick = "", - highestDSSid = "", highestDSSnick = "", - highestDSPid = "", highestDSPnick = "", - highestAPPDSPid = "", highestAPPDSPnick = "", - highestCheeseID = "", highestCheeseNick = "", - highestGBEid = "", highestGBEnick = "", - highestNyaAPPid = "", highestNyaAPPnick = "", - highestAreaID = "", highestAreaNick = "", - highestEstTRid = "", highestEstTRnick = "", - highestEstAccID = "", highestEstAccNick = "", - highestOpenerID = "", highestOpenerNick = "", - highestPlonkID = "", highestPlonkNick = "", - highestStrideID = "", highestStrideNick = "", - highestInfDSid = "", highestInfDSnick = ""; - for (var entry in filtredLeaderboard){ - avgAPM += entry.apm; - avgPPS += entry.pps; - avgVS += entry.vs; - avgTR += entry.tr; - avgGlixare += entry.gxe; - if (entry.glicko != null) avgGlicko += entry.glicko!; - if (entry.rd != null) avgRD += entry.rd!; - avgAPP += entry.nerdStats.app; - avgVSAPM += entry.nerdStats.vsapm; - avgDSS += entry.nerdStats.dss; - avgDSP += entry.nerdStats.dsp; - avgAPPDSP += entry.nerdStats.appdsp; - avgCheese += entry.nerdStats.cheese; - avgGBE += entry.nerdStats.gbe; - avgNyaAPP += entry.nerdStats.nyaapp; - avgArea += entry.nerdStats.area; - avgEstTR += entry.estTr.esttr; - avgEstAcc += entry.esttracc; - avgOpener += entry.playstyle.opener; - avgPlonk += entry.playstyle.plonk; - avgStride += entry.playstyle.stride; - avgInfDS += entry.playstyle.infds; - totalGamesPlayed += entry.gamesPlayed; - totalGamesWon += entry.gamesWon; - if (entry.tr < lowestTR){ - lowestTR = entry.tr; - lowestTRid = entry.userId; - lowestTRnick = entry.username; - } - if (entry.gxe < lowestGlixare){ - lowestGlixare = entry.gxe; - lowestGlixareID = entry.userId; - lowestGlixareNick = entry.username; - } - if (entry.glicko != null && entry.glicko! < lowestGlicko){ - lowestGlicko = entry.glicko!; - lowestGlickoID = entry.userId; - lowestGlickoNick = entry.username; - } - if (entry.rd != null && entry.rd! < lowestRD){ - lowestRD = entry.rd!; - lowestRdID = entry.userId; - lowestRdNick = entry.username; - } - if (entry.gamesPlayed < lowestGamesPlayed){ - lowestGamesPlayed = entry.gamesPlayed; - lowestGamesPlayedID = entry.userId; - lowestGamesPlayedNick = entry.username; - } - if (entry.gamesWon < lowestGamesWon){ - lowestGamesWon = entry.gamesWon; - lowestGamesWonID = entry.userId; - lowestGamesWonNick = entry.username; - } - if (entry.winrate < lowestWinrate){ - lowestWinrate = entry.winrate; - lowestWinrateID = entry.userId; - lowestWinrateNick = entry.username; - } - if (entry.apm < lowestAPM){ - lowestAPM = entry.apm; - lowestAPMid = entry.userId; - lowestAPMnick = entry.username; - } - if (entry.pps < lowestPPS){ - lowestPPS = entry.pps; - lowestPPSid = entry.userId; - lowestPPSnick = entry.username; - } - if (entry.vs < lowestVS){ - lowestVS = entry.vs; - lowestVSid = entry.userId; - lowestVSnick = entry.username; - } - if (entry.nerdStats.app < lowestAPP){ - lowestAPP = entry.nerdStats.app; - lowestAPPid = entry.userId; - lowestAPPnick = entry.username; - } - if (entry.nerdStats.vsapm < lowestVSAPM){ - lowestVSAPM = entry.nerdStats.vsapm; - lowestVSAPMid = entry.userId; - lowestVSAPMnick = entry.username; - } - if (entry.nerdStats.dss < lowestDSS){ - lowestDSS = entry.nerdStats.dss; - lowestDSSid = entry.userId; - lowestDSSnick = entry.username; - } - if (entry.nerdStats.dsp < lowestDSP){ - lowestDSP = entry.nerdStats.dsp; - lowestDSPid = entry.userId; - lowestDSPnick = entry.username; - } - if (entry.nerdStats.appdsp < lowestAPPDSP){ - lowestAPPDSP = entry.nerdStats.appdsp; - lowestAPPDSPid = entry.userId; - lowestAPPDSPnick = entry.username; - } - if (entry.nerdStats.cheese < lowestCheese){ - lowestCheese = entry.nerdStats.cheese; - lowestCheeseID = entry.userId; - lowestCheeseNick = entry.username; - } - if (entry.nerdStats.gbe < lowestGBE){ - lowestGBE = entry.nerdStats.gbe; - lowestGBEid = entry.userId; - lowestGBEnick = entry.username; - } - if (entry.nerdStats.nyaapp < lowestNyaAPP){ - lowestNyaAPP = entry.nerdStats.nyaapp; - lowestNyaAPPid = entry.userId; - lowestNyaAPPnick = entry.username; - } - if (entry.nerdStats.area < lowestArea){ - lowestArea = entry.nerdStats.area; - lowestAreaID = entry.userId; - lowestAreaNick = entry.username; - } - if (entry.estTr.esttr < lowestEstTR){ - lowestEstTR = entry.estTr.esttr; - lowestEstTRid = entry.userId; - lowestEstTRnick = entry.username; - } - if (entry.esttracc < lowestEstAcc){ - lowestEstAcc = entry.esttracc; - lowestEstAccID = entry.userId; - lowestEstAccNick = entry.username; - } - if (entry.playstyle.opener < lowestOpener){ - lowestOpener = entry.playstyle.opener; - lowestOpenerID = entry.userId; - lowestOpenerNick = entry.username; - } - if (entry.playstyle.plonk < lowestPlonk){ - lowestPlonk = entry.playstyle.plonk; - lowestPlonkID = entry.userId; - lowestPlonkNick = entry.username; - } - if (entry.playstyle.stride < lowestStride){ - lowestStride = entry.playstyle.stride; - lowestStrideID = entry.userId; - lowestStrideNick = entry.username; - } - if (entry.playstyle.infds < lowestInfDS){ - lowestInfDS = entry.playstyle.infds; - lowestInfDSid = entry.userId; - lowestInfDSnick = entry.username; - } - if (entry.tr > highestTR){ - highestTR = entry.tr; - highestTRid = entry.userId; - highestTRnick = entry.username; - } - if (entry.gxe > highestGlixare){ - highestGlixare = entry.gxe; - highestGlixareID = entry.userId; - highestGlixareNick = entry.username; - } - if (entry.glicko != null && entry.glicko! > highestGlicko){ - highestGlicko = entry.glicko!; - highestGlickoID = entry.userId; - highestGlickoNick = entry.username; - } - if (entry.rd != null && entry.rd! > highestRD){ - highestRD = entry.rd!; - highestRdID = entry.userId; - highestRdNick = entry.username; - } - if (entry.gamesPlayed > highestGamesPlayed){ - highestGamesPlayed = entry.gamesPlayed; - highestGamesPlayedID = entry.userId; - highestGamesPlayedNick = entry.username; - } - if (entry.gamesWon > highestGamesWon){ - highestGamesWon = entry.gamesWon; - highestGamesWonID = entry.userId; - highestGamesWonNick = entry.username; - } - if (entry.winrate > highestWinrate){ - highestWinrate = entry.winrate; - highestWinrateID = entry.userId; - highestWinrateNick = entry.username; - } - if (entry.apm > highestAPM){ - highestAPM = entry.apm; - highestAPMid = entry.userId; - highestAPMnick = entry.username; - } - if (entry.pps > highestPPS){ - highestPPS = entry.pps; - highestPPSid = entry.userId; - highestPPSnick = entry.username; - } - if (entry.vs > highestVS){ - highestVS = entry.vs; - highestVSid = entry.userId; - highestVSnick = entry.username; - } - if (entry.nerdStats.app > highestAPP){ - highestAPP = entry.nerdStats.app; - highestAPPid = entry.userId; - highestAPPnick = entry.username; - } - if (entry.nerdStats.vsapm > highestVSAPM){ - highestVSAPM = entry.nerdStats.vsapm; - highestVSAPMid = entry.userId; - highestVSAPMnick = entry.username; - } - if (entry.nerdStats.dss > highestDSS){ - highestDSS = entry.nerdStats.dss; - highestDSSid = entry.userId; - highestDSSnick = entry.username; - } - if (entry.nerdStats.dsp > highestDSP){ - highestDSP = entry.nerdStats.dsp; - highestDSPid = entry.userId; - highestDSPnick = entry.username; - } - if (entry.nerdStats.appdsp > highestAPPDSP){ - highestAPPDSP = entry.nerdStats.appdsp; - highestAPPDSPid = entry.userId; - highestAPPDSPnick = entry.username; - } - if (entry.nerdStats.cheese > highestCheese){ - highestCheese = entry.nerdStats.cheese; - highestCheeseID = entry.userId; - highestCheeseNick = entry.username; - } - if (entry.nerdStats.gbe > highestGBE){ - highestGBE = entry.nerdStats.gbe; - highestGBEid = entry.userId; - highestGBEnick = entry.username; - } - if (entry.nerdStats.nyaapp > highestNyaAPP){ - highestNyaAPP = entry.nerdStats.nyaapp; - highestNyaAPPid = entry.userId; - highestNyaAPPnick = entry.username; - } - if (entry.nerdStats.area > highestArea){ - highestArea = entry.nerdStats.area; - highestAreaID = entry.userId; - highestAreaNick = entry.username; - } - if (entry.estTr.esttr > highestEstTR){ - highestEstTR = entry.estTr.esttr; - highestEstTRid = entry.userId; - highestEstTRnick = entry.username; - } - if (entry.esttracc > highestEstAcc){ - highestEstAcc = entry.esttracc; - highestEstAccID = entry.userId; - highestEstAccNick = entry.username; - } - if (entry.playstyle.opener > highestOpener){ - highestOpener = entry.playstyle.opener; - highestOpenerID = entry.userId; - highestOpenerNick = entry.username; - } - if (entry.playstyle.plonk > highestPlonk){ - highestPlonk = entry.playstyle.plonk; - highestPlonkID = entry.userId; - highestPlonkNick = entry.username; - } - if (entry.playstyle.stride > highestStride){ - highestStride = entry.playstyle.stride; - highestStrideID = entry.userId; - highestStrideNick = entry.username; - } - if (entry.playstyle.infds > highestInfDS){ - highestInfDS = entry.playstyle.infds; - highestInfDSid = entry.userId; - highestInfDSnick = entry.username; - } - } - avgAPM /= filtredLeaderboard.length; - avgPPS /= filtredLeaderboard.length; - avgVS /= filtredLeaderboard.length; - avgTR /= filtredLeaderboard.length; - avgGlixare /= filtredLeaderboard.length; - avgGlicko /= filtredLeaderboard.length; - avgRD /= filtredLeaderboard.length; - avgAPP /= filtredLeaderboard.length; - avgVSAPM /= filtredLeaderboard.length; - avgDSS /= filtredLeaderboard.length; - avgDSP /= filtredLeaderboard.length; - avgAPPDSP /= leaderboard.length; - avgCheese /= filtredLeaderboard.length; - avgGBE /= filtredLeaderboard.length; - avgNyaAPP /= filtredLeaderboard.length; - avgArea /= filtredLeaderboard.length; - avgEstTR /= filtredLeaderboard.length; - avgEstAcc /= filtredLeaderboard.length; - avgOpener /= filtredLeaderboard.length; - avgPlonk /= filtredLeaderboard.length; - avgStride /= filtredLeaderboard.length; - avgInfDS /= filtredLeaderboard.length; - avgGamesPlayed = (totalGamesPlayed / filtredLeaderboard.length).floor(); - avgGamesWon = (totalGamesWon / filtredLeaderboard.length).floor(); - return [TetraLeague(id: "", timestamp: DateTime.now(), apm: avgAPM, pps: avgPPS, vs: avgVS, gxe: avgGlixare, glicko: avgGlicko, rd: avgRD, gamesPlayed: avgGamesPlayed, gamesWon: avgGamesWon, bestRank: rank, decaying: false, tr: avgTR, rank: rank == "" ? "z" : rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1, season: currentSeason), - { - "everyone": rank == "", - "totalGamesPlayed": totalGamesPlayed, - "totalGamesWon": totalGamesWon, - "players": filtredLeaderboard.length, - "lowestTR": lowestTR, - "lowestTRid": lowestTRid, - "lowestTRnick": lowestTRnick, - "lowestGlixare": lowestGlixare, - "lowestGlixareID": lowestGlixareID, - "lowestGlixareNick": lowestGlixareNick, - "lowestS1tr": lowestGlixare * 250, - "lowestS1trID": lowestGlixareID, - "lowestS1trNick": lowestGlixareNick, - "lowestGlicko": lowestGlicko, - "lowestGlickoID": lowestGlickoID, - "lowestGlickoNick": lowestGlickoNick, - "lowestRD": lowestRD, - "lowestRdID": lowestRdID, - "lowestRdNick": lowestRdNick, - "lowestGamesPlayed": lowestGamesPlayed, - "lowestGamesPlayedID": lowestGamesPlayedID, - "lowestGamesPlayedNick": lowestGamesPlayedNick, - "lowestGamesWon": lowestGamesWon, - "lowestGamesWonID": lowestGamesWonID, - "lowestGamesWonNick": lowestGamesWonNick, - "lowestWinrate": lowestWinrate, - "lowestWinrateID": lowestWinrateID, - "lowestWinrateNick": lowestWinrateNick, - "lowestAPM": lowestAPM, - "lowestAPMid": lowestAPMid, - "lowestAPMnick": lowestAPMnick, - "lowestPPS": lowestPPS, - "lowestPPSid": lowestPPSid, - "lowestPPSnick": lowestPPSnick, - "lowestVS": lowestVS, - "lowestVSid": lowestVSid, - "lowestVSnick": lowestVSnick, - "lowestAPP": lowestAPP, - "lowestAPPid": lowestAPPid, - "lowestAPPnick": lowestAPPnick, - "lowestVSAPM": lowestVSAPM, - "lowestVSAPMid": lowestVSAPMid, - "lowestVSAPMnick": lowestVSAPMnick, - "lowestDSS": lowestDSS, - "lowestDSSid": lowestDSSid, - "lowestDSSnick": lowestDSSnick, - "lowestDSP": lowestDSP, - "lowestDSPid": lowestDSPid, - "lowestDSPnick": lowestDSPnick, - "lowestAPPDSP": lowestAPPDSP, - "lowestAPPDSPid": lowestAPPDSPid, - "lowestAPPDSPnick": lowestAPPDSPnick, - "lowestCheese": lowestCheese, - "lowestCheeseID": lowestCheeseID, - "lowestCheeseNick": lowestCheeseNick, - "lowestGBE": lowestGBE, - "lowestGBEid": lowestGBEid, - "lowestGBEnick": lowestGBEnick, - "lowestNyaAPP": lowestNyaAPP, - "lowestNyaAPPid": lowestNyaAPPid, - "lowestNyaAPPnick": lowestNyaAPPnick, - "lowestArea": lowestArea, - "lowestAreaID": lowestAreaID, - "lowestAreaNick": lowestAreaNick, - "lowestEstTR": lowestEstTR, - "lowestEstTRid": lowestEstTRid, - "lowestEstTRnick": lowestEstTRnick, - "lowestEstAcc": lowestEstAcc, - "lowestEstAccID": lowestEstAccID, - "lowestEstAccNick": lowestEstAccNick, - "lowestOpener": lowestOpener, - "lowestOpenerID": lowestOpenerID, - "lowestOpenerNick": lowestOpenerNick, - "lowestPlonk": lowestPlonk, - "lowestPlonkID": lowestPlonkID, - "lowestPlonkNick": lowestPlonkNick, - "lowestStride": lowestStride, - "lowestStrideID": lowestStrideID, - "lowestStrideNick": lowestStrideNick, - "lowestInfDS": lowestInfDS, - "lowestInfDSid": lowestInfDSid, - "lowestInfDSnick": lowestInfDSnick, - "highestTR": highestTR, - "highestTRid": highestTRid, - "highestTRnick": highestTRnick, - "highestGlixare": highestGlixare, - "highestGlixareID": highestGlixareID, - "highestGlixareNick": highestGlixareNick, - "highestS1tr": highestGlixare * 250, - "highestS1trID": highestGlixareID, - "highestS1trNick": highestGlixareNick, - "highestGlicko": highestGlicko, - "highestGlickoID": highestGlickoID, - "highestGlickoNick": highestGlickoNick, - "highestRD": highestRD, - "highestRdID": highestRdID, - "highestRdNick": highestRdNick, - "highestGamesPlayed": highestGamesPlayed, - "highestGamesPlayedID": highestGamesPlayedID, - "highestGamesPlayedNick": highestGamesPlayedNick, - "highestGamesWon": highestGamesWon, - "highestGamesWonID": highestGamesWonID, - "highestGamesWonNick": highestGamesWonNick, - "highestWinrate": highestWinrate, - "highestWinrateID": highestWinrateID, - "highestWinrateNick": highestWinrateNick, - "highestAPM": highestAPM, - "highestAPMid": highestAPMid, - "highestAPMnick": highestAPMnick, - "highestPPS": highestPPS, - "highestPPSid": highestPPSid, - "highestPPSnick": highestPPSnick, - "highestVS": highestVS, - "highestVSid": highestVSid, - "highestVSnick": highestVSnick, - "highestAPP": highestAPP, - "highestAPPid": highestAPPid, - "highestAPPnick": highestAPPnick, - "highestVSAPM": highestVSAPM, - "highestVSAPMid": highestVSAPMid, - "highestVSAPMnick": highestVSAPMnick, - "highestDSS": highestDSS, - "highestDSSid": highestDSSid, - "highestDSSnick": highestDSSnick, - "highestDSP": highestDSP, - "highestDSPid": highestDSPid, - "highestDSPnick": highestDSPnick, - "highestAPPDSP": highestAPPDSP, - "highestAPPDSPid": highestAPPDSPid, - "highestAPPDSPnick": highestAPPDSPnick, - "highestCheese": highestCheese, - "highestCheeseID": highestCheeseID, - "highestCheeseNick": highestCheeseNick, - "highestGBE": highestGBE, - "highestGBEid": highestGBEid, - "highestGBEnick": highestGBEnick, - "highestNyaAPP": highestNyaAPP, - "highestNyaAPPid": highestNyaAPPid, - "highestNyaAPPnick": highestNyaAPPnick, - "highestArea": highestArea, - "highestAreaID": highestAreaID, - "highestAreaNick": highestAreaNick, - "highestEstTR": highestEstTR, - "highestEstTRid": highestEstTRid, - "highestEstTRnick": highestEstTRnick, - "highestEstAcc": highestEstAcc, - "highestEstAccID": highestEstAccID, - "highestEstAccNick": highestEstAccNick, - "highestOpener": highestOpener, - "highestOpenerID": highestOpenerID, - "highestOpenerNick": highestOpenerNick, - "highestPlonk": highestPlonk, - "highestPlonkID": highestPlonkID, - "highestPlonkNick": highestPlonkNick, - "highestStride": highestStride, - "highestStrideID": highestStrideID, - "highestStrideNick": highestStrideNick, - "highestInfDS": highestInfDS, - "highestInfDSid": highestInfDSid, - "highestInfDSnick": highestInfDSnick, - "avgAPP": avgAPP, - "avgVSAPM": avgVSAPM, - "avgDSS": avgDSS, - "avgDSP": avgDSP, - "avgAPPDSP": avgAPPDSP, - "avgCheese": avgCheese, - "avgGBE": avgGBE, - "avgNyaAPP": avgNyaAPP, - "avgArea": avgArea, - "avgEstTR": avgEstTR, - "avgEstAcc": avgEstAcc, - "avgOpener": avgOpener, - "avgPlonk": avgPlonk, - "avgStride": avgStride, - "avgInfDS": avgInfDS, - "toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].tr : lowestTR, - "toEnterGlicko": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].glicko : 0, - "entries": filtredLeaderboard - }]; - }else{ - return [TetraLeague(id: "", timestamp: DateTime.now(), apm: 0, pps: 0, vs: 0, glicko: 0, rd: noTrRd, gamesPlayed: 0, gamesWon: 0, bestRank: rank, decaying: false, tr: 0, rank: rank, percentileRank: rank, gxe: -1, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1, season: currentSeason), - {"players": filtredLeaderboard.length, "lowestTR": 0, "toEnterTR": 0, "toEnterGlicko": 0}]; - } - } - - PlayerLeaderboardPosition? getLeaderboardPosition(Mapleague) { - if (league.values.first.gamesPlayed == 0) return null; - bool fakePositions = false; - late List copyOfLeaderboard; - if (leaderboard.indexWhere((element) => element.userId == league.keys.first) == -1){ - fakePositions =true; - copyOfLeaderboard = List.of(leaderboard); - copyOfLeaderboard.add(league.values.first.convertToPlayerFromLeaderboard(league.keys.first)); - } - List stats = [Stats.apm, Stats.pps, Stats.vs, Stats.gp, Stats.gw, Stats.wr, - Stats.app, Stats.vsapm, Stats.dss, Stats.dsp, Stats.appdsp, Stats.cheese, Stats.gbe, Stats.nyaapp, Stats.area, Stats.eTR, Stats.acceTR]; - List results = []; - for (Stats stat in stats) { - List sortedLeaderboard = getStatRanking(fakePositions ? copyOfLeaderboard : leaderboard, stat, reversed: stat == Stats.cheese ? true : false); - int position = sortedLeaderboard.indexWhere((element) => element.userId == league.keys.first) + 1; - if (position == 0) { - results.add(null); - } else { - results.add(LeaderboardPosition(fakePositions ? 1001 : position, position / sortedLeaderboard.length)); - } - } - return PlayerLeaderboardPosition.fromSearchResults(results); - } - - Map> get averages => { - 'x+': getAverageOfRank("x+"), - 'x': getAverageOfRank("x"), - 'u': getAverageOfRank("u"), - 'ss': getAverageOfRank("ss"), - 's+': getAverageOfRank("s+"), - 's': getAverageOfRank("s"), - 's-': getAverageOfRank("s-"), - 'a+': getAverageOfRank("a+"), - 'a': getAverageOfRank("a"), - 'a-': getAverageOfRank("a-"), - 'b+': getAverageOfRank("b+"), - 'b': getAverageOfRank("b"), - 'b-': getAverageOfRank("b-"), - 'c+': getAverageOfRank("c+"), - 'c': getAverageOfRank("c"), - 'c-': getAverageOfRank("c-"), - 'd+': getAverageOfRank("d+"), - 'd': getAverageOfRank("d"), - 'z': getAverageOfRank("z") - }; - - Map get cutoffs => { - 'x': getAverageOfRank("x")[1]["toEnterTR"], - 'u': getAverageOfRank("u")[1]["toEnterTR"], - 'ss': getAverageOfRank("ss")[1]["toEnterTR"], - 's+': getAverageOfRank("s+")[1]["toEnterTR"], - 's': getAverageOfRank("s")[1]["toEnterTR"], - 's-': getAverageOfRank("s-")[1]["toEnterTR"], - 'a+': getAverageOfRank("a+")[1]["toEnterTR"], - 'a': getAverageOfRank("a")[1]["toEnterTR"], - 'a-': getAverageOfRank("a-")[1]["toEnterTR"], - 'b+': getAverageOfRank("b+")[1]["toEnterTR"], - 'b': getAverageOfRank("b")[1]["toEnterTR"], - 'b-': getAverageOfRank("b-")[1]["toEnterTR"], - 'c+': getAverageOfRank("c+")[1]["toEnterTR"], - 'c': getAverageOfRank("c")[1]["toEnterTR"], - 'c-': getAverageOfRank("c-")[1]["toEnterTR"], - 'd+': getAverageOfRank("d+")[1]["toEnterTR"], - 'd': getAverageOfRank("d")[1]["toEnterTR"] - }; - - Map get cutoffsGlicko => { - 'x': getAverageOfRank("x")[1]["toEnterGlicko"], - 'u': getAverageOfRank("u")[1]["toEnterGlicko"], - 'ss': getAverageOfRank("ss")[1]["toEnterGlicko"], - 's+': getAverageOfRank("s+")[1]["toEnterGlicko"], - 's': getAverageOfRank("s")[1]["toEnterGlicko"], - 's-': getAverageOfRank("s-")[1]["toEnterGlicko"], - 'a+': getAverageOfRank("a+")[1]["toEnterGlicko"], - 'a': getAverageOfRank("a")[1]["toEnterGlicko"], - 'a-': getAverageOfRank("a-")[1]["toEnterGlicko"], - 'b+': getAverageOfRank("b+")[1]["toEnterGlicko"], - 'b': getAverageOfRank("b")[1]["toEnterGlicko"], - 'b-': getAverageOfRank("b-")[1]["toEnterGlicko"], - 'c+': getAverageOfRank("c+")[1]["toEnterGlicko"], - 'c': getAverageOfRank("c")[1]["toEnterGlicko"], - 'c-': getAverageOfRank("c-")[1]["toEnterGlicko"], - 'd+': getAverageOfRank("d+")[1]["toEnterGlicko"], - 'd': getAverageOfRank("d")[1]["toEnterGlicko"] - }; - - TetrioPlayersLeaderboard.fromJson(List json, String t, DateTime ts) { - type = t; - timestamp = ts; - leaderboard = []; - for (Map entry in json) { - leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry, ts)); - } - } - - addPlayers(List list){ - leaderboard.addAll(list); - } -} - -class TetrioPlayerFromLeaderboard { - late String userId; - late String username; - late String role; - late double xp; - String? country; - late DateTime timestamp; - late int gamesPlayed; - late int gamesWon; - late double tr; - late double gxe; - late double? glicko; - late double? rd; - late String rank; - late String? bestRank; - late double apm; - late double pps; - late double vs; - late bool decaying; - late NerdStats nerdStats; - late EstTr estTr; - late Playstyle playstyle; - - TetrioPlayerFromLeaderboard( - this.userId, - this.username, - this.role, - this.xp, - this.country, - this.timestamp, - this.gamesPlayed, - this.gamesWon, - this.tr, - this.gxe, - this.glicko, - this.rd, - this.rank, - this.bestRank, - this.apm, - this.pps, - this.vs, - this.decaying){ - nerdStats = NerdStats(apm, pps, vs); - estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - } - - double get winrate => gamesWon / gamesPlayed; - double get esttracc => estTr.esttr - tr; - double get s1tr => gxe * 250; - - TetrioPlayerFromLeaderboard.fromJson(Map json, DateTime ts) { - userId = json['_id']; - username = json['username']; - role = json['role']; - xp = json['xp'].toDouble(); - country = json['country']; - timestamp = ts; - gamesPlayed = json['league']['gamesplayed'] as int; - gamesWon = json['league']['gameswon'] as int; - tr = json['league']['tr'] != null ? json['league']['tr'].toDouble() : 0; - gxe = json['league']['gxe']??-1; - glicko = json['league']['glicko']?.toDouble(); - rd = json['league']['rd']?.toDouble(); - rank = json['league']['rank']; - bestRank = json['league']['bestrank']; - apm = json['league']['apm'] != null ? json['league']['apm'].toDouble() : 0.00; - pps = json['league']['pps'] != null ? json['league']['pps'].toDouble() : 0.00; - vs = json['league']['vs'] != null ? json['league']['vs'].toDouble(): 0.00; - decaying = json['league']['decaying']; - nerdStats = NerdStats(apm, pps, vs); - estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); - playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); - } - - num getStatByEnum(Stats stat){ - switch (stat) { - case Stats.tr: - return tr; - case Stats.glicko: - return glicko??-1; - case Stats.gxe: - return gxe; - case Stats.s1tr: - return s1tr; - case Stats.rd: - return rd??-1; - case Stats.gp: - return gamesPlayed; - case Stats.gw: - return gamesWon; - case Stats.wr: - return winrate*100; - case Stats.apm: - return apm; - case Stats.pps: - return pps; - case Stats.vs: - return vs; - case Stats.app: - return nerdStats.app; - case Stats.dss: - return nerdStats.dss; - case Stats.dsp: - return nerdStats.dsp; - case Stats.appdsp: - return nerdStats.appdsp; - case Stats.vsapm: - return nerdStats.vsapm; - case Stats.cheese: - return nerdStats.cheese; - case Stats.gbe: - return nerdStats.gbe; - case Stats.nyaapp: - return nerdStats.nyaapp; - case Stats.area: - return nerdStats.area; - case Stats.eTR: - return estTr.esttr; - case Stats.acceTR: - return esttracc; - case Stats.acceTRabs: - return esttracc.abs(); - case Stats.opener: - return playstyle.opener; - case Stats.plonk: - return playstyle.plonk; - case Stats.infDS: - return playstyle.infds; - case Stats.stride: - return playstyle.stride; - case Stats.stridemMinusPlonk: - return playstyle.stride - playstyle.plonk; - case Stats.openerMinusInfDS: - return playstyle.opener - playstyle.infds; - } - } -} - -class CutoffTetrio { - late int pos; - late double percentile; - late double tr; - late double targetTr; - late double apm; - late double pps; - late double vs; - late int count; - late double countPercentile; - - CutoffTetrio.fromJson(Map json, int total){ - pos = json['pos']; - percentile = json['percentile'].toDouble(); - tr = json['tr'].toDouble(); - targetTr = json['targettr'].toDouble(); - apm = json['apm'].toDouble(); - pps = json['pps'].toDouble(); - vs = json['vs'].toDouble(); - count = json['count']; - countPercentile = count / total; - } -} - -class CutoffsTetrio { - late String id; - late DateTime timestamp; - late int total; - Map data = {}; - - CutoffsTetrio.fromJson(Map json){ - id = json['s']; - timestamp = DateTime.parse(json['t']); - total = json['data']['total']; - json['data'].remove("total"); - for (String rank in json['data'].keys){ - data[rank] = CutoffTetrio.fromJson(json['data'][rank], total); - } - } -} \ No newline at end of file diff --git a/lib/data_objects/tetrio_constants.dart b/lib/data_objects/tetrio_constants.dart new file mode 100644 index 0000000..b397d38 --- /dev/null +++ b/lib/data_objects/tetrio_constants.dart @@ -0,0 +1,188 @@ +import 'package:flutter/material.dart'; + +const int currentSeason = 2; +const double noTrRd = 60.9; +const double apmWeight = 1; +const double ppsWeight = 45; +const double vsWeight = 0.444; +const double appWeight = 185; +const double dssWeight = 175; +const double dspWeight = 450; +const double appdspWeight = 140; +const double vsapmWeight = 60; +const double cheeseWeight = 1.25; +const double gbeWeight = 315; +const List ranks = [ + "d", "d+", "c-", "c", "c+", "b-", "b", "b+", "a-", "a", "a+", "s-", "s", "s+", "ss", "u", "x", "x+" +]; +const Map rankCutoffs = { + "x+": 0.002, + "x": 0.01, + "u": 0.05, + "ss": 0.11, + "s+": 0.17, + "s": 0.23, + "s-": 0.3, + "a+": 0.38, + "a": 0.46, + "a-": 0.54, + "b+": 0.62, + "b": 0.7, + "b-": 0.78, + "c+": 0.84, + "c": 0.9, + "c-": 0.95, + "d+": 0.975, + "d": 1, + "z": -1, + "": 0.5 +}; +const Map rankTargets = { + "x+": 24000.00, + "x": 22500.00, + "u": 20000.00, + "ss": 18000.00, + "s+": 16500.00, + "s": 15200.00, + "s-": 13800.00, + "a+": 12000.00, + "a": 10500.00, + "a-": 9000.00, + "b+": 7400.00, + "b": 5700.00, + "b-": 4200.00, + "c+": 3000.00, + "c": 2000.00, + "c-": 1300.00, + "d+": 800.00, + "d": 0.00, +}; +// DateTime seasonStart = DateTime.utc(2024, 08, 16, 18); +//DateTime seasonEnd = DateTime.utc(2024, 07, 26, 15); +enum Stats { + tr, + glicko, + gxe, + s1tr, + rd, + gp, + gw, + wr, + apm, + pps, + vs, + app, + dss, + dsp, + appdsp, + vsapm, + cheese, + gbe, + nyaapp, + area, + eTR, + acceTR, + acceTRabs, + opener, + plonk, + infDS, + stride, + stridemMinusPlonk, + openerMinusInfDS + } + +const Map chartsShortTitles = { + Stats.tr: "TR", + Stats.gxe: "Glixare", + Stats.s1tr: "S1 TR", + Stats.glicko: "Glicko", + Stats.rd: "RD", + Stats.gp: "GP", + Stats.gw: "GW", + Stats.wr: "WR%", + Stats.apm: "APM", + Stats.pps: "PPS", + Stats.vs: "VS", + Stats.app: "APP", + Stats.dss: "DS/S", + Stats.dsp: "DS/P", + Stats.appdsp: "APP + DS/P", + Stats.vsapm: "VS/APM", + Stats.cheese: "Cheese", + Stats.gbe: "GbE", + Stats.nyaapp: "wAPP", + Stats.area: "Area", + Stats.eTR: "eTR", + Stats.acceTR: "±eTR", + Stats.acceTRabs: "+eTR absolute", + Stats.opener: "Opener", + Stats.plonk: "Plonk", + Stats.infDS: "Inf. DS", + Stats.stride: "Stride", + Stats.stridemMinusPlonk: "Stride - Plonk", + Stats.openerMinusInfDS: "Opener - Inf. DS" + }; + +const Map rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:458 + 'x+': Color(0xFF643C8D), + 'x': Color(0xFFFF45FF), + 'u': Color(0xFFFF3813), + 'ss': Color(0xFFDB8B1F), + 's+': Color(0xFFD8AF0E), + 's': Color(0xFFE0A71B), + 's-': Color(0xFFB2972B), + 'a+': Color(0xFF1FA834), + 'a': Color(0xFF46AD51), + 'a-': Color(0xFF3BB687), + 'b+': Color(0xFF4F99C0), + 'b': Color(0xFF4F64C9), + 'b-': Color(0xFF5650C7), + 'c+': Color(0xFF552883), + 'c': Color(0xFF733E8F), + 'c-': Color(0xFF79558C), + 'd+': Color(0xFF8E6091), + 'd': Color(0xFF907591), + 'z': Color(0xFF375433) +}; + +const Map sprintAverages = { // based on https://discord.com/channels/673303546107658242/674421736162197515/1244287342965952562 + 'x': Duration(seconds: 25, milliseconds: 144), + 'u': Duration(seconds: 36, milliseconds: 115), + 'ss': Duration(seconds: 46, milliseconds: 396), + 's+': Duration(seconds: 55, milliseconds: 056), + 's': Duration(seconds: 61, milliseconds: 892), + 's-': Duration(seconds: 68, milliseconds: 918), + 'a+': Duration(seconds: 76, milliseconds: 187), + 'a': Duration(seconds: 83, milliseconds: 529), + 'a-': Duration(seconds: 88, milliseconds: 608), + 'b+': Duration(seconds: 97, milliseconds: 626), + 'b': Duration(seconds: 104, milliseconds: 687), + 'b-': Duration(seconds: 113, milliseconds: 372), + 'c+': Duration(seconds: 123, milliseconds: 461), + 'c': Duration(seconds: 135, milliseconds: 326), + 'c-': Duration(seconds: 147, milliseconds: 056), + 'd+': Duration(seconds: 156, milliseconds: 757), + 'd': Duration(seconds: 167, milliseconds: 393), + //'z': Duration(seconds: 66, milliseconds: 802) +}; + +const Map blitzAverages = { + 'x': 600715, + 'u': 379418, + 'ss': 233740, + 's+': 158295, + 's': 125164, + 's-': 100933, + 'a+': 83593, + 'a': 68613, + 'a-': 60219, + 'b+': 51197, + 'b': 44171, + 'b-': 39045, + 'c+': 34130, + 'c': 28931, + 'c-': 25095, + 'd+': 22944, + 'd': 20728, + //'z': 72084 +}; \ No newline at end of file diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index e4dd836..68f1d04 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -1,7 +1,12 @@ import 'dart:math'; import 'dart:typed_data'; -import 'tetrio.dart'; +import 'package:tetra_stats/data_objects/clears.dart'; +import 'package:tetra_stats/data_objects/end_context_multi.dart'; +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/finesse.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; // I want to implement those fancy TWC stats // So, i'm going to read replay for things diff --git a/lib/data_objects/tetrio_player.dart b/lib/data_objects/tetrio_player.dart new file mode 100644 index 0000000..63fd430 --- /dev/null +++ b/lib/data_objects/tetrio_player.dart @@ -0,0 +1,150 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; +import 'package:flutter/foundation.dart'; +import 'package:tetra_stats/data_objects/badge.dart'; +import 'package:tetra_stats/data_objects/connections.dart'; +import 'package:tetra_stats/data_objects/distinguishment.dart'; +import 'package:tetra_stats/data_objects/tetrio_zen.dart'; + +class TetrioPlayer { + late String userId; + late String username; + late DateTime state; + late String role; + int? avatarRevision; + int? bannerRevision; + DateTime? registrationTime; + List badges = []; + String? bio; + String? country; + late int friendCount; + late int gamesPlayed; + late int gamesWon; + late Duration gameTime; + late double xp; + late int supporterTier; + late bool verified; + bool? badstanding; + String? botmaster; + Connections? connections; + TetrioZen? zen; + Distinguishment? distinguishment; + DateTime? cachedUntil; + + TetrioPlayer({ + required this.userId, + required this.username, + required this.role, + required this.state, + this.avatarRevision, + this.bannerRevision, + this.registrationTime, + required this.badges, + this.bio, + this.country, + required this.friendCount, + required this.gamesPlayed, + required this.gamesWon, + required this.gameTime, + required this.xp, + required this.supporterTier, + required this.verified, + this.badstanding, + this.botmaster, + required this.connections, + this.zen, + this.distinguishment, + this.cachedUntil + }); + + double get level => pow((xp / 500), 0.6) + (xp / (5000 + (max(0, xp - 4 * pow(10, 6)) / 5000))) + 1; + + TetrioPlayer.fromJson(Map json, DateTime stateTime, String id, String nick, [DateTime? cUntil]) { + //developer.log("TetrioPlayer.fromJson $stateTime: $json", name: "data_objects/tetrio"); + userId = id; + username = nick; + state = stateTime; + role = json['role']; + registrationTime = json['ts'] != null ? DateTime.parse(json['ts']) : DateTime.fromMillisecondsSinceEpoch(int.parse(id.substring(0, 8), radix: 16) * 1000); + if (json['badges'] != null) { + json['badges'].forEach((v) { + badges.add(Badge.fromJson(v)); + }); + } + xp = json['xp'] != null ? json['xp'].toDouble() : -1; + gamesPlayed = json['gamesplayed'] ?? -1; + gamesWon = json['gameswon'] ?? -1; + gameTime = json['gametime'] != null && json['gametime'] != -1 ? Duration(microseconds: (json['gametime'].toDouble() * 1000000).floor()) : const Duration(seconds: -1); + country = json['country']; + supporterTier = json['supporter_tier'] ?? 0; + verified = json['verified'] ?? false; + avatarRevision = json['avatar_revision']; + bannerRevision = json['banner_revision']; + bio = json['bio']; + if (json['connections'] != null && json['connections'].isNotEmpty) connections = Connections.fromJson(json['connections']); + distinguishment = json['distinguishment'] != null ? Distinguishment.fromJson(json['distinguishment']) : null; + friendCount = json['friend_count'] ?? 0; + badstanding = json['badstanding']; + botmaster = json['botmaster']; + cachedUntil = cUntil; + } + + Map toJson() { + final Map data = {}; + // data['_id'] = userId; + // data['username'] = username; + data['role'] = role; + if (registrationTime != null) data['ts'] = registrationTime?.toString(); + if (badges.isNotEmpty) data['badges'] = badges.map((v) => v.toJson()).toList(); + if (xp >= 0) data['xp'] = xp; + if (gamesPlayed >= 0) data['gamesplayed'] = gamesPlayed; + if (gamesWon >= 0) data['gameswon'] = gamesWon; + if (!gameTime.isNegative) data['gametime'] = gameTime.inMicroseconds / 1000000; + if (country != null) data['country'] = country; + if (supporterTier > 0) data['supporter_tier'] = supporterTier; + if (verified) data['verified'] = verified; + if (distinguishment != null) data['distinguishment'] = distinguishment?.toJson(); + if (avatarRevision != null) data['avatar_revision'] = avatarRevision; + if (bannerRevision != null) data['banner_revision'] = bannerRevision; + if (bio != null) data['bio'] = bio; + if (connections != null) data['connections'] = connections!.toJson(); + if (friendCount > 0) data['friend_count'] = friendCount; + if (badstanding != null) data['badstanding'] = badstanding; + if (botmaster != null) data['botmaster'] = botmaster; + //developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio"); + return data; + } + + bool isSameState(covariant TetrioPlayer other) { + if (userId != other.userId) return false; + if (username != other.username) return false; + if (role != other.role) return false; + if (listEquals(badges, other.badges) == false) return false; + //if (bio != other.bio) return false; + if (country != other.country) return false; + if (friendCount != other.friendCount) return false; + if (gamesPlayed != other.gamesPlayed) return false; + if (gamesWon != other.gamesWon) return false; + if (gameTime != other.gameTime) return false; + if (xp != other.xp) return false; + if (supporterTier != other.supporterTier) return false; + if (verified != other.verified) return false; + if (badstanding != other.badstanding) return false; + if (botmaster != other.botmaster) return false; + if (connections != other.connections) return false; + if (distinguishment != other.distinguishment) return false; + return true; + } + + @override + String toString() { + return "$username ($state)"; + } + + @override + int get hashCode => state.hashCode; + + @override + bool operator ==(covariant TetrioPlayer other) => isSameState(other) && state.isAtSameMomentAs(other.state); +} diff --git a/lib/data_objects/tetrio_player_from_leaderboard.dart b/lib/data_objects/tetrio_player_from_leaderboard.dart new file mode 100644 index 0000000..28a7fab --- /dev/null +++ b/lib/data_objects/tetrio_player_from_leaderboard.dart @@ -0,0 +1,145 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; + +class TetrioPlayerFromLeaderboard { + late String userId; + late String username; + late String role; + late double xp; + String? country; + late DateTime timestamp; + late int gamesPlayed; + late int gamesWon; + late double tr; + late double gxe; + late double? glicko; + late double? rd; + late String rank; + late String? bestRank; + late double apm; + late double pps; + late double vs; + late bool decaying; + late NerdStats nerdStats; + late EstTr estTr; + late Playstyle playstyle; + + TetrioPlayerFromLeaderboard( + this.userId, + this.username, + this.role, + this.xp, + this.country, + this.timestamp, + this.gamesPlayed, + this.gamesWon, + this.tr, + this.gxe, + this.glicko, + this.rd, + this.rank, + this.bestRank, + this.apm, + this.pps, + this.vs, + this.decaying){ + nerdStats = NerdStats(apm, pps, vs); + estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + } + + double get winrate => gamesWon / gamesPlayed; + double get esttracc => estTr.esttr - tr; + double get s1tr => gxe * 250; + + TetrioPlayerFromLeaderboard.fromJson(Map json, DateTime ts) { + userId = json['_id']; + username = json['username']; + role = json['role']; + xp = json['xp'].toDouble(); + country = json['country']; + timestamp = ts; + gamesPlayed = json['league']['gamesplayed'] as int; + gamesWon = json['league']['gameswon'] as int; + tr = json['league']['tr'] != null ? json['league']['tr'].toDouble() : 0; + gxe = json['league']['gxe']??-1; + glicko = json['league']['glicko']?.toDouble(); + rd = json['league']['rd']?.toDouble(); + rank = json['league']['rank']; + bestRank = json['league']['bestrank']; + apm = json['league']['apm'] != null ? json['league']['apm'].toDouble() : 0.00; + pps = json['league']['pps'] != null ? json['league']['pps'].toDouble() : 0.00; + vs = json['league']['vs'] != null ? json['league']['vs'].toDouble(): 0.00; + decaying = json['league']['decaying']; + nerdStats = NerdStats(apm, pps, vs); + estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe); + playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank); + } + + num getStatByEnum(Stats stat){ + switch (stat) { + case Stats.tr: + return tr; + case Stats.glicko: + return glicko??-1; + case Stats.gxe: + return gxe; + case Stats.s1tr: + return s1tr; + case Stats.rd: + return rd??-1; + case Stats.gp: + return gamesPlayed; + case Stats.gw: + return gamesWon; + case Stats.wr: + return winrate*100; + case Stats.apm: + return apm; + case Stats.pps: + return pps; + case Stats.vs: + return vs; + case Stats.app: + return nerdStats.app; + case Stats.dss: + return nerdStats.dss; + case Stats.dsp: + return nerdStats.dsp; + case Stats.appdsp: + return nerdStats.appdsp; + case Stats.vsapm: + return nerdStats.vsapm; + case Stats.cheese: + return nerdStats.cheese; + case Stats.gbe: + return nerdStats.gbe; + case Stats.nyaapp: + return nerdStats.nyaapp; + case Stats.area: + return nerdStats.area; + case Stats.eTR: + return estTr.esttr; + case Stats.acceTR: + return esttracc; + case Stats.acceTRabs: + return esttracc.abs(); + case Stats.opener: + return playstyle.opener; + case Stats.plonk: + return playstyle.plonk; + case Stats.infDS: + return playstyle.infds; + case Stats.stride: + return playstyle.stride; + case Stats.stridemMinusPlonk: + return playstyle.stride - playstyle.plonk; + case Stats.openerMinusInfDS: + return playstyle.opener - playstyle.infds; + } + } +} diff --git a/lib/data_objects/tetrio_players_leaderboard.dart b/lib/data_objects/tetrio_players_leaderboard.dart new file mode 100644 index 0000000..1d2305d --- /dev/null +++ b/lib/data_objects/tetrio_players_leaderboard.dart @@ -0,0 +1,759 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; +import 'package:tetra_stats/data_objects/leaderboard_position.dart'; +import 'package:tetra_stats/data_objects/player_leaderboard_position.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart'; + +class TetrioPlayersLeaderboard { + late String type; + late DateTime timestamp; + late List leaderboard; + + TetrioPlayersLeaderboard(this.type, this.leaderboard); + + @override + String toString(){ + return "$type leaderboard: ${leaderboard.length} players"; + } + + List getStatRanking(List leaderboard, Stats stat, {bool reversed = false, String country = ""}){ + List lb = List.from(leaderboard); + if (country.isNotEmpty){ + lb.removeWhere((element) => element.country != country); + } + lb.sort(((a, b) { + if (a.getStatByEnum(stat).isNaN) return 1; + if (b.getStatByEnum(stat).isNaN) return -1; + if (a.getStatByEnum(stat) > b.getStatByEnum(stat)){ + return reversed ? 1 : -1; + }else if (a.getStatByEnum(stat) == b.getStatByEnum(stat)){ + return 0; + }else{ + return reversed ? -1 : 1; + } + })); + return lb; + } + + List getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible + if (rank.isNotEmpty && !rankCutoffs.keys.contains(rank)) throw Exception("Invalid rank"); + List filtredLeaderboard = List.from(leaderboard); + if (rank.isNotEmpty) { + filtredLeaderboard.removeWhere((element) => element.rank != rank); + } + if (filtredLeaderboard.isNotEmpty){ + double avgAPM = 0, + avgPPS = 0, + avgVS = 0, + avgTR = 0, + avgGlixare = 0, + avgGlicko = 0, + avgRD = 0, + avgAPP = 0, + avgVSAPM = 0, + avgDSS = 0, + avgDSP = 0, + avgAPPDSP = 0, + avgCheese = 0, + avgGBE = 0, + avgNyaAPP = 0, + avgArea = 0, + avgEstTR = 0, + avgEstAcc = 0, + avgOpener = 0, + avgPlonk = 0, + avgStride = 0, + avgInfDS = 0, + lowestTR = 25000, + lowestGlixare = double.infinity, + lowestGlicko = double.infinity, + lowestRD = double.infinity, + lowestWinrate = double.infinity, + lowestAPM = double.infinity, + lowestPPS = double.infinity, + lowestVS = double.infinity, + lowestAPP = double.infinity, + lowestVSAPM = double.infinity, + lowestDSS = double.infinity, + lowestDSP = double.infinity, + lowestAPPDSP = double.infinity, + lowestCheese = double.infinity, + lowestGBE = double.infinity, + lowestNyaAPP = double.infinity, + lowestArea = double.infinity, + lowestEstTR = double.infinity, + lowestEstAcc = double.infinity, + lowestOpener = double.infinity, + lowestPlonk = double.infinity, + lowestStride = double.infinity, + lowestInfDS = double.infinity, + highestTR = double.negativeInfinity, + highestGlixare = double.negativeInfinity, + highestGlicko = double.negativeInfinity, + highestRD = double.negativeInfinity, + highestWinrate = double.negativeInfinity, + highestAPM = double.negativeInfinity, + highestPPS = double.negativeInfinity, + highestVS = double.negativeInfinity, + highestAPP = double.negativeInfinity, + highestVSAPM = double.negativeInfinity, + highestDSS = double.negativeInfinity, + highestDSP = double.negativeInfinity, + highestAPPDSP = double.negativeInfinity, + highestCheese = double.negativeInfinity, + highestGBE = double.negativeInfinity, + highestNyaAPP = double.negativeInfinity, + highestArea = double.negativeInfinity, + highestEstTR = double.negativeInfinity, + highestEstAcc = double.negativeInfinity, + highestOpener = double.negativeInfinity, + highestPlonk = double.negativeInfinity, + highestStride = double.negativeInfinity, + highestInfDS = double.negativeInfinity; + int avgGamesPlayed = 0, + avgGamesWon = 0, + totalGamesPlayed = 0, + totalGamesWon = 0, + lowestGamesPlayed = pow(2, 53) as int, + lowestGamesWon = pow(2, 53) as int, + highestGamesPlayed = 0, + highestGamesWon = 0; + String lowestTRid = "", lowestTRnick = "", + lowestGlixareID = "", lowestGlixareNick = "", + lowestGlickoID = "", lowestGlickoNick = "", + lowestRdID = "", lowestRdNick = "", + lowestGamesPlayedID = "", lowestGamesPlayedNick = "", + lowestGamesWonID = "", lowestGamesWonNick = "", + lowestWinrateID = "", lowestWinrateNick = "", + lowestAPMid = "", lowestAPMnick = "", + lowestPPSid = "", lowestPPSnick = "", + lowestVSid = "", lowestVSnick = "", + lowestAPPid = "", lowestAPPnick = "", + lowestVSAPMid = "", lowestVSAPMnick = "", + lowestDSSid = "", lowestDSSnick = "", + lowestDSPid = "", lowestDSPnick = "", + lowestAPPDSPid = "", lowestAPPDSPnick = "", + lowestCheeseID = "", lowestCheeseNick = "", + lowestGBEid = "", lowestGBEnick = "", + lowestNyaAPPid = "", lowestNyaAPPnick = "", + lowestAreaID = "", lowestAreaNick = "", + lowestEstTRid = "", lowestEstTRnick = "", + lowestEstAccID = "", lowestEstAccNick = "", + lowestOpenerID = "", lowestOpenerNick = "", + lowestPlonkID = "", lowestPlonkNick = "", + lowestStrideID = "", lowestStrideNick = "", + lowestInfDSid = "", lowestInfDSnick = "", + highestTRid = "", highestTRnick = "", + highestGlixareID = "", highestGlixareNick = "", + highestGlickoID = "", highestGlickoNick = "", + highestRdID = "", highestRdNick = "", + highestGamesPlayedID = "", highestGamesPlayedNick = "", + highestGamesWonID = "", highestGamesWonNick = "", + highestWinrateID = "", highestWinrateNick = "", + highestAPMid = "", highestAPMnick = "", + highestPPSid = "", highestPPSnick = "", + highestVSid = "", highestVSnick = "", + highestAPPid = "", highestAPPnick = "", + highestVSAPMid = "", highestVSAPMnick = "", + highestDSSid = "", highestDSSnick = "", + highestDSPid = "", highestDSPnick = "", + highestAPPDSPid = "", highestAPPDSPnick = "", + highestCheeseID = "", highestCheeseNick = "", + highestGBEid = "", highestGBEnick = "", + highestNyaAPPid = "", highestNyaAPPnick = "", + highestAreaID = "", highestAreaNick = "", + highestEstTRid = "", highestEstTRnick = "", + highestEstAccID = "", highestEstAccNick = "", + highestOpenerID = "", highestOpenerNick = "", + highestPlonkID = "", highestPlonkNick = "", + highestStrideID = "", highestStrideNick = "", + highestInfDSid = "", highestInfDSnick = ""; + for (var entry in filtredLeaderboard){ + avgAPM += entry.apm; + avgPPS += entry.pps; + avgVS += entry.vs; + avgTR += entry.tr; + avgGlixare += entry.gxe; + if (entry.glicko != null) avgGlicko += entry.glicko!; + if (entry.rd != null) avgRD += entry.rd!; + avgAPP += entry.nerdStats.app; + avgVSAPM += entry.nerdStats.vsapm; + avgDSS += entry.nerdStats.dss; + avgDSP += entry.nerdStats.dsp; + avgAPPDSP += entry.nerdStats.appdsp; + avgCheese += entry.nerdStats.cheese; + avgGBE += entry.nerdStats.gbe; + avgNyaAPP += entry.nerdStats.nyaapp; + avgArea += entry.nerdStats.area; + avgEstTR += entry.estTr.esttr; + avgEstAcc += entry.esttracc; + avgOpener += entry.playstyle.opener; + avgPlonk += entry.playstyle.plonk; + avgStride += entry.playstyle.stride; + avgInfDS += entry.playstyle.infds; + totalGamesPlayed += entry.gamesPlayed; + totalGamesWon += entry.gamesWon; + if (entry.tr < lowestTR){ + lowestTR = entry.tr; + lowestTRid = entry.userId; + lowestTRnick = entry.username; + } + if (entry.gxe < lowestGlixare){ + lowestGlixare = entry.gxe; + lowestGlixareID = entry.userId; + lowestGlixareNick = entry.username; + } + if (entry.glicko != null && entry.glicko! < lowestGlicko){ + lowestGlicko = entry.glicko!; + lowestGlickoID = entry.userId; + lowestGlickoNick = entry.username; + } + if (entry.rd != null && entry.rd! < lowestRD){ + lowestRD = entry.rd!; + lowestRdID = entry.userId; + lowestRdNick = entry.username; + } + if (entry.gamesPlayed < lowestGamesPlayed){ + lowestGamesPlayed = entry.gamesPlayed; + lowestGamesPlayedID = entry.userId; + lowestGamesPlayedNick = entry.username; + } + if (entry.gamesWon < lowestGamesWon){ + lowestGamesWon = entry.gamesWon; + lowestGamesWonID = entry.userId; + lowestGamesWonNick = entry.username; + } + if (entry.winrate < lowestWinrate){ + lowestWinrate = entry.winrate; + lowestWinrateID = entry.userId; + lowestWinrateNick = entry.username; + } + if (entry.apm < lowestAPM){ + lowestAPM = entry.apm; + lowestAPMid = entry.userId; + lowestAPMnick = entry.username; + } + if (entry.pps < lowestPPS){ + lowestPPS = entry.pps; + lowestPPSid = entry.userId; + lowestPPSnick = entry.username; + } + if (entry.vs < lowestVS){ + lowestVS = entry.vs; + lowestVSid = entry.userId; + lowestVSnick = entry.username; + } + if (entry.nerdStats.app < lowestAPP){ + lowestAPP = entry.nerdStats.app; + lowestAPPid = entry.userId; + lowestAPPnick = entry.username; + } + if (entry.nerdStats.vsapm < lowestVSAPM){ + lowestVSAPM = entry.nerdStats.vsapm; + lowestVSAPMid = entry.userId; + lowestVSAPMnick = entry.username; + } + if (entry.nerdStats.dss < lowestDSS){ + lowestDSS = entry.nerdStats.dss; + lowestDSSid = entry.userId; + lowestDSSnick = entry.username; + } + if (entry.nerdStats.dsp < lowestDSP){ + lowestDSP = entry.nerdStats.dsp; + lowestDSPid = entry.userId; + lowestDSPnick = entry.username; + } + if (entry.nerdStats.appdsp < lowestAPPDSP){ + lowestAPPDSP = entry.nerdStats.appdsp; + lowestAPPDSPid = entry.userId; + lowestAPPDSPnick = entry.username; + } + if (entry.nerdStats.cheese < lowestCheese){ + lowestCheese = entry.nerdStats.cheese; + lowestCheeseID = entry.userId; + lowestCheeseNick = entry.username; + } + if (entry.nerdStats.gbe < lowestGBE){ + lowestGBE = entry.nerdStats.gbe; + lowestGBEid = entry.userId; + lowestGBEnick = entry.username; + } + if (entry.nerdStats.nyaapp < lowestNyaAPP){ + lowestNyaAPP = entry.nerdStats.nyaapp; + lowestNyaAPPid = entry.userId; + lowestNyaAPPnick = entry.username; + } + if (entry.nerdStats.area < lowestArea){ + lowestArea = entry.nerdStats.area; + lowestAreaID = entry.userId; + lowestAreaNick = entry.username; + } + if (entry.estTr.esttr < lowestEstTR){ + lowestEstTR = entry.estTr.esttr; + lowestEstTRid = entry.userId; + lowestEstTRnick = entry.username; + } + if (entry.esttracc < lowestEstAcc){ + lowestEstAcc = entry.esttracc; + lowestEstAccID = entry.userId; + lowestEstAccNick = entry.username; + } + if (entry.playstyle.opener < lowestOpener){ + lowestOpener = entry.playstyle.opener; + lowestOpenerID = entry.userId; + lowestOpenerNick = entry.username; + } + if (entry.playstyle.plonk < lowestPlonk){ + lowestPlonk = entry.playstyle.plonk; + lowestPlonkID = entry.userId; + lowestPlonkNick = entry.username; + } + if (entry.playstyle.stride < lowestStride){ + lowestStride = entry.playstyle.stride; + lowestStrideID = entry.userId; + lowestStrideNick = entry.username; + } + if (entry.playstyle.infds < lowestInfDS){ + lowestInfDS = entry.playstyle.infds; + lowestInfDSid = entry.userId; + lowestInfDSnick = entry.username; + } + if (entry.tr > highestTR){ + highestTR = entry.tr; + highestTRid = entry.userId; + highestTRnick = entry.username; + } + if (entry.gxe > highestGlixare){ + highestGlixare = entry.gxe; + highestGlixareID = entry.userId; + highestGlixareNick = entry.username; + } + if (entry.glicko != null && entry.glicko! > highestGlicko){ + highestGlicko = entry.glicko!; + highestGlickoID = entry.userId; + highestGlickoNick = entry.username; + } + if (entry.rd != null && entry.rd! > highestRD){ + highestRD = entry.rd!; + highestRdID = entry.userId; + highestRdNick = entry.username; + } + if (entry.gamesPlayed > highestGamesPlayed){ + highestGamesPlayed = entry.gamesPlayed; + highestGamesPlayedID = entry.userId; + highestGamesPlayedNick = entry.username; + } + if (entry.gamesWon > highestGamesWon){ + highestGamesWon = entry.gamesWon; + highestGamesWonID = entry.userId; + highestGamesWonNick = entry.username; + } + if (entry.winrate > highestWinrate){ + highestWinrate = entry.winrate; + highestWinrateID = entry.userId; + highestWinrateNick = entry.username; + } + if (entry.apm > highestAPM){ + highestAPM = entry.apm; + highestAPMid = entry.userId; + highestAPMnick = entry.username; + } + if (entry.pps > highestPPS){ + highestPPS = entry.pps; + highestPPSid = entry.userId; + highestPPSnick = entry.username; + } + if (entry.vs > highestVS){ + highestVS = entry.vs; + highestVSid = entry.userId; + highestVSnick = entry.username; + } + if (entry.nerdStats.app > highestAPP){ + highestAPP = entry.nerdStats.app; + highestAPPid = entry.userId; + highestAPPnick = entry.username; + } + if (entry.nerdStats.vsapm > highestVSAPM){ + highestVSAPM = entry.nerdStats.vsapm; + highestVSAPMid = entry.userId; + highestVSAPMnick = entry.username; + } + if (entry.nerdStats.dss > highestDSS){ + highestDSS = entry.nerdStats.dss; + highestDSSid = entry.userId; + highestDSSnick = entry.username; + } + if (entry.nerdStats.dsp > highestDSP){ + highestDSP = entry.nerdStats.dsp; + highestDSPid = entry.userId; + highestDSPnick = entry.username; + } + if (entry.nerdStats.appdsp > highestAPPDSP){ + highestAPPDSP = entry.nerdStats.appdsp; + highestAPPDSPid = entry.userId; + highestAPPDSPnick = entry.username; + } + if (entry.nerdStats.cheese > highestCheese){ + highestCheese = entry.nerdStats.cheese; + highestCheeseID = entry.userId; + highestCheeseNick = entry.username; + } + if (entry.nerdStats.gbe > highestGBE){ + highestGBE = entry.nerdStats.gbe; + highestGBEid = entry.userId; + highestGBEnick = entry.username; + } + if (entry.nerdStats.nyaapp > highestNyaAPP){ + highestNyaAPP = entry.nerdStats.nyaapp; + highestNyaAPPid = entry.userId; + highestNyaAPPnick = entry.username; + } + if (entry.nerdStats.area > highestArea){ + highestArea = entry.nerdStats.area; + highestAreaID = entry.userId; + highestAreaNick = entry.username; + } + if (entry.estTr.esttr > highestEstTR){ + highestEstTR = entry.estTr.esttr; + highestEstTRid = entry.userId; + highestEstTRnick = entry.username; + } + if (entry.esttracc > highestEstAcc){ + highestEstAcc = entry.esttracc; + highestEstAccID = entry.userId; + highestEstAccNick = entry.username; + } + if (entry.playstyle.opener > highestOpener){ + highestOpener = entry.playstyle.opener; + highestOpenerID = entry.userId; + highestOpenerNick = entry.username; + } + if (entry.playstyle.plonk > highestPlonk){ + highestPlonk = entry.playstyle.plonk; + highestPlonkID = entry.userId; + highestPlonkNick = entry.username; + } + if (entry.playstyle.stride > highestStride){ + highestStride = entry.playstyle.stride; + highestStrideID = entry.userId; + highestStrideNick = entry.username; + } + if (entry.playstyle.infds > highestInfDS){ + highestInfDS = entry.playstyle.infds; + highestInfDSid = entry.userId; + highestInfDSnick = entry.username; + } + } + avgAPM /= filtredLeaderboard.length; + avgPPS /= filtredLeaderboard.length; + avgVS /= filtredLeaderboard.length; + avgTR /= filtredLeaderboard.length; + avgGlixare /= filtredLeaderboard.length; + avgGlicko /= filtredLeaderboard.length; + avgRD /= filtredLeaderboard.length; + avgAPP /= filtredLeaderboard.length; + avgVSAPM /= filtredLeaderboard.length; + avgDSS /= filtredLeaderboard.length; + avgDSP /= filtredLeaderboard.length; + avgAPPDSP /= leaderboard.length; + avgCheese /= filtredLeaderboard.length; + avgGBE /= filtredLeaderboard.length; + avgNyaAPP /= filtredLeaderboard.length; + avgArea /= filtredLeaderboard.length; + avgEstTR /= filtredLeaderboard.length; + avgEstAcc /= filtredLeaderboard.length; + avgOpener /= filtredLeaderboard.length; + avgPlonk /= filtredLeaderboard.length; + avgStride /= filtredLeaderboard.length; + avgInfDS /= filtredLeaderboard.length; + avgGamesPlayed = (totalGamesPlayed / filtredLeaderboard.length).floor(); + avgGamesWon = (totalGamesWon / filtredLeaderboard.length).floor(); + return [TetraLeague(id: "", timestamp: DateTime.now(), apm: avgAPM, pps: avgPPS, vs: avgVS, gxe: avgGlixare, glicko: avgGlicko, rd: avgRD, gamesPlayed: avgGamesPlayed, gamesWon: avgGamesWon, bestRank: rank, decaying: false, tr: avgTR, rank: rank == "" ? "z" : rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1, season: currentSeason), + { + "everyone": rank == "", + "totalGamesPlayed": totalGamesPlayed, + "totalGamesWon": totalGamesWon, + "players": filtredLeaderboard.length, + "lowestTR": lowestTR, + "lowestTRid": lowestTRid, + "lowestTRnick": lowestTRnick, + "lowestGlixare": lowestGlixare, + "lowestGlixareID": lowestGlixareID, + "lowestGlixareNick": lowestGlixareNick, + "lowestS1tr": lowestGlixare * 250, + "lowestS1trID": lowestGlixareID, + "lowestS1trNick": lowestGlixareNick, + "lowestGlicko": lowestGlicko, + "lowestGlickoID": lowestGlickoID, + "lowestGlickoNick": lowestGlickoNick, + "lowestRD": lowestRD, + "lowestRdID": lowestRdID, + "lowestRdNick": lowestRdNick, + "lowestGamesPlayed": lowestGamesPlayed, + "lowestGamesPlayedID": lowestGamesPlayedID, + "lowestGamesPlayedNick": lowestGamesPlayedNick, + "lowestGamesWon": lowestGamesWon, + "lowestGamesWonID": lowestGamesWonID, + "lowestGamesWonNick": lowestGamesWonNick, + "lowestWinrate": lowestWinrate, + "lowestWinrateID": lowestWinrateID, + "lowestWinrateNick": lowestWinrateNick, + "lowestAPM": lowestAPM, + "lowestAPMid": lowestAPMid, + "lowestAPMnick": lowestAPMnick, + "lowestPPS": lowestPPS, + "lowestPPSid": lowestPPSid, + "lowestPPSnick": lowestPPSnick, + "lowestVS": lowestVS, + "lowestVSid": lowestVSid, + "lowestVSnick": lowestVSnick, + "lowestAPP": lowestAPP, + "lowestAPPid": lowestAPPid, + "lowestAPPnick": lowestAPPnick, + "lowestVSAPM": lowestVSAPM, + "lowestVSAPMid": lowestVSAPMid, + "lowestVSAPMnick": lowestVSAPMnick, + "lowestDSS": lowestDSS, + "lowestDSSid": lowestDSSid, + "lowestDSSnick": lowestDSSnick, + "lowestDSP": lowestDSP, + "lowestDSPid": lowestDSPid, + "lowestDSPnick": lowestDSPnick, + "lowestAPPDSP": lowestAPPDSP, + "lowestAPPDSPid": lowestAPPDSPid, + "lowestAPPDSPnick": lowestAPPDSPnick, + "lowestCheese": lowestCheese, + "lowestCheeseID": lowestCheeseID, + "lowestCheeseNick": lowestCheeseNick, + "lowestGBE": lowestGBE, + "lowestGBEid": lowestGBEid, + "lowestGBEnick": lowestGBEnick, + "lowestNyaAPP": lowestNyaAPP, + "lowestNyaAPPid": lowestNyaAPPid, + "lowestNyaAPPnick": lowestNyaAPPnick, + "lowestArea": lowestArea, + "lowestAreaID": lowestAreaID, + "lowestAreaNick": lowestAreaNick, + "lowestEstTR": lowestEstTR, + "lowestEstTRid": lowestEstTRid, + "lowestEstTRnick": lowestEstTRnick, + "lowestEstAcc": lowestEstAcc, + "lowestEstAccID": lowestEstAccID, + "lowestEstAccNick": lowestEstAccNick, + "lowestOpener": lowestOpener, + "lowestOpenerID": lowestOpenerID, + "lowestOpenerNick": lowestOpenerNick, + "lowestPlonk": lowestPlonk, + "lowestPlonkID": lowestPlonkID, + "lowestPlonkNick": lowestPlonkNick, + "lowestStride": lowestStride, + "lowestStrideID": lowestStrideID, + "lowestStrideNick": lowestStrideNick, + "lowestInfDS": lowestInfDS, + "lowestInfDSid": lowestInfDSid, + "lowestInfDSnick": lowestInfDSnick, + "highestTR": highestTR, + "highestTRid": highestTRid, + "highestTRnick": highestTRnick, + "highestGlixare": highestGlixare, + "highestGlixareID": highestGlixareID, + "highestGlixareNick": highestGlixareNick, + "highestS1tr": highestGlixare * 250, + "highestS1trID": highestGlixareID, + "highestS1trNick": highestGlixareNick, + "highestGlicko": highestGlicko, + "highestGlickoID": highestGlickoID, + "highestGlickoNick": highestGlickoNick, + "highestRD": highestRD, + "highestRdID": highestRdID, + "highestRdNick": highestRdNick, + "highestGamesPlayed": highestGamesPlayed, + "highestGamesPlayedID": highestGamesPlayedID, + "highestGamesPlayedNick": highestGamesPlayedNick, + "highestGamesWon": highestGamesWon, + "highestGamesWonID": highestGamesWonID, + "highestGamesWonNick": highestGamesWonNick, + "highestWinrate": highestWinrate, + "highestWinrateID": highestWinrateID, + "highestWinrateNick": highestWinrateNick, + "highestAPM": highestAPM, + "highestAPMid": highestAPMid, + "highestAPMnick": highestAPMnick, + "highestPPS": highestPPS, + "highestPPSid": highestPPSid, + "highestPPSnick": highestPPSnick, + "highestVS": highestVS, + "highestVSid": highestVSid, + "highestVSnick": highestVSnick, + "highestAPP": highestAPP, + "highestAPPid": highestAPPid, + "highestAPPnick": highestAPPnick, + "highestVSAPM": highestVSAPM, + "highestVSAPMid": highestVSAPMid, + "highestVSAPMnick": highestVSAPMnick, + "highestDSS": highestDSS, + "highestDSSid": highestDSSid, + "highestDSSnick": highestDSSnick, + "highestDSP": highestDSP, + "highestDSPid": highestDSPid, + "highestDSPnick": highestDSPnick, + "highestAPPDSP": highestAPPDSP, + "highestAPPDSPid": highestAPPDSPid, + "highestAPPDSPnick": highestAPPDSPnick, + "highestCheese": highestCheese, + "highestCheeseID": highestCheeseID, + "highestCheeseNick": highestCheeseNick, + "highestGBE": highestGBE, + "highestGBEid": highestGBEid, + "highestGBEnick": highestGBEnick, + "highestNyaAPP": highestNyaAPP, + "highestNyaAPPid": highestNyaAPPid, + "highestNyaAPPnick": highestNyaAPPnick, + "highestArea": highestArea, + "highestAreaID": highestAreaID, + "highestAreaNick": highestAreaNick, + "highestEstTR": highestEstTR, + "highestEstTRid": highestEstTRid, + "highestEstTRnick": highestEstTRnick, + "highestEstAcc": highestEstAcc, + "highestEstAccID": highestEstAccID, + "highestEstAccNick": highestEstAccNick, + "highestOpener": highestOpener, + "highestOpenerID": highestOpenerID, + "highestOpenerNick": highestOpenerNick, + "highestPlonk": highestPlonk, + "highestPlonkID": highestPlonkID, + "highestPlonkNick": highestPlonkNick, + "highestStride": highestStride, + "highestStrideID": highestStrideID, + "highestStrideNick": highestStrideNick, + "highestInfDS": highestInfDS, + "highestInfDSid": highestInfDSid, + "highestInfDSnick": highestInfDSnick, + "avgAPP": avgAPP, + "avgVSAPM": avgVSAPM, + "avgDSS": avgDSS, + "avgDSP": avgDSP, + "avgAPPDSP": avgAPPDSP, + "avgCheese": avgCheese, + "avgGBE": avgGBE, + "avgNyaAPP": avgNyaAPP, + "avgArea": avgArea, + "avgEstTR": avgEstTR, + "avgEstAcc": avgEstAcc, + "avgOpener": avgOpener, + "avgPlonk": avgPlonk, + "avgStride": avgStride, + "avgInfDS": avgInfDS, + "toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].tr : lowestTR, + "toEnterGlicko": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].glicko : 0, + "entries": filtredLeaderboard + }]; + }else{ + return [TetraLeague(id: "", timestamp: DateTime.now(), apm: 0, pps: 0, vs: 0, glicko: 0, rd: noTrRd, gamesPlayed: 0, gamesWon: 0, bestRank: rank, decaying: false, tr: 0, rank: rank, percentileRank: rank, gxe: -1, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1, season: currentSeason), + {"players": filtredLeaderboard.length, "lowestTR": 0, "toEnterTR": 0, "toEnterGlicko": 0}]; + } + } + + PlayerLeaderboardPosition? getLeaderboardPosition(Mapleague) { + if (league.values.first.gamesPlayed == 0) return null; + bool fakePositions = false; + late List copyOfLeaderboard; + if (leaderboard.indexWhere((element) => element.userId == league.keys.first) == -1){ + fakePositions =true; + copyOfLeaderboard = List.of(leaderboard); + copyOfLeaderboard.add(league.values.first.convertToPlayerFromLeaderboard(league.keys.first)); + } + List stats = [Stats.apm, Stats.pps, Stats.vs, Stats.gp, Stats.gw, Stats.wr, + Stats.app, Stats.vsapm, Stats.dss, Stats.dsp, Stats.appdsp, Stats.cheese, Stats.gbe, Stats.nyaapp, Stats.area, Stats.eTR, Stats.acceTR]; + List results = []; + for (Stats stat in stats) { + List sortedLeaderboard = getStatRanking(fakePositions ? copyOfLeaderboard : leaderboard, stat, reversed: stat == Stats.cheese ? true : false); + int position = sortedLeaderboard.indexWhere((element) => element.userId == league.keys.first) + 1; + if (position == 0) { + results.add(null); + } else { + results.add(LeaderboardPosition(fakePositions ? 1001 : position, position / sortedLeaderboard.length)); + } + } + return PlayerLeaderboardPosition.fromSearchResults(results); + } + + Map> get averages => { + 'x+': getAverageOfRank("x+"), + 'x': getAverageOfRank("x"), + 'u': getAverageOfRank("u"), + 'ss': getAverageOfRank("ss"), + 's+': getAverageOfRank("s+"), + 's': getAverageOfRank("s"), + 's-': getAverageOfRank("s-"), + 'a+': getAverageOfRank("a+"), + 'a': getAverageOfRank("a"), + 'a-': getAverageOfRank("a-"), + 'b+': getAverageOfRank("b+"), + 'b': getAverageOfRank("b"), + 'b-': getAverageOfRank("b-"), + 'c+': getAverageOfRank("c+"), + 'c': getAverageOfRank("c"), + 'c-': getAverageOfRank("c-"), + 'd+': getAverageOfRank("d+"), + 'd': getAverageOfRank("d"), + 'z': getAverageOfRank("z") + }; + + Map get cutoffs => { + 'x': getAverageOfRank("x")[1]["toEnterTR"], + 'u': getAverageOfRank("u")[1]["toEnterTR"], + 'ss': getAverageOfRank("ss")[1]["toEnterTR"], + 's+': getAverageOfRank("s+")[1]["toEnterTR"], + 's': getAverageOfRank("s")[1]["toEnterTR"], + 's-': getAverageOfRank("s-")[1]["toEnterTR"], + 'a+': getAverageOfRank("a+")[1]["toEnterTR"], + 'a': getAverageOfRank("a")[1]["toEnterTR"], + 'a-': getAverageOfRank("a-")[1]["toEnterTR"], + 'b+': getAverageOfRank("b+")[1]["toEnterTR"], + 'b': getAverageOfRank("b")[1]["toEnterTR"], + 'b-': getAverageOfRank("b-")[1]["toEnterTR"], + 'c+': getAverageOfRank("c+")[1]["toEnterTR"], + 'c': getAverageOfRank("c")[1]["toEnterTR"], + 'c-': getAverageOfRank("c-")[1]["toEnterTR"], + 'd+': getAverageOfRank("d+")[1]["toEnterTR"], + 'd': getAverageOfRank("d")[1]["toEnterTR"] + }; + + Map get cutoffsGlicko => { + 'x': getAverageOfRank("x")[1]["toEnterGlicko"], + 'u': getAverageOfRank("u")[1]["toEnterGlicko"], + 'ss': getAverageOfRank("ss")[1]["toEnterGlicko"], + 's+': getAverageOfRank("s+")[1]["toEnterGlicko"], + 's': getAverageOfRank("s")[1]["toEnterGlicko"], + 's-': getAverageOfRank("s-")[1]["toEnterGlicko"], + 'a+': getAverageOfRank("a+")[1]["toEnterGlicko"], + 'a': getAverageOfRank("a")[1]["toEnterGlicko"], + 'a-': getAverageOfRank("a-")[1]["toEnterGlicko"], + 'b+': getAverageOfRank("b+")[1]["toEnterGlicko"], + 'b': getAverageOfRank("b")[1]["toEnterGlicko"], + 'b-': getAverageOfRank("b-")[1]["toEnterGlicko"], + 'c+': getAverageOfRank("c+")[1]["toEnterGlicko"], + 'c': getAverageOfRank("c")[1]["toEnterGlicko"], + 'c-': getAverageOfRank("c-")[1]["toEnterGlicko"], + 'd+': getAverageOfRank("d+")[1]["toEnterGlicko"], + 'd': getAverageOfRank("d")[1]["toEnterGlicko"] + }; + + TetrioPlayersLeaderboard.fromJson(List json, String t, DateTime ts) { + type = t; + timestamp = ts; + leaderboard = []; + for (Map entry in json) { + leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry, ts)); + } + } + + addPlayers(List list){ + leaderboard.addAll(list); + } +} diff --git a/lib/data_objects/tetrio_zen.dart b/lib/data_objects/tetrio_zen.dart new file mode 100644 index 0000000..97e085c --- /dev/null +++ b/lib/data_objects/tetrio_zen.dart @@ -0,0 +1,24 @@ +// ignore_for_file: hash_and_equals + +import 'dart:math'; + +class TetrioZen { + late int level; + late int score; + + TetrioZen({required this.level, required this.score}); + + double get scoreRequirement => (10000 + 10000 * ((log(level + 1) / log(2)) - 1)); + + TetrioZen.fromJson(Map json) { + level = json['level']; + score = json['score']; + } + + Map toJson() { + final Map data = {}; + data['level'] = level; + data['score'] = score; + return data; + } +} diff --git a/lib/data_objects/user_records.dart b/lib/data_objects/user_records.dart new file mode 100644 index 0000000..cac93d4 --- /dev/null +++ b/lib/data_objects/user_records.dart @@ -0,0 +1,13 @@ +// ignore_for_file: hash_and_equals + +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/tetrio_zen.dart'; + +class UserRecords{ + String id; + RecordSingle? sprint; + RecordSingle? blitz; + TetrioZen zen; + + UserRecords(this.id, this.sprint, this.blitz, this.zen); +} diff --git a/lib/data_objects/zenith_results.dart b/lib/data_objects/zenith_results.dart new file mode 100644 index 0000000..d3efdb1 --- /dev/null +++ b/lib/data_objects/zenith_results.dart @@ -0,0 +1,36 @@ +// ignore_for_file: hash_and_equals + +class ZenithResults{ + late double altitude; + late double rank; + late double peakrank; + late double avgrankpts; + late int floor; + late double targetingfactor; + late double targetinggrace; + late double totalbonus; + late int revives; + late int revivesTotal; + late bool speedrun; + late bool speedrunSeen; + late List splits; + + ZenithResults.fromJson(Map json){ + altitude = json['altitude'].toDouble(); + rank = json['rank'].toDouble(); + peakrank = json['peakrank'].toDouble(); + avgrankpts = json['avgrankpts'].toDouble(); + floor = json['floor']; + targetingfactor = json['targetingfactor'].toDouble(); + targetinggrace = json['targetinggrace'].toDouble(); + totalbonus = json['totalbonus'].toDouble(); + revives = json['revives']; + revivesTotal = json['revivesTotal']; + speedrun = json['speedrun']; + speedrunSeen = json['speedrun_seen']; + splits = []; + for (int ms in json['splits']) { + splits.add(Duration(milliseconds: ms)); + } + } +} diff --git a/lib/main.dart b/lib/main.dart index bbba219..a847a1e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,7 +16,7 @@ import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:tetra_stats/views/main_view.dart'; +import 'package:tetra_stats/views/main_view_tiles.dart'; import 'package:tetra_stats/views/settings_view.dart'; import 'package:tetra_stats/views/tracked_players_view.dart'; import 'package:tetra_stats/views/calc_view.dart'; diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index 102dc89..2217ad6 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -5,17 +5,32 @@ import 'dart:convert'; import 'dart:developer' as developer; import 'dart:io'; import 'package:path_provider/path_provider.dart'; -import 'package:sqflite/sql.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; -import 'package:tetra_stats/data_objects/tetra_stats.dart'; +import 'package:tetra_stats/data_objects/cutoff_tetrio.dart'; +import 'package:tetra_stats/data_objects/end_context_multi.dart'; +import 'package:tetra_stats/data_objects/news.dart'; +import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart'; +import 'package:tetra_stats/data_objects/player_leaderboard_position.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/singleplayer_stream.dart'; +import 'package:tetra_stats/data_objects/summaries.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; +import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart'; +import 'package:tetra_stats/data_objects/tetra_league_alpha_stream.dart'; +import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart'; +import 'package:tetra_stats/data_objects/tetrio_player.dart'; +import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart'; +import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart'; +import 'package:tetra_stats/data_objects/tetrio_zen.dart'; +import 'package:tetra_stats/data_objects/user_records.dart'; import 'package:tetra_stats/main.dart' show packageInfo; import 'package:flutter/foundation.dart'; import 'package:tetra_stats/services/custom_http_client.dart'; import 'package:http/http.dart' as http; import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/services/sqlite_db_controller.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:csv/csv.dart'; const String dbName = "TetraStats.db"; diff --git a/lib/views/calc_view.dart b/lib/views/calc_view.dart index 45c7749..603e4d6 100644 --- a/lib/views/calc_view.dart +++ b/lib/views/calc_view.dart @@ -2,7 +2,9 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/widgets/graphs.dart'; import 'package:window_manager/window_manager.dart'; diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart index 333df80..208f9b4 100644 --- a/lib/views/compare_view.dart +++ b/lib/views/compare_view.dart @@ -5,7 +5,10 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/summaries.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_zen.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/utils/relative_timestamps.dart'; diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 9e52818..9a593a6 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -11,8 +11,25 @@ import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter/services.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; -import 'package:tetra_stats/data_objects/tetra_stats.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/beta_record.dart'; +import 'package:tetra_stats/data_objects/distinguishment.dart'; +import 'package:tetra_stats/data_objects/news.dart'; +import 'package:tetra_stats/data_objects/news_entry.dart'; +import 'package:tetra_stats/data_objects/player_leaderboard_position.dart'; +import 'package:tetra_stats/data_objects/record_extras.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/singleplayer_stream.dart'; +import 'package:tetra_stats/data_objects/summaries.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; +import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart'; +import 'package:tetra_stats/data_objects/tetra_league_alpha_stream.dart'; +import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart'; +import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_player.dart'; +import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart'; +import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart'; +import 'package:tetra_stats/data_objects/tetrio_zen.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show prefs, teto; import 'package:tetra_stats/services/crud_exceptions.dart'; @@ -338,7 +355,7 @@ class _MainState extends State with TickerProviderStateMixin { appBar: AppBar( title: _showSearchBar ? SearchBox(onSubmit: changePlayer, bigScreen: MediaQuery.of(context).size.width > 768) : Text(title, style: const TextStyle(shadows: textShadow)), backgroundColor: Colors.black, - actions: widget.player == null ? [ // search bar and PopupMenuButton hidden if player provided TODO: Subject to change + actions: widget.player == null ? [ // search bar and PopupMenuButton hidden if player provided _showSearchBar ? IconButton( onPressed: () { @@ -1555,7 +1572,7 @@ class _OtherThingy extends StatelessWidget { child: Column( children: [ Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended",fontSize: bigScreen ? 42 : 28)), - MarkdownBody(data: bio!, styleSheet: MarkdownStyleSheet(textScaleFactor: 1.5, textAlign: WrapAlignment.center)) // Text(bio!, style: const TextStyle(fontSize: 18)), + MarkdownBody(data: bio!, styleSheet: MarkdownStyleSheet(textScaler: TextScaler.linear(1.5), textAlign: WrapAlignment.center)) // Text(bio!, style: const TextStyle(fontSize: 18)), ], ), ), diff --git a/lib/views/main_view_tiles.dart b/lib/views/main_view_tiles.dart index c749d5b..37aa103 100644 --- a/lib/views/main_view_tiles.dart +++ b/lib/views/main_view_tiles.dart @@ -6,7 +6,23 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:intl/intl.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; -import 'package:tetra_stats/data_objects/tetra_stats.dart'; +import 'package:tetra_stats/data_objects/badge.dart'; +import 'package:tetra_stats/data_objects/beta_record.dart'; +import 'package:tetra_stats/data_objects/distinguishment.dart'; +import 'package:tetra_stats/data_objects/est_tr.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/news.dart'; +import 'package:tetra_stats/data_objects/news_entry.dart'; +import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; +import 'package:tetra_stats/data_objects/record_extras.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/singleplayer_stream.dart'; +import 'package:tetra_stats/data_objects/summaries.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; +import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_player.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/utils/colors_functions.dart'; @@ -20,9 +36,7 @@ import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/lineclears_thingy.dart'; import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart'; import 'package:tetra_stats/widgets/sp_trailing_stats.dart'; -import 'package:tetra_stats/widgets/stat_sell_num.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/widgets/tl_progress_bar.dart'; import 'package:tetra_stats/widgets/user_thingy.dart'; @@ -594,6 +608,35 @@ class RecordSummary extends StatelessWidget{ } +class LeagueCard extends StatelessWidget{ + final TetraLeague league; + final bool showSeasonNumber; + + const LeagueCard({super.key, required this.league, this.showSeasonNumber = false}); + + @override + Widget build(BuildContext context) { + return Card( + child: Padding( + padding: const EdgeInsets.fromLTRB(20.0, 8.0, 20.0, 12.0), + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(showSeasonNumber ? "Season ${league.season}" : "Tetra League", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, height: 0.9)), + const Divider(color: Color.fromARGB(50, 158, 158, 158)), + TLRatingThingy(userID: "", tlData: league, showPositions: true), + const Divider(color: Color.fromARGB(50, 158, 158, 158)), + Text("${league.apm != null ? f2.format(league.apm) : "-.--"} APM • ${league.pps != null ? f2.format(league.pps) : "-.--"} PPS • ${league.vs != null ? f2.format(league.vs) : "-.--"} VS • ${league.nerdStats != null ? f2.format(league.nerdStats!.app) : "-.--"} APP • ${league.nerdStats != null ? f2.format(league.nerdStats!.vsapm) : "-.--"} VS/APM", style: const TextStyle(color: Colors.grey)) + ], + ), + ), + ), + ); + } + +} + class _DestinationHomeState extends State { Cards rightCard = Cards.overview; CardMod cardMod = CardMod.info; @@ -645,23 +688,7 @@ class _DestinationHomeState extends State { ), ), ), - Card( - child: Padding( - padding: const EdgeInsets.fromLTRB(20.0, 8.0, 20.0, 12.0), - child: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Text("Tetra League", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, height: 0.9)), - const Divider(color: Color.fromARGB(50, 158, 158, 158)), - TLRatingThingy(userID: "", tlData: summaries.league, showPositions: true), - const Divider(color: Color.fromARGB(50, 158, 158, 158)), - Text("${summaries.league.apm != null ? f2.format(summaries.league.apm) : "-.--"} APM • ${summaries.league.pps != null ? f2.format(summaries.league.pps) : "-.--"} PPS • ${summaries.league.vs != null ? f2.format(summaries.league.vs) : "-.--"} VS • ${summaries.league.nerdStats != null ? f2.format(summaries.league.nerdStats!.app) : "-.--"} APP • ${summaries.league.nerdStats != null ? f2.format(summaries.league.nerdStats!.vsapm) : "-.--"} VS/APM", style: const TextStyle(color: Colors.grey)) - ], - ), - ), - ), - ), + LeagueCard(league: summaries.league), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -840,6 +867,7 @@ class _DestinationHomeState extends State { return Column( children: [ Card( + //surfaceTintColor: rankColors[data.rank], child: Padding( padding: const EdgeInsets.only(bottom: 4.0), child: Center( @@ -856,6 +884,7 @@ class _DestinationHomeState extends State { ), TetraLeagueThingy(league: data, cutoffs: cutoffs), if (data.nerdStats != null) Card( + //surfaceTintColor: rankColors[data.rank], child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -871,6 +900,31 @@ class _DestinationHomeState extends State { ); } + Widget getPreviousSeasonsList(Map pastLeague){ + return Column( + children: [ + Card( + child: Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text("Previous Seasons", style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)), + //Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center) + ], + ), + ), + ), + ), + for (var key in pastLeague.keys) Card( + child: LeagueCard(league: pastLeague[key]!, showSeasonNumber: true), + ) + ], + ); + } + Widget getListOfRecords(String recentStream, String topStream, BoxConstraints constraints){ return Column( children: [ @@ -1373,6 +1427,10 @@ class _DestinationHomeState extends State { value: CardMod.info, label: Text('Standing'), ), + const ButtonSegment( + value: CardMod.ex, // yeah i misusing my own Enum shut the fuck up + label: Text('Previous Seasons'), + ), const ButtonSegment( value: CardMod.records, label: Text('Recent Matches'), @@ -1436,10 +1494,10 @@ class _DestinationHomeState extends State { Column( mainAxisSize: MainAxisSize.min, children: [ - Text(t.errors.noSuchUser, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center), + Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Padding( padding: const EdgeInsets.only(top: 8.0), - child: Text(t.errors.noSuchUserSub, textAlign: TextAlign.center), + child: Text(snapshot.stackTrace.toString(), textAlign: TextAlign.center), ), ], ) @@ -1524,6 +1582,7 @@ class _DestinationHomeState extends State { Cards.overview => getOverviewCard(snapshot.data!.summaries!), Cards.tetraLeague => switch (cardMod){ CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs), + CardMod.ex => getPreviousSeasonsList(snapshot.data!.summaries!.pastLeague), CardMod.records => getRecentTLrecords(widget.constraints), _ => const Center(child: Text("huh?")) }, @@ -1532,7 +1591,6 @@ class _DestinationHomeState extends State { CardMod.records => getListOfRecords("zenith/recent", "zenith/top", widget.constraints), CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx), CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints), - _ => const Center(child: Text("huh?")) }, Cards.sprint => switch (cardMod){ CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank), @@ -2356,6 +2414,7 @@ class TetraLeagueThingy extends StatelessWidget{ @override Widget build(BuildContext context) { return Card( + //surfaceTintColor: rankColors[league.rank], child: Column( children: [ TLRatingThingy(userID: "w", tlData: league), diff --git a/lib/views/rank_averages_view.dart b/lib/views/rank_averages_view.dart index 14c6ad0..d9d4a42 100644 --- a/lib/views/rank_averages_view.dart +++ b/lib/views/rank_averages_view.dart @@ -3,7 +3,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; +import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart'; +import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/views/main_view.dart' show MainView; import 'package:window_manager/window_manager.dart'; diff --git a/lib/views/ranks_averages_view.dart b/lib/views/ranks_averages_view.dart index c2f6387..cd10535 100644 --- a/lib/views/ranks_averages_view.dart +++ b/lib/views/ranks_averages_view.dart @@ -1,7 +1,8 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/cutoff_tetrio.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/text_shadow.dart'; diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 1eb96c5..6734b14 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -1,6 +1,6 @@ import 'dart:io'; import 'package:go_router/go_router.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetrio_player.dart'; import 'package:tetra_stats/main.dart' show packageInfo, teto, prefs; import 'package:file_selector/file_selector.dart'; import 'package:file_picker/file_picker.dart'; diff --git a/lib/views/singleplayer_record_view.dart b/lib/views/singleplayer_record_view.dart index 2126c2f..0fe3bf0 100644 --- a/lib/views/singleplayer_record_view.dart +++ b/lib/views/singleplayer_record_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/widgets/singleplayer_record.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart'; diff --git a/lib/views/sprint_and_blitz_averages.dart b/lib/views/sprint_and_blitz_averages.dart index a37fbd9..9ac06ed 100644 --- a/lib/views/sprint_and_blitz_averages.dart +++ b/lib/views/sprint_and_blitz_averages.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/text_shadow.dart'; diff --git a/lib/views/state_view.dart b/lib/views/state_view.dart index b97f141..2e70d2f 100644 --- a/lib/views/state_view.dart +++ b/lib/views/state_view.dart @@ -2,11 +2,10 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:tetra_stats/widgets/tl_thingy.dart'; -import 'package:tetra_stats/widgets/user_thingy.dart'; import 'package:window_manager/window_manager.dart'; final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); @@ -41,13 +40,9 @@ class StateState extends State { super.dispose(); } - void _justUpdate() { - setState(() {}); - } - @override Widget build(BuildContext context) { - final t = Translations.of(context); + //final t = Translations.of(context); return Scaffold( appBar: AppBar( title: Text("State from ${timestamp(widget.state.timestamp)}"), diff --git a/lib/views/states_view.dart b/lib/views/states_view.dart index bf0fc5f..021adf9 100644 --- a/lib/views/states_view.dart +++ b/lib/views/states_view.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/views/tl_leaderboard_view.dart b/lib/views/tl_leaderboard_view.dart index d7699ad..47945e9 100644 --- a/lib/views/tl_leaderboard_view.dart +++ b/lib/views/tl_leaderboard_view.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/views/main_view.dart'; diff --git a/lib/views/tl_match_view.dart b/lib/views/tl_match_view.dart index fc4b50d..6b43db3 100644 --- a/lib/views/tl_match_view.dart +++ b/lib/views/tl_match_view.dart @@ -1,6 +1,9 @@ // ignore_for_file: use_build_context_synchronously, type_literal_in_constant_pattern import 'dart:io'; +import 'package:tetra_stats/data_objects/beta_league_round.dart'; +import 'package:tetra_stats/data_objects/beta_league_stats.dart'; +import 'package:tetra_stats/data_objects/beta_record.dart'; import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/views/compare_view.dart' show CompareThingy; @@ -10,7 +13,6 @@ import 'package:tetra_stats/widgets/vs_graphs.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/open_in_browser.dart'; import 'package:window_manager/window_manager.dart'; diff --git a/lib/views/tracked_players_view.dart b/lib/views/tracked_players_view.dart index 721bce4..b7816e5 100644 --- a/lib/views/tracked_players_view.dart +++ b/lib/views/tracked_players_view.dart @@ -2,12 +2,10 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/utils/filesizes_converter.dart'; import 'package:tetra_stats/views/states_view.dart'; -import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:window_manager/window_manager.dart'; late String oldWindowTitle; diff --git a/lib/views/zenith_record_view.dart b/lib/views/zenith_record_view.dart index b9f5c29..7169bf7 100644 --- a/lib/views/zenith_record_view.dart +++ b/lib/views/zenith_record_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:tetra_stats/widgets/zenith_thingy.dart'; diff --git a/lib/widgets/finesse_thingy.dart b/lib/widgets/finesse_thingy.dart index 937d767..c6600c2 100644 --- a/lib/widgets/finesse_thingy.dart +++ b/lib/widgets/finesse_thingy.dart @@ -1,7 +1,7 @@ // ignore_for_file: curly_braces_in_flow_control_structures import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/finesse.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/text_shadow.dart'; diff --git a/lib/widgets/gauget_num.dart b/lib/widgets/gauget_num.dart index 0f3bd6f..edfad86 100644 --- a/lib/widgets/gauget_num.dart +++ b/lib/widgets/gauget_num.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/leaderboard_position.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/widgets/graphs.dart b/lib/widgets/graphs.dart index 194496d..2e42f32 100644 --- a/lib/widgets/graphs.dart +++ b/lib/widgets/graphs.dart @@ -8,9 +8,11 @@ import 'package:fl_chart/src/chart/radar_chart/radar_chart_renderer.dart'; import 'package:fl_chart/src/chart/base/base_chart/base_chart_painter.dart'; import 'package:fl_chart/src/utils/canvas_wrapper.dart'; import 'package:fl_chart/src/utils/utils.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/main.dart' show prefs; import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/widgets/lineclears_thingy.dart b/lib/widgets/lineclears_thingy.dart index 78745db..cb739b8 100644 --- a/lib/widgets/lineclears_thingy.dart +++ b/lib/widgets/lineclears_thingy.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/clears.dart'; import 'package:tetra_stats/gen/strings.g.dart'; class LineclearsThingy extends StatelessWidget{ diff --git a/lib/widgets/recent_sp_games.dart b/lib/widgets/recent_sp_games.dart index e3e1b7a..92a2ff9 100644 --- a/lib/widgets/recent_sp_games.dart +++ b/lib/widgets/recent_sp_games.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/singleplayer_stream.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/text_shadow.dart'; diff --git a/lib/widgets/singleplayer_record.dart b/lib/widgets/singleplayer_record.dart index f717ca2..62bec0d 100644 --- a/lib/widgets/singleplayer_record.dart +++ b/lib/widgets/singleplayer_record.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; +import 'package:tetra_stats/data_objects/singleplayer_stream.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/widgets/sp_trailing_stats.dart b/lib/widgets/sp_trailing_stats.dart index fc679c6..b59f750 100644 --- a/lib/widgets/sp_trailing_stats.dart +++ b/lib/widgets/sp_trailing_stats.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart'; diff --git a/lib/widgets/stat_sell_num.dart b/lib/widgets/stat_sell_num.dart index f837bb4..c9c0165 100644 --- a/lib/widgets/stat_sell_num.dart +++ b/lib/widgets/stat_sell_num.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/leaderboard_position.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/widgets/tl_progress_bar.dart b/lib/widgets/tl_progress_bar.dart index bc8f94f..ed23430 100644 --- a/lib/widgets/tl_progress_bar.dart +++ b/lib/widgets/tl_progress_bar.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:tetra_stats/data_objects/glicko.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/widgets/tl_rating_thingy.dart b/lib/widgets/tl_rating_thingy.dart index ac7d4c3..1a3fbd0 100644 --- a/lib/widgets/tl_rating_thingy.dart +++ b/lib/widgets/tl_rating_thingy.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show prefs; import 'package:tetra_stats/utils/numers_formats.dart'; diff --git a/lib/widgets/tl_thingy.dart b/lib/widgets/tl_thingy.dart index 853adde..be40b7c 100644 --- a/lib/widgets/tl_thingy.dart +++ b/lib/widgets/tl_thingy.dart @@ -1,14 +1,11 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/player_leaderboard_position.dart'; +import 'package:tetra_stats/data_objects/tetra_league.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:tetra_stats/gen/strings.g.dart'; -import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; -import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/widgets/gauget_num.dart'; import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/stat_sell_num.dart'; @@ -80,8 +77,6 @@ class _TLThingyState extends State with TickerProviderStateMixin { return Column( children: [ if (widget.showTitle) Text(t.tetraLeague, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), - //if (DateTime.now().isBefore(seasonEnd)) Text(t.seasonEnds(countdown: countdown(seasonLeft))) - //else Text(t.seasonEnded), if (oldTl != null) Text(t.comparingWith(newDate: timestamp(currentTl.timestamp), oldDate: timestamp(oldTl!.timestamp)), textAlign: TextAlign.center,), if (oldTl != null) RangeSlider(values: _currentRangeValues, max: widget.states.length.toDouble(), @@ -95,7 +90,7 @@ class _TLThingyState extends State with TickerProviderStateMixin { if (values.start.round() == 0){ currentTl = widget.tl; }else{ - currentTl = sortedStates[values.start.round()-1]!; + currentTl = sortedStates[values.start.round()-1]; } if (values.end.round() == 0){ oldTl = widget.tl; @@ -207,7 +202,6 @@ class _TLThingyState extends State with TickerProviderStateMixin { oldPlayerStat: oldTl?.nerdStats?.appdsp,), StatCellNum(playerStat: currentTl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese, pos: widget.lbPositions?.cheese, - //averageStat: rankAverages?.nerdStats?.cheese, TODO: questonable alertWidgets: [Text(t.statCellNum.cheeseDescription), Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"), Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),], diff --git a/lib/widgets/user_thingy.dart b/lib/widgets/user_thingy.dart index f27e7a3..ee6dc92 100644 --- a/lib/widgets/user_thingy.dart +++ b/lib/widgets/user_thingy.dart @@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/tetrio_player.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/views/compare_view.dart'; diff --git a/lib/widgets/vs_graphs.dart b/lib/widgets/vs_graphs.dart index 0b78adc..9dce22d 100644 --- a/lib/widgets/vs_graphs.dart +++ b/lib/widgets/vs_graphs.dart @@ -1,7 +1,9 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; +import 'package:tetra_stats/data_objects/nerd_stats.dart'; +import 'package:tetra_stats/data_objects/playstyle.dart'; +import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/widgets/graphs.dart' show MyRadarChart; -import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; class VsGraphs extends StatelessWidget{ diff --git a/lib/widgets/zenith_thingy.dart b/lib/widgets/zenith_thingy.dart index a5a43f3..d1954d0 100644 --- a/lib/widgets/zenith_thingy.dart +++ b/lib/widgets/zenith_thingy.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; -import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/data_objects/record_extras.dart'; +import 'package:tetra_stats/data_objects/record_single.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart';