Optimized data storing and history saving

This commit is contained in:
dan63047 2023-07-18 20:53:43 +03:00
parent 501832c9aa
commit 248b708276
2 changed files with 88 additions and 77 deletions

View File

@ -31,7 +31,8 @@ const Map<String, double> rankCutoffs = {
"c": 0.9,
"c-": 0.95,
"d+": 0.975,
"d": 1
"d": 1,
"z": -1
};
const Map<String, Color> rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:418
'x': Color(0xFFFF45FF),
@ -85,7 +86,7 @@ class TetrioPlayer {
late bool verified;
bool? badstanding;
String? botmaster;
late Connections connections;
Connections? connections;
late TetraLeagueAlpha tlSeason1;
List<RecordSingle?> sprint = [];
List<RecordSingle?> blitz = [];
@ -122,34 +123,30 @@ class TetrioPlayer {
double get level => pow((xp / 500), 0.6) + (xp / (5000 + (max(0, xp - 4 * pow(10, 6)) / 5000))) + 1;
TetrioPlayer.fromJson(Map<String, dynamic> json, DateTime stateTime) {
TetrioPlayer.fromJson(Map<String, dynamic> json, DateTime stateTime, String id, String nick) {
//developer.log("TetrioPlayer.fromJson $stateTime: $json", name: "data_objects/tetrio");
userId = json['_id'];
username = json['username'];
userId = id;
username = nick;
state = stateTime;
if (json['role'] == "retrived from p1nkl0bst3r api"){ //i fucked my own db lol i remove it later
role = "p1nkl0bst3r";
}else{
role = json['role'];
}
registrationTime = json['ts'] != null ? DateTime.parse(json['ts']) : null;
if (json['badges'] != null) {
json['badges'].forEach((v) {
badges.add(Badge.fromJson(v));
});
}
xp = json['xp'].toDouble();
gamesPlayed = json['gamesplayed'];
gamesWon = json['gameswon'];
gameTime = doubleSecondsToDuration(json['gametime'].toDouble());
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'];
verified = json['verified'];
supporterTier = json['supporter_tier'] ?? 0;
verified = json['verified'] ?? false;
tlSeason1 = TetraLeagueAlpha.fromJson(json['league'], stateTime);
avatarRevision = json['avatar_revision'];
bannerRevision = json['banner_revision'];
bio = json['bio'];
connections = Connections.fromJson(json['connections']);
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'];
@ -158,25 +155,25 @@ class TetrioPlayer {
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = userId;
data['username'] = username;
// data['_id'] = userId;
// data['username'] = username;
data['role'] = role;
if (registrationTime != null) data['ts'] = registrationTime?.toString();
data['badges'] = badges.map((v) => v.toJson()).toList();
data['xp'] = xp;
data['gamesplayed'] = gamesPlayed;
data['gameswon'] = gamesWon;
data['gametime'] = gameTime.inMicroseconds / 1000000;
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;
data['supporter_tier'] = supporterTier;
data['verified'] = verified;
if (supporterTier > 0) data['supporter_tier'] = supporterTier;
if (verified) data['verified'] = verified;
data['league'] = tlSeason1.toJson();
if (distinguishment != null) data['distinguishment'] = distinguishment?.toJson();
if (avatarRevision != null) data['avatar_revision'] = avatarRevision;
if (bannerRevision != null) data['banner_revision'] = bannerRevision;
if (data['bio'] != null) data['bio'] = bio;
data['connections'] = connections.toJson();
data['friend_count'] = friendCount;
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");
@ -741,7 +738,7 @@ class TetraLeagueAlpha {
this.pps,
this.vs,
this.records}){
nerdStats = (apm != null && pps != null && apm != null) ? NerdStats(apm!, pps!, vs!) : null;
nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null;
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, (rd != null) ? rd! : 69, 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;
}
@ -750,29 +747,28 @@ class TetraLeagueAlpha {
TetraLeagueAlpha.fromJson(Map<String, dynamic> json, ts) {
timestamp = ts;
gamesPlayed = json['gamesplayed'];
gamesWon = json['gameswon'];
rating = json['rating'].toDouble();
gamesPlayed = json['gamesplayed'] ?? 0;
gamesWon = json['gameswon'] ?? 0;
rating = json['rating'] != null ? json['rating'].toDouble() : -1;
glicko = json['glicko']?.toDouble();
rd = json['rd']?.toDouble();
rank = json['rank'];
bestRank = json['bestrank'].toString();
apm = json['apm']?.toDouble();
pps = json['pps']?.toDouble();
vs = json['vs']?.toDouble();
decaying = json['decaying'];
standing = json['standing'];
percentile = json['percentile'].toDouble();
standingLocal = json['standing_local'];
rd = json['rd'] != null ? json['rd']!.toDouble() : noTrRd;
rank = json['rank'] != null ? json['rank']!.toString() : 'z';
bestRank = json['bestrank'] != null ? json['bestrank']!.toString() : 'z';
apm = json['apm'] != null ? json['apm']!.toDouble() : null;
pps = json['pps'] != null ? json['pps']!.toDouble() : null;
vs = json['vs'] != null ? json['vs']!.toDouble() : null;
decaying = 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'];
prevAt = json['prev_at'] ?? -1;
nextRank = json['next_rank'];
nextAt = json['next_at'];
percentileRank = json['percentile_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!, (rd != null) ? rd! : 69, 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;
playstyle = (nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null;
}
@override
@ -784,25 +780,25 @@ class TetraLeagueAlpha {
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['gamesplayed'] = gamesPlayed;
data['gameswon'] = gamesWon;
data['rating'] = rating;
if (gamesPlayed > 0) data['gamesplayed'] = gamesPlayed;
if (gamesWon > 0) data['gameswon'] = gamesWon;
if (rating >= 0) data['rating'] = rating;
if (glicko != null) data['glicko'] = glicko;
if (rd != null) data['rd'] = rd;
data['rank'] = rank;
data['bestrank'] = bestRank;
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;
data['decaying'] = decaying;
data['standing'] = standing;
data['percentile'] = percentile;
data['standing_local'] = standingLocal;
if (decaying) data['decaying'] = decaying;
if (standing >= 0) data['standing'] = standing;
if (!rankCutoffs.containsValue(percentile)) data['percentile'] = percentile;
if (standingLocal >= 0) data['standing_local'] = standingLocal;
if (prevRank != null) data['prev_rank'] = prevRank;
data['prev_at'] = prevAt;
if (prevAt >= 0) data['prev_at'] = prevAt;
if (nextRank != null) data['next_rank'] = nextRank;
data['next_at'] = nextAt;
data['percentile_rank'] = percentileRank;
if (nextAt >= 0) data['next_at'] = nextAt;
if (percentileRank != rank) data['percentile_rank'] = percentileRank;
return data;
}
}

View File

@ -117,15 +117,30 @@ class TetrioService extends DB {
xp: -1,
supporterTier: 0,
verified: false,
connections: Connections(),
tlSeason1: TetraLeagueAlpha(timestamp: DateTime.parse(entry[9]), apm: entry[6], pps: entry[7], vs: entry[8], glicko: entry[4], rd: noTrRd, gamesPlayed: entry[1], gamesWon: entry[2], bestRank: "z", decaying: false, rating: entry[3], rank: entry[5], percentileRank: entry[5], percentile: rankCutoffs[entry[5]]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1),
connections: null,
tlSeason1: TetraLeagueAlpha(timestamp: DateTime.parse(entry[9]), apm: entry[6] != '' ? entry[6] : null, pps: entry[7] != '' ? entry[7] : null, vs: entry[8] != '' ? entry[8] : null, glicko: entry[4], rd: noTrRd, gamesPlayed: entry[1], gamesWon: entry[2], bestRank: "z", decaying: false, rating: entry[3], rank: entry[5], percentileRank: entry[5], percentile: rankCutoffs[entry[5]]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1),
sprint: [],
blitz: []
);
history.add(state);
// _players.addEntries({state.userId: [state]}.entries);
await storeState(state, isFromHistory: true);
}
ensureDbIsOpen();
final db = getDatabaseOrThrow();
late List<TetrioPlayer> states;
try{
states = _players[id]!;
}catch(e){
var player = await fetchPlayer(id);
await createPlayer(player);
states = _players[id]!;
}
states.insertAll(0, history.reversed);
final Map<String, dynamic> statesJson = {};
for (var e in states) {
statesJson.addEntries({(e.state.millisecondsSinceEpoch ~/ 1000).toString(): e.toJson()}.entries);
}
await db.update(tetrioUsersTable, {idCol: id, nickCol: nick, statesCol: jsonEncode(statesJson)}, where: '$idCol = ?', whereArgs: [id]);
_tetrioStreamController.add(_players);
return history;
}
else {
@ -270,7 +285,7 @@ class TetrioService extends DB {
if (results.isNotEmpty) {
throw TetrioPlayerAlreadyExist();
}
final Map<String, dynamic> statesJson = {tetrioPlayer.state.millisecondsSinceEpoch.toString(): tetrioPlayer.toJson()};
final Map<String, dynamic> statesJson = {(tetrioPlayer.state.millisecondsSinceEpoch ~/ 1000).toString(): tetrioPlayer.toJson()};
db.insert(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)});
_players.addEntries({
tetrioPlayer.userId: [tetrioPlayer]
@ -319,7 +334,7 @@ class TetrioService extends DB {
}
}
Future<void> storeState(TetrioPlayer tetrioPlayer, {bool isFromHistory = false}) async {
Future<void> storeState(TetrioPlayer tetrioPlayer) async {
ensureDbIsOpen();
final db = getDatabaseOrThrow();
late List<TetrioPlayer> states;
@ -330,15 +345,15 @@ class TetrioService extends DB {
await createPlayer(tetrioPlayer);
states = await getPlayer(tetrioPlayer.userId);
}
bool test = isFromHistory ? _players[tetrioPlayer.userId]!.last.checkForRetrivedHistory(tetrioPlayer) : _players[tetrioPlayer.userId]!.last.isSameState(tetrioPlayer);
if (test == false) isFromHistory ? states.insert(0, tetrioPlayer) : states.add(tetrioPlayer);
bool test = _players[tetrioPlayer.userId]!.last.isSameState(tetrioPlayer);
if (test == false) states.add(tetrioPlayer);
final Map<String, dynamic> statesJson = {};
for (var e in states) {
statesJson.addEntries({e.state.millisecondsSinceEpoch.toString(): e.toJson()}.entries);
statesJson.addEntries({(e.state.millisecondsSinceEpoch ~/ 1000).toString(): e.toJson()}.entries);
}
await db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
isFromHistory ? _players[tetrioPlayer.userId]!.insert(0, tetrioPlayer) : _players[tetrioPlayer.userId]!.add(tetrioPlayer);
_players[tetrioPlayer.userId]!.add(tetrioPlayer);
_tetrioStreamController.add(_players);
}
@ -369,7 +384,7 @@ class TetrioService extends DB {
} else {
dynamic rawStates = results.first['jsonStates'] as String;
rawStates = json.decode(rawStates);
rawStates.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k)))));
rawStates.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), id, results.first[nickCol] as String)));
_players.removeWhere((key, value) => key == id);
_players.addEntries({states.last.userId: states}.entries);
_tetrioStreamController.add(_players);
@ -395,9 +410,9 @@ class TetrioService extends DB {
final response = await http.get(url);
if (response.statusCode == 200) {
if (jsonDecode(response.body)['success']) {
TetrioPlayer player = TetrioPlayer.fromJson(
jsonDecode(response.body)['data']['user'], DateTime.fromMillisecondsSinceEpoch(jsonDecode(response.body)['cache']['cached_at'], isUtc: true));
var json = jsonDecode(response.body);
if (json['success']) {
TetrioPlayer player = TetrioPlayer.fromJson(json['data']['user'], DateTime.fromMillisecondsSinceEpoch(json['cache']['cached_at'], isUtc: true), json['data']['user']['_id'], json['data']['user']['username']);
developer.log("fetchPlayer: $user retrieved and cached", name: "services/tetrio_crud");
_playersCache[jsonDecode(response.body)['cache']['cached_until'].toString()] = player;
return player;
@ -421,7 +436,7 @@ class TetrioService extends DB {
// what the fuck am i doing here?
var test = json.decode(row['jsonStates'] as String);
List<TetrioPlayer> states = [];
test.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k)))));
test.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), row[idCol] as String, row[nickCol] as String)));
data.addEntries({states.last.userId: states}.entries);
return data;
});