From 232aa71e751f6531b35daf5d243424ce62ee41e8 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Mon, 17 Jun 2024 23:55:01 +0300 Subject: [PATCH 01/14] It's time to continue on freyhoe analysis --- lib/data_objects/freyhoe_test.dart | 41 +- .../tetrio_multiplayer_replay.dart | 762 +++++++++--------- 2 files changed, 421 insertions(+), 382 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 5275e86..441a020 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -1,25 +1,26 @@ -//import 'dart:convert'; -//import 'dart:io'; +import 'dart:convert'; +import 'dart:io'; -//import 'package:path_provider/path_provider.dart'; +import 'package:path_provider/path_provider.dart'; -//import 'tetrio_multiplayer_replay.dart'; +import 'tetrio_multiplayer_replay.dart'; -/// That thing allows me to test my new staff i'm trying to implement -//void main() async { - // List queue = List.from(tetrominoes); - // TetrioRNG rng = TetrioRNG(0); - // queue = rng.shuffleList(queue); - // print(queue); - // queue = List.from(tetrominoes); - // queue = rng.shuffleList(queue); - // print(queue); +// That thing allows me to test my new staff i'm trying to implement +void main() async { + List queue = List.from(tetrominoes); + TetrioRNG rng = TetrioRNG(0); + queue = rng.shuffleList(queue); + print(queue); + queue = List.from(tetrominoes); + queue = rng.shuffleList(queue); + print(queue); - // var downloadPath = await getDownloadsDirectory(); - // ReplayData replay = ReplayData.fromJson(jsonDecode(File("${downloadPath!.path}/65b504a9ade6d287b8427af0").readAsStringSync())); - // List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; - // print(replay.rawJson); + var downloadPath = await getDownloadsDirectory(); + var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); + ReplayData replay = ReplayData.fromJson(replayJson); + List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; + //print(replay.rawJson); - //print(""); -// exit(0); -//} \ No newline at end of file + print(""); + exit(0); +} \ 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 9e5ecbd..081f062 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -1,6 +1,8 @@ import 'dart:math'; import 'dart:typed_data'; +import 'package:vector_math/vector_math_64.dart'; + import 'tetrio.dart'; // I want to implement those fancy TWC stats @@ -269,399 +271,435 @@ class ReplayData{ // can't belive i have to implement that difficult shit -// List readEventList(Map json){ -// List events = []; -// int id = 0; -// for (var event in json['data'][0]['replays'][0]['events']){ -// int frame = event["frame"]; -// EventType type = EventType.values.byName(event['type']); -// switch (type) { -// case EventType.start: -// events.add(Event(id, frame, type)); -// break; -// case EventType.full: -// events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); -// break; -// case EventType.targets: -// // TODO -// break; -// case EventType.keydown: -// events.add(EventKeyPress(id, frame, type, -// Keypress( -// KeyType.values.byName(event['data']['key']), -// event['data']['subframe'], -// false) -// )); -// break; -// case EventType.keyup: -// events.add(EventKeyPress(id, frame, type, -// Keypress( -// KeyType.values.byName(event['data']['key']), -// event['data']['subframe'], -// true) -// )); -// break; -// case EventType.end: -// // TODO: Handle this case. -// case EventType.ige: -// // TODO: Handle this case. -// case EventType.exit: -// // TODO: Handle this case. -// } -// id++; -// } -// return []; -// } +List readEventList(Map json){ + List events = []; + int id = 0; + for (var event in json['data'][0]['replays'][0]['events']){ + int frame = event["frame"]; + EventType type = EventType.values.byName(event['type']); + switch (type) { + case EventType.start: + events.add(Event(id, frame, type)); + break; + case EventType.full: + events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); + break; + case EventType.targets: + events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); + break; + case EventType.keydown: + events.add(EventKeyPress(id, frame, type, + Keypress( + KeyType.values.byName(event['data']['key']), + event['data']['subframe'], + false) + )); + break; + case EventType.keyup: + events.add(EventKeyPress(id, frame, type, + Keypress( + KeyType.values.byName(event['data']['key']), + event['data']['subframe'], + true) + )); + break; + case EventType.end: + event.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); + break; + case EventType.ige: + // TODO: Handle this case. + case EventType.exit: + events.add(Event(id, frame, type)); + } + id++; + } + return []; +} -// enum EventType -// { -// start, -// end, -// full, -// keydown, -// keyup, -// targets, -// ige, -// exit -// } +enum EventType +{ + start, + end, + full, + keydown, + keyup, + targets, + ige, + exit +} -// enum KeyType -// { -// moveLeft, -// moveRight, -// softDrop, -// rotateCCW, -// rotateCW, -// rotate180, -// hardDrop, -// hold, -// chat, -// exit, -// retry -// } +enum KeyType +{ + moveLeft, + moveRight, + softDrop, + rotateCCW, + rotateCW, + rotate180, + hardDrop, + hold, + chat, + exit, + retry +} -// class Event{ -// int id; -// int frame; -// EventType type; -// //dynamic data; +class Event{ + int id; + int frame; + EventType type; + //dynamic data; -// Event(this.id, this.frame, this.type); + Event(this.id, this.frame, this.type); -// @override -// String toString(){ -// return "E#$id f#$frame: $type"; -// } -// } + @override + String toString(){ + return "E#$id f#$frame: $type"; + } +} -// class Keypress{ -// KeyType key; -// double subframe; -// bool released; +class Keypress{ + KeyType key; + double subframe; + bool released; -// Keypress(this.key, this.subframe, this.released); -// } + Keypress(this.key, this.subframe, this.released); +} -// class EventKeyPress extends Event{ -// Keypress data; +class EventKeyPress extends Event{ + Keypress data; -// EventKeyPress(super.id, super.frame, super.type, this.data); -// } + EventKeyPress(super.id, super.frame, super.type, this.data); +} -// class IGE{ -// int id; -// int frame; -// String type; -// int amount; +class Targets{ + String? id; + int? frame; + String? type; + List? data; -// IGE(this.id, this.frame, this.type, this.amount); -// } + Targets(this.id, this.frame, this.type, this.data); -// class EventIGE extends Event{ -// IGE data; + Targets.fromJson(Map json){ + id = json["id"]; + frame = json["frame"]; + type = json["type"]; + data = json["data"]; + } +} -// EventIGE(super.id, super.frame, super.type, this.data); -// } +class EventTargets extends Event{ + Targets data; -// class Hold -// { -// String? piece; -// bool locked; + EventTargets(super.id, super.frame, super.type, this.data); +} -// Hold(this.piece, this.locked); -// } +class IGE{ + int id; + int frame; + String type; + int amount; -// class DataFullOptions{ -// int? version; -// bool? seedRandom; -// int? seed; -// double? g; -// int? stock; -// int? gMargin; -// double? gIncrease; -// double? garbageMultiplier; -// int? garbageMargin; -// double? garbageIncrease; -// int? garbageCap; -// double? garbageCapIncrease; -// int? garbageCapMax; -// int? garbageHoleSize; -// String? garbageBlocking; // TODO: enum -// bool? hasGarbage; -// int? locktime; -// int? garbageSpeed; -// int? forfeitTime; -// int? are; -// int? areLineclear; -// bool? infiniteMovement; -// int? lockresets; -// bool? allow180; -// bool? btbChaining; -// bool? allclears; -// bool? clutch; -// bool? noLockout; -// String? passthrough; -// int? boardwidth; -// int? boardheight; -// Handling? handling; -// int? boardbuffer; + IGE(this.id, this.frame, this.type, this.amount); +} -// DataFullOptions.fromJson(Map json){ -// version = json["version"]; -// seedRandom = json["seed_random"]; -// seed = json["seed"]; -// g = json["g"]; -// stock = json["stock"]; -// gMargin = json["gmargin"]; -// gIncrease = json["gincrease"]; -// garbageMultiplier = json["garbagemultiplier"]; -// garbageCapIncrease = json["garbagecapincrease"]; -// garbageCapMax = json["garbagecapmax"]; -// garbageHoleSize = json["garbageholesize"]; -// garbageBlocking = json["garbageblocking"]; -// hasGarbage = json["hasgarbage"]; -// locktime = json["locktime"]; -// garbageSpeed = json["garbagespeed"]; -// forfeitTime = json["forfeit_time"]; -// are = json["are"]; -// areLineclear = json["lineclear_are"]; -// infiniteMovement = json["infinitemovement"]; -// lockresets = json["lockresets"]; -// allow180 = json["allow180"]; -// btbChaining = json["b2bchaining"]; -// allclears = json["allclears"]; -// clutch = json["clutch"]; -// noLockout = json["nolockout"]; -// passthrough = json["passthrough"]; -// boardwidth = json["boardwidth"]; -// boardheight = json["boardheight"]; -// handling = Handling.fromJson(json["handling"]); -// boardbuffer = json["boardbuffer"]; -// } -// } +class EventIGE extends Event{ + IGE data; -// class DataFullStats -// { -// double? seed; -// int? lines; -// int? levelLines; -// int? levelLinesNeeded; -// int? inputs; -// int? holds; -// int? score; -// int? zenLevel; -// int? zenProgress; -// int? level; -// int? combo; -// int? currentComboPower; -// int? topCombo; -// int? btb; -// int? topbtb; -// int? tspins; -// int? piecesPlaced; -// Clears? clears; -// Garbage? garbage; -// int? kills; -// Finesse? finesse; + EventIGE(super.id, super.frame, super.type, this.data); +} -// DataFullStats.fromJson(Map json){ -// seed = json["seed"]; -// lines = json["lines"]; -// levelLines = json["level_lines"]; -// levelLinesNeeded = json["level_lines_needed"]; -// inputs = json["inputs"]; -// holds = json["holds"]; -// score = json["score"]; -// zenLevel = json["zenlevel"]; -// zenProgress = json["zenprogress"]; -// level = json["level"]; -// combo = json["combo"]; -// currentComboPower = json["currentcombopower"]; -// topCombo = json["topcombo"]; -// btb = json["btb"]; -// topbtb = json["topbtb"]; -// tspins = json["tspins"]; -// piecesPlaced = json["piecesplaced"]; -// clears = Clears.fromJson(json["clears"]); -// garbage = Garbage.fromJson(json["garbage"]); -// kills = json["kills"]; -// finesse = Finesse.fromJson(json["finesse"]); -// } -// } +class EndData { + String reason; + DataFull export; -// class DataFullGame -// { -// List>? board; -// List? bag; -// double? g; -// bool? playing; -// Hold? hold; -// String? piece; -// Handling? handling; + EndData(this.reason, this.export); +} -// DataFullGame.fromJson(Map json){ -// board = json["board"]; -// bag = json["bag"]; -// hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); -// g = json["g"]; -// handling = Handling.fromJson(json["handling"]); -// } -// } +class EventEnd extends Event{ + EndData data; -// class DataFull{ -// bool? successful; -// String? gameOverReason; -// int? fire; -// DataFullOptions? options; -// DataFullStats? stats; -// DataFullGame? game; + EventEnd(super.id, super.frame, super.type, this.data); +} -// DataFull.fromJson(Map json){ -// successful = json["successful"]; -// gameOverReason = json["gameoverreason"]; -// fire = json["fire"]; -// options = DataFullOptions.fromJson(json["options"]); -// stats = DataFullStats.fromJson(json["stats"]); -// game = DataFullGame.fromJson(json["game"]); -// } -// } +class Hold +{ + String? piece; + bool locked; -// class EventFull extends Event{ -// DataFull data; + Hold(this.piece, this.locked); +} -// EventFull(super.id, super.frame, super.type, this.data); -// } +class DataFullOptions{ + int? version; + bool? seedRandom; + int? seed; + double? g; + int? stock; + int? gMargin; + double? gIncrease; + double? garbageMultiplier; + int? garbageMargin; + double? garbageIncrease; + int? garbageCap; + double? garbageCapIncrease; + int? garbageCapMax; + int? garbageHoleSize; + String? garbageBlocking; // TODO: enum + bool? hasGarbage; + int? locktime; + int? garbageSpeed; + int? forfeitTime; + int? are; + int? areLineclear; + bool? infiniteMovement; + int? lockresets; + bool? allow180; + bool? btbChaining; + bool? allclears; + bool? clutch; + bool? noLockout; + String? passthrough; + int? boardwidth; + int? boardheight; + Handling? handling; + int? boardbuffer; -// class TetrioRNG{ -// late double _t; + DataFullOptions.fromJson(Map json){ + version = json["version"]; + seedRandom = json["seed_random"]; + seed = json["seed"]; + g = json["g"]; + stock = json["stock"]; + gMargin = json["gmargin"]; + gIncrease = json["gincrease"]; + garbageMultiplier = json["garbagemultiplier"]; + garbageCapIncrease = json["garbagecapincrease"]; + garbageCapMax = json["garbagecapmax"]; + garbageHoleSize = json["garbageholesize"]; + garbageBlocking = json["garbageblocking"]; + hasGarbage = json["hasgarbage"]; + locktime = json["locktime"]; + garbageSpeed = json["garbagespeed"]; + forfeitTime = json["forfeit_time"]; + are = json["are"]; + areLineclear = json["lineclear_are"]; + infiniteMovement = json["infinitemovement"]; + lockresets = json["lockresets"]; + allow180 = json["allow180"]; + btbChaining = json["b2bchaining"]; + allclears = json["allclears"]; + clutch = json["clutch"]; + noLockout = json["nolockout"]; + passthrough = json["passthrough"]; + boardwidth = json["boardwidth"]; + boardheight = json["boardheight"]; + handling = Handling.fromJson(json["handling"]); + boardbuffer = json["boardbuffer"]; + } +} -// TetrioRNG(int seed){ -// _t = seed % 2147483647; -// if (_t <= 0) _t += 2147483646; -// } +class DataFullStats + { + double? seed; + int? lines; + int? levelLines; + int? levelLinesNeeded; + int? inputs; + int? holds; + int? score; + int? zenLevel; + int? zenProgress; + int? level; + int? combo; + int? currentComboPower; + int? topCombo; + int? btb; + int? topbtb; + int? tspins; + int? piecesPlaced; + Clears? clears; + Garbage? garbage; + int? kills; + Finesse? finesse; -// int next(){ -// _t = 16807 * _t % 2147483647; -// return _t.toInt(); -// } + DataFullStats.fromJson(Map json){ + seed = json["seed"]; + lines = json["lines"]; + levelLines = json["level_lines"]; + levelLinesNeeded = json["level_lines_needed"]; + inputs = json["inputs"]; + holds = json["holds"]; + score = json["score"]; + zenLevel = json["zenlevel"]; + zenProgress = json["zenprogress"]; + level = json["level"]; + combo = json["combo"]; + currentComboPower = json["currentcombopower"]; + topCombo = json["topcombo"]; + btb = json["btb"]; + topbtb = json["topbtb"]; + tspins = json["tspins"]; + piecesPlaced = json["piecesplaced"]; + clears = Clears.fromJson(json["clears"]); + garbage = Garbage.fromJson(json["garbage"]); + kills = json["kills"]; + finesse = Finesse.fromJson(json["finesse"]); + } + } -// double nextFloat(){ -// return (next() - 1) / 2147483646; -// } +class DataFullGame + { + List>? board; + List? bag; + double? g; + bool? playing; + Hold? hold; + String? piece; + Handling? handling; -// List shuffleList(List array){ -// int length = array.length; -// if (length == 0) return []; + DataFullGame.fromJson(Map json){ + board = json["board"]; + bag = json["bag"]; + hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); + g = json["g"]; + handling = Handling.fromJson(json["handling"]); + } + } -// for (; --length > 0;){ -// int swapIndex = ((nextFloat()) * (length + 1)).toInt(); -// Tetromino tmp = array[length]; -// array[length] = array[swapIndex]; -// array[swapIndex] = tmp; -// } -// return array; -// } -// } +class DataFull{ + bool? successful; + String? gameOverReason; + int? fire; + DataFullOptions? options; + DataFullStats? stats; + DataFullGame? game; -// enum Tetromino{ -// Z, -// L, -// O, -// S, -// I, -// J, -// T, -// garbage, -// empty -// } + DataFull.fromJson(Map json){ + successful = json["successful"]; + gameOverReason = json["gameoverreason"]; + fire = json["fire"]; + options = DataFullOptions.fromJson(json["options"]); + stats = DataFullStats.fromJson(json["stats"]); + game = DataFullGame.fromJson(json["game"]); + } +} -// List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; -// List>> shapes = [ -// [ // Z -// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], -// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] -// ], -// [ // L -// [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] -// ], -// [ // O -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] -// ], -// [ // S -// [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], -// [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], -// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] -// ], -// [ // I -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], -// [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], -// [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] -// ], -// [ // J -// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] -// ], -// [ // T -// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], -// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] -// ] -// ]; -// List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; +class EventFull extends Event{ + DataFull data; -// const Map garbage = { -// "single": 0, -// "double": 1, -// "triple": 2, -// "quad": 4, -// "penta": 5, -// "t-spin": 0, -// "t-spin single": 2, -// "t-spin double": 4, -// "t-spin triple": 6, -// "t-spin quad": 10, -// "t-spin penta": 12, -// "t-spin mini": 0, -// "t-spin mini single": 0, -// "t-spin mini double": 1, -// "allclear": 10 -// }; -// int btbBonus = 1; -// double btbLog = 0.8; -// double comboBonus = 0.25; -// int comboMinifier = 1; -// double comboMinifierLog = 1.25; -// List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; + EventFull(super.id, super.frame, super.type, this.data); +} + +class TetrioRNG{ + late double _t; + + TetrioRNG(int seed){ + _t = seed % 2147483647; + if (_t <= 0) _t += 2147483646; + } + + int next(){ + _t = 16807 * _t % 2147483647; + return _t.toInt(); + } + + double nextFloat(){ + return (next() - 1) / 2147483646; + } + + List shuffleList(List array){ + int length = array.length; + if (length == 0) return []; + + for (; --length > 0;){ + int swapIndex = ((nextFloat()) * (length + 1)).toInt(); + Tetromino tmp = array[length]; + array[length] = array[swapIndex]; + array[swapIndex] = tmp; + } + return array; + } +} + +enum Tetromino{ + Z, + L, + O, + S, + I, + J, + T, + garbage, + empty +} + +List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; +List>> shapes = [ + [ // Z + [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], + [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], + [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] + ], + [ // L + [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], + [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], + [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] + ], + [ // O + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] + ], + [ // S + [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], + [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], + [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] + ], + [ // I + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], + [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], + [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], + [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] + ], + [ // J + [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], + [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], + [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] + ], + [ // T + [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], + [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], + [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] + ] +]; +List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; + +const Map garbage = { + "single": 0, + "double": 1, + "triple": 2, + "quad": 4, + "penta": 5, + "t-spin": 0, + "t-spin single": 2, + "t-spin double": 4, + "t-spin triple": 6, + "t-spin quad": 10, + "t-spin penta": 12, + "t-spin mini": 0, + "t-spin mini single": 0, + "t-spin mini double": 1, + "allclear": 10 +}; +int btbBonus = 1; +double btbLog = 0.8; +double comboBonus = 0.25; +int comboMinifier = 1; +double comboMinifierLog = 1.25; +List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; From 1824e353c3c9bd205783c8bb94e3ea0451c70e8c Mon Sep 17 00:00:00 2001 From: dan63047 Date: Tue, 18 Jun 2024 23:20:42 +0300 Subject: [PATCH 02/14] Can read events, but ige events are pain in the ass --- lib/data_objects/freyhoe_test.dart | 24 ++--- .../tetrio_multiplayer_replay.dart | 97 ++++++++++++++++--- lib/widgets/tl_thingy.dart | 4 +- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 441a020..ded335e 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -7,20 +7,20 @@ import 'tetrio_multiplayer_replay.dart'; // That thing allows me to test my new staff i'm trying to implement void main() async { - List queue = List.from(tetrominoes); - TetrioRNG rng = TetrioRNG(0); - queue = rng.shuffleList(queue); - print(queue); - queue = List.from(tetrominoes); - queue = rng.shuffleList(queue); - print(queue); + // List queue = List.from(tetrominoes); + // TetrioRNG rng = TetrioRNG(0); + // queue = rng.shuffleList(queue); + // print(queue); + // queue = List.from(tetrominoes); + // queue = rng.shuffleList(queue); + // print(queue); - var downloadPath = await getDownloadsDirectory(); + //var downloadPath = await getDownloadsDirectory(); var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); ReplayData replay = ReplayData.fromJson(replayJson); - List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; - //print(replay.rawJson); - - print(""); + //List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; + List events = readEventList(replay.rawJson); + events.retainWhere((element) => element.type == EventType.ige); + print((events[1] as EventIGE).data.data); exit(0); } \ 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 081f062..b277964 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -304,16 +304,24 @@ List readEventList(Map json){ )); break; case EventType.end: - event.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); + events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); break; case EventType.ige: - // TODO: Handle this case. + events.add(EventIGE(id, frame, type, IGE( + event['data']['id'], + event['data']['frame'], + event['data']['type'], + event['data']['data'] + )) + ); + break; case EventType.exit: events.add(Event(id, frame, type)); + break; } id++; } - return []; + return events; } enum EventType @@ -359,10 +367,12 @@ class Event{ class Keypress{ KeyType key; - double subframe; + late double subframe; bool released; - Keypress(this.key, this.subframe, this.released); + Keypress(this.key, num sframe, this.released){ + subframe = sframe.toDouble(); + } } class EventKeyPress extends Event{ @@ -393,13 +403,76 @@ class EventTargets extends Event{ EventTargets(super.id, super.frame, super.type, this.data); } +class IGEdata{ + +} + +enum GarbageStatus +{ + sleeping, + caution, + spawn, + danger +} + +// class GarbageData{ +// int id; +// int iid; +// int ackiid; +// String username; +// String type; +// bool active; +// GarbageStatus status; +// int delay; +// bool queued; +// int amt; +// int x; +// int y; +// int size; +// int column; +// int cid; +// bool firstcycle; +// int gid; + +// GarbageData.fromJson(Map data){ +// id; +// iid; +// ackiid; +// username; +// type; +// active; +// status; +// delay; +// queued; +// amt; +// x; +// y; +// size; +// column; +// cid; +// firstcycle; +// gid; +// } +// } + +// class IGEdataTarget extends { +// String type; +// List targets; +// int frame; + +// String gameid +// GarbageData? data; +// //compatibility for v15 targets event +// String? sender_id; +// } + class IGE{ int id; int frame; String type; - int amount; + Map data; - IGE(this.id, this.frame, this.type, this.amount); + IGE(this.id, this.frame, this.type, this.data); } class EventIGE extends Event{ @@ -472,8 +545,8 @@ class DataFullOptions{ stock = json["stock"]; gMargin = json["gmargin"]; gIncrease = json["gincrease"]; - garbageMultiplier = json["garbagemultiplier"]; - garbageCapIncrease = json["garbagecapincrease"]; + garbageMultiplier = json["garbagemultiplier"].toDouble(); + garbageCapIncrease = json["garbagecapincrease"].toDouble(); garbageCapMax = json["garbagecapmax"]; garbageHoleSize = json["garbageholesize"]; garbageBlocking = json["garbageblocking"]; @@ -500,7 +573,7 @@ class DataFullOptions{ class DataFullStats { - double? seed; + int? seed; int? lines; int? levelLines; int? levelLinesNeeded; @@ -549,8 +622,8 @@ class DataFullStats class DataFullGame { - List>? board; - List? bag; + List? board; + List? bag; double? g; bool? playing; Hold? hold; diff --git a/lib/widgets/tl_thingy.dart b/lib/widgets/tl_thingy.dart index d22333e..71f674e 100644 --- a/lib/widgets/tl_thingy.dart +++ b/lib/widgets/tl_thingy.dart @@ -57,8 +57,8 @@ class _TLThingyState extends State { Widget build(BuildContext context) { final t = Translations.of(context); String decimalSeparator = f2.symbols.DECIMAL_SEP; - List estTRformated = f2.format(currentTl.estTr!.esttr).split(decimalSeparator); - List estTRaccFormated = intFDiff.format(currentTl.esttracc!).split("."); + List estTRformated = currentTl.estTr != null ? f2.format(currentTl.estTr!.esttr).split(decimalSeparator) : []; + List estTRaccFormated = currentTl.esttracc != null ? intFDiff.format(currentTl.esttracc!).split(".") : []; if (currentTl.gamesPlayed == 0) return Center(child: Text(widget.guest ? t.anonTL : widget.bot ? t.botTL : t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28), textAlign: TextAlign.center,)); return LayoutBuilder(builder: (context, constraints) { bool bigScreen = constraints.maxWidth >= 768; From 9096c423ceb9d41ff2e91fd812222bfd6ca59994 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Wed, 19 Jun 2024 16:11:20 +0300 Subject: [PATCH 03/14] i have to quickly resolve the situation --- lib/data_objects/freyhoe_test.dart | 44 +- .../tetrio_multiplayer_replay.dart | 934 +++++++++--------- lib/services/tetrio_crud.dart | 9 +- 3 files changed, 499 insertions(+), 488 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index ded335e..ee91554 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -1,26 +1,26 @@ -import 'dart:convert'; -import 'dart:io'; +// import 'dart:convert'; +// import 'dart:io'; -import 'package:path_provider/path_provider.dart'; +// import 'package:path_provider/path_provider.dart'; -import 'tetrio_multiplayer_replay.dart'; +// import 'tetrio_multiplayer_replay.dart'; -// That thing allows me to test my new staff i'm trying to implement -void main() async { - // List queue = List.from(tetrominoes); - // TetrioRNG rng = TetrioRNG(0); - // queue = rng.shuffleList(queue); - // print(queue); - // queue = List.from(tetrominoes); - // queue = rng.shuffleList(queue); - // print(queue); +// // That thing allows me to test my new staff i'm trying to implement +// void main() async { +// // List queue = List.from(tetrominoes); +// // TetrioRNG rng = TetrioRNG(0); +// // queue = rng.shuffleList(queue); +// // print(queue); +// // queue = List.from(tetrominoes); +// // queue = rng.shuffleList(queue); +// // print(queue); - //var downloadPath = await getDownloadsDirectory(); - var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); - ReplayData replay = ReplayData.fromJson(replayJson); - //List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; - List events = readEventList(replay.rawJson); - events.retainWhere((element) => element.type == EventType.ige); - print((events[1] as EventIGE).data.data); - exit(0); -} \ No newline at end of file +// //var downloadPath = await getDownloadsDirectory(); +// var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); +// ReplayData replay = ReplayData.fromJson(replayJson); +// //List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; +// List events = readEventList(replay.rawJson); +// events.retainWhere((element) => element.type == EventType.ige); +// print((events[1] as EventIGE).data.data); +// exit(0); +// } \ 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 b277964..0ad4786 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -271,508 +271,516 @@ class ReplayData{ // can't belive i have to implement that difficult shit -List readEventList(Map json){ - List events = []; - int id = 0; - for (var event in json['data'][0]['replays'][0]['events']){ - int frame = event["frame"]; - EventType type = EventType.values.byName(event['type']); - switch (type) { - case EventType.start: - events.add(Event(id, frame, type)); - break; - case EventType.full: - events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); - break; - case EventType.targets: - events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); - break; - case EventType.keydown: - events.add(EventKeyPress(id, frame, type, - Keypress( - KeyType.values.byName(event['data']['key']), - event['data']['subframe'], - false) - )); - break; - case EventType.keyup: - events.add(EventKeyPress(id, frame, type, - Keypress( - KeyType.values.byName(event['data']['key']), - event['data']['subframe'], - true) - )); - break; - case EventType.end: - events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); - break; - case EventType.ige: - events.add(EventIGE(id, frame, type, IGE( - event['data']['id'], - event['data']['frame'], - event['data']['type'], - event['data']['data'] - )) - ); - break; - case EventType.exit: - events.add(Event(id, frame, type)); - break; - } - id++; - } - return events; -} +// List readEventList(Map json){ +// List events = []; +// int id = 0; +// for (var event in json['data'][0]['replays'][0]['events']){ +// int frame = event["frame"]; +// EventType type = EventType.values.byName(event['type']); +// switch (type) { +// case EventType.start: +// events.add(Event(id, frame, type)); +// break; +// case EventType.full: +// events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); +// break; +// case EventType.targets: +// events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); +// break; +// case EventType.keydown: +// events.add(EventKeyPress(id, frame, type, +// Keypress( +// KeyType.values.byName(event['data']['key']), +// event['data']['subframe'], +// false) +// )); +// break; +// case EventType.keyup: +// events.add(EventKeyPress(id, frame, type, +// Keypress( +// KeyType.values.byName(event['data']['key']), +// event['data']['subframe'], +// true) +// )); +// break; +// case EventType.end: +// events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); +// break; +// case EventType.ige: +// events.add(EventIGE(id, frame, type, IGE( +// event['data']['id'], +// event['data']['frame'], +// event['data']['type'], +// event['data']['data'] +// )) +// ); +// break; +// case EventType.exit: +// events.add(Event(id, frame, type)); +// break; +// } +// id++; +// } +// return events; +// } -enum EventType -{ - start, - end, - full, - keydown, - keyup, - targets, - ige, - exit -} +// enum EventType +// { +// start, +// end, +// full, +// keydown, +// keyup, +// targets, +// ige, +// exit +// } -enum KeyType -{ - moveLeft, - moveRight, - softDrop, - rotateCCW, - rotateCW, - rotate180, - hardDrop, - hold, - chat, - exit, - retry -} +// enum KeyType +// { +// moveLeft, +// moveRight, +// softDrop, +// rotateCCW, +// rotateCW, +// rotate180, +// hardDrop, +// hold, +// chat, +// exit, +// retry +// } -class Event{ - int id; - int frame; - EventType type; - //dynamic data; - - Event(this.id, this.frame, this.type); - - @override - String toString(){ - return "E#$id f#$frame: $type"; - } -} - -class Keypress{ - KeyType key; - late double subframe; - bool released; - - Keypress(this.key, num sframe, this.released){ - subframe = sframe.toDouble(); - } -} - -class EventKeyPress extends Event{ - Keypress data; - - EventKeyPress(super.id, super.frame, super.type, this.data); -} - -class Targets{ - String? id; - int? frame; - String? type; - List? data; - - Targets(this.id, this.frame, this.type, this.data); - - Targets.fromJson(Map json){ - id = json["id"]; - frame = json["frame"]; - type = json["type"]; - data = json["data"]; - } -} - -class EventTargets extends Event{ - Targets data; - - EventTargets(super.id, super.frame, super.type, this.data); -} - -class IGEdata{ - -} - -enum GarbageStatus -{ - sleeping, - caution, - spawn, - danger -} - -// class GarbageData{ +// class Event{ // int id; -// int iid; -// int ackiid; -// String username; -// String type; -// bool active; -// GarbageStatus status; -// int delay; -// bool queued; -// int amt; -// int x; -// int y; -// int size; -// int column; -// int cid; -// bool firstcycle; -// int gid; +// int frame; +// EventType type; +// //dynamic data; -// GarbageData.fromJson(Map data){ -// id; -// iid; -// ackiid; -// username; -// type; -// active; -// status; -// delay; -// queued; -// amt; -// x; -// y; -// size; -// column; -// cid; -// firstcycle; -// gid; +// Event(this.id, this.frame, this.type); + +// @override +// String toString(){ +// return "E#$id f#$frame: $type"; // } // } -// class IGEdataTarget extends { -// String type; -// List targets; -// int frame; +// class Keypress{ +// KeyType key; +// late double subframe; +// bool released; + +// Keypress(this.key, num sframe, this.released){ +// subframe = sframe.toDouble(); +// } +// } + +// class EventKeyPress extends Event{ +// Keypress data; + +// EventKeyPress(super.id, super.frame, super.type, this.data); +// } + +// class Targets{ +// String? id; +// int? frame; +// String? type; +// List? data; + +// Targets(this.id, this.frame, this.type, this.data); + +// Targets.fromJson(Map json){ +// id = json["id"]; +// frame = json["frame"]; +// type = json["type"]; +// data = json["data"]; +// } +// } + +// class EventTargets extends Event{ +// Targets data; + +// EventTargets(super.id, super.frame, super.type, this.data); +// } + +// class IGEdata{ + +// } + +// enum GarbageStatus +// { +// sleeping, +// caution, +// spawn, +// danger +// } + +// class GarbageData{ +// int? id; +// late int iid; +// late int ackiid; +// String? username; +// late String type; +// bool? active; +// GarbageStatus? status; +// int? delay; +// bool? queued; +// late int amt; +// late int x; +// late int y; +// int? size; +// late int column; +// int? cid; +// bool? firstcycle; +// int? gid; + +// GarbageData.fromJson(Map data){ +// id = data['id']; +// iid = data['iid']; +// ackiid = data['ackiid']; +// username = data['username']; +// type = data['type']; +// active = data['active']; +// status = data['status'] != null ? GarbageStatus.values[data['status']] : null; +// delay = data['delay']; +// queued = data['queued']; +// amt = data['amt']; +// x = data['x']; +// y = data['y']; +// size = data['size']; +// column = data['column']; +// cid = data['cid']; +// firstcycle = data['firstcycle']; +// gid = data['gid']; +// } +// } + +// class IGEdataTarget extends IGEdata{ +// late String type; +// late List targets; +// late int frame; -// String gameid +// late String gameid; // GarbageData? data; // //compatibility for v15 targets event // String? sender_id; + +// IGEdataTarget.fromJson(Map d){ +// type = d['type']; +// targets = d['targets']; +// frame = d['targets']; +// gameid = d['gameid']; +// data = GarbageData.fromJson(d['data']); +// } // } -class IGE{ - int id; - int frame; - String type; - Map data; +// class IGE{ +// int id; +// int frame; +// String type; +// Map data; - IGE(this.id, this.frame, this.type, this.data); -} +// IGE(this.id, this.frame, this.type, this.data); +// } -class EventIGE extends Event{ - IGE data; +// class EventIGE extends Event{ +// IGE data; - EventIGE(super.id, super.frame, super.type, this.data); -} +// EventIGE(super.id, super.frame, super.type, this.data); +// } -class EndData { - String reason; - DataFull export; +// class EndData { +// String reason; +// DataFull export; - EndData(this.reason, this.export); -} +// EndData(this.reason, this.export); +// } -class EventEnd extends Event{ - EndData data; +// class EventEnd extends Event{ +// EndData data; - EventEnd(super.id, super.frame, super.type, this.data); -} +// EventEnd(super.id, super.frame, super.type, this.data); +// } -class Hold -{ - String? piece; - bool locked; +// class Hold +// { +// String? piece; +// bool locked; - Hold(this.piece, this.locked); -} +// Hold(this.piece, this.locked); +// } -class DataFullOptions{ - int? version; - bool? seedRandom; - int? seed; - double? g; - int? stock; - int? gMargin; - double? gIncrease; - double? garbageMultiplier; - int? garbageMargin; - double? garbageIncrease; - int? garbageCap; - double? garbageCapIncrease; - int? garbageCapMax; - int? garbageHoleSize; - String? garbageBlocking; // TODO: enum - bool? hasGarbage; - int? locktime; - int? garbageSpeed; - int? forfeitTime; - int? are; - int? areLineclear; - bool? infiniteMovement; - int? lockresets; - bool? allow180; - bool? btbChaining; - bool? allclears; - bool? clutch; - bool? noLockout; - String? passthrough; - int? boardwidth; - int? boardheight; - Handling? handling; - int? boardbuffer; +// class DataFullOptions{ +// int? version; +// bool? seedRandom; +// int? seed; +// double? g; +// int? stock; +// int? gMargin; +// double? gIncrease; +// double? garbageMultiplier; +// int? garbageMargin; +// double? garbageIncrease; +// int? garbageCap; +// double? garbageCapIncrease; +// int? garbageCapMax; +// int? garbageHoleSize; +// String? garbageBlocking; // TODO: enum +// bool? hasGarbage; +// int? locktime; +// int? garbageSpeed; +// int? forfeitTime; +// int? are; +// int? areLineclear; +// bool? infiniteMovement; +// int? lockresets; +// bool? allow180; +// bool? btbChaining; +// bool? allclears; +// bool? clutch; +// bool? noLockout; +// String? passthrough; +// int? boardwidth; +// int? boardheight; +// Handling? handling; +// int? boardbuffer; - DataFullOptions.fromJson(Map json){ - version = json["version"]; - seedRandom = json["seed_random"]; - seed = json["seed"]; - g = json["g"]; - stock = json["stock"]; - gMargin = json["gmargin"]; - gIncrease = json["gincrease"]; - garbageMultiplier = json["garbagemultiplier"].toDouble(); - garbageCapIncrease = json["garbagecapincrease"].toDouble(); - garbageCapMax = json["garbagecapmax"]; - garbageHoleSize = json["garbageholesize"]; - garbageBlocking = json["garbageblocking"]; - hasGarbage = json["hasgarbage"]; - locktime = json["locktime"]; - garbageSpeed = json["garbagespeed"]; - forfeitTime = json["forfeit_time"]; - are = json["are"]; - areLineclear = json["lineclear_are"]; - infiniteMovement = json["infinitemovement"]; - lockresets = json["lockresets"]; - allow180 = json["allow180"]; - btbChaining = json["b2bchaining"]; - allclears = json["allclears"]; - clutch = json["clutch"]; - noLockout = json["nolockout"]; - passthrough = json["passthrough"]; - boardwidth = json["boardwidth"]; - boardheight = json["boardheight"]; - handling = Handling.fromJson(json["handling"]); - boardbuffer = json["boardbuffer"]; - } -} +// DataFullOptions.fromJson(Map json){ +// version = json["version"]; +// seedRandom = json["seed_random"]; +// seed = json["seed"]; +// g = json["g"]; +// stock = json["stock"]; +// gMargin = json["gmargin"]; +// gIncrease = json["gincrease"]; +// garbageMultiplier = json["garbagemultiplier"].toDouble(); +// garbageCapIncrease = json["garbagecapincrease"].toDouble(); +// garbageCapMax = json["garbagecapmax"]; +// garbageHoleSize = json["garbageholesize"]; +// garbageBlocking = json["garbageblocking"]; +// hasGarbage = json["hasgarbage"]; +// locktime = json["locktime"]; +// garbageSpeed = json["garbagespeed"]; +// forfeitTime = json["forfeit_time"]; +// are = json["are"]; +// areLineclear = json["lineclear_are"]; +// infiniteMovement = json["infinitemovement"]; +// lockresets = json["lockresets"]; +// allow180 = json["allow180"]; +// btbChaining = json["b2bchaining"]; +// allclears = json["allclears"]; +// clutch = json["clutch"]; +// noLockout = json["nolockout"]; +// passthrough = json["passthrough"]; +// boardwidth = json["boardwidth"]; +// boardheight = json["boardheight"]; +// handling = Handling.fromJson(json["handling"]); +// boardbuffer = json["boardbuffer"]; +// } +// } -class DataFullStats - { - int? seed; - int? lines; - int? levelLines; - int? levelLinesNeeded; - int? inputs; - int? holds; - int? score; - int? zenLevel; - int? zenProgress; - int? level; - int? combo; - int? currentComboPower; - int? topCombo; - int? btb; - int? topbtb; - int? tspins; - int? piecesPlaced; - Clears? clears; - Garbage? garbage; - int? kills; - Finesse? finesse; +// class DataFullStats +// { +// int? seed; +// int? lines; +// int? levelLines; +// int? levelLinesNeeded; +// int? inputs; +// int? holds; +// int? score; +// int? zenLevel; +// int? zenProgress; +// int? level; +// int? combo; +// int? currentComboPower; +// int? topCombo; +// int? btb; +// int? topbtb; +// int? tspins; +// int? piecesPlaced; +// Clears? clears; +// Garbage? garbage; +// int? kills; +// Finesse? finesse; - DataFullStats.fromJson(Map json){ - seed = json["seed"]; - lines = json["lines"]; - levelLines = json["level_lines"]; - levelLinesNeeded = json["level_lines_needed"]; - inputs = json["inputs"]; - holds = json["holds"]; - score = json["score"]; - zenLevel = json["zenlevel"]; - zenProgress = json["zenprogress"]; - level = json["level"]; - combo = json["combo"]; - currentComboPower = json["currentcombopower"]; - topCombo = json["topcombo"]; - btb = json["btb"]; - topbtb = json["topbtb"]; - tspins = json["tspins"]; - piecesPlaced = json["piecesplaced"]; - clears = Clears.fromJson(json["clears"]); - garbage = Garbage.fromJson(json["garbage"]); - kills = json["kills"]; - finesse = Finesse.fromJson(json["finesse"]); - } - } +// DataFullStats.fromJson(Map json){ +// seed = json["seed"]; +// lines = json["lines"]; +// levelLines = json["level_lines"]; +// levelLinesNeeded = json["level_lines_needed"]; +// inputs = json["inputs"]; +// holds = json["holds"]; +// score = json["score"]; +// zenLevel = json["zenlevel"]; +// zenProgress = json["zenprogress"]; +// level = json["level"]; +// combo = json["combo"]; +// currentComboPower = json["currentcombopower"]; +// topCombo = json["topcombo"]; +// btb = json["btb"]; +// topbtb = json["topbtb"]; +// tspins = json["tspins"]; +// piecesPlaced = json["piecesplaced"]; +// clears = Clears.fromJson(json["clears"]); +// garbage = Garbage.fromJson(json["garbage"]); +// kills = json["kills"]; +// finesse = Finesse.fromJson(json["finesse"]); +// } +// } -class DataFullGame - { - List? board; - List? bag; - double? g; - bool? playing; - Hold? hold; - String? piece; - Handling? handling; +// class DataFullGame +// { +// List? board; +// List? bag; +// double? g; +// bool? playing; +// Hold? hold; +// String? piece; +// Handling? handling; - DataFullGame.fromJson(Map json){ - board = json["board"]; - bag = json["bag"]; - hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); - g = json["g"]; - handling = Handling.fromJson(json["handling"]); - } - } +// DataFullGame.fromJson(Map json){ +// board = json["board"]; +// bag = json["bag"]; +// hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); +// g = json["g"]; +// handling = Handling.fromJson(json["handling"]); +// } +// } -class DataFull{ - bool? successful; - String? gameOverReason; - int? fire; - DataFullOptions? options; - DataFullStats? stats; - DataFullGame? game; +// class DataFull{ +// bool? successful; +// String? gameOverReason; +// int? fire; +// DataFullOptions? options; +// DataFullStats? stats; +// DataFullGame? game; - DataFull.fromJson(Map json){ - successful = json["successful"]; - gameOverReason = json["gameoverreason"]; - fire = json["fire"]; - options = DataFullOptions.fromJson(json["options"]); - stats = DataFullStats.fromJson(json["stats"]); - game = DataFullGame.fromJson(json["game"]); - } -} +// DataFull.fromJson(Map json){ +// successful = json["successful"]; +// gameOverReason = json["gameoverreason"]; +// fire = json["fire"]; +// options = DataFullOptions.fromJson(json["options"]); +// stats = DataFullStats.fromJson(json["stats"]); +// game = DataFullGame.fromJson(json["game"]); +// } +// } -class EventFull extends Event{ - DataFull data; +// class EventFull extends Event{ +// DataFull data; - EventFull(super.id, super.frame, super.type, this.data); -} +// EventFull(super.id, super.frame, super.type, this.data); +// } -class TetrioRNG{ - late double _t; +// class TetrioRNG{ +// late double _t; - TetrioRNG(int seed){ - _t = seed % 2147483647; - if (_t <= 0) _t += 2147483646; - } +// TetrioRNG(int seed){ +// _t = seed % 2147483647; +// if (_t <= 0) _t += 2147483646; +// } - int next(){ - _t = 16807 * _t % 2147483647; - return _t.toInt(); - } +// int next(){ +// _t = 16807 * _t % 2147483647; +// return _t.toInt(); +// } - double nextFloat(){ - return (next() - 1) / 2147483646; - } +// double nextFloat(){ +// return (next() - 1) / 2147483646; +// } - List shuffleList(List array){ - int length = array.length; - if (length == 0) return []; +// List shuffleList(List array){ +// int length = array.length; +// if (length == 0) return []; - for (; --length > 0;){ - int swapIndex = ((nextFloat()) * (length + 1)).toInt(); - Tetromino tmp = array[length]; - array[length] = array[swapIndex]; - array[swapIndex] = tmp; - } - return array; - } -} +// for (; --length > 0;){ +// int swapIndex = ((nextFloat()) * (length + 1)).toInt(); +// Tetromino tmp = array[length]; +// array[length] = array[swapIndex]; +// array[swapIndex] = tmp; +// } +// return array; +// } +// } -enum Tetromino{ - Z, - L, - O, - S, - I, - J, - T, - garbage, - empty -} +// enum Tetromino{ +// Z, +// L, +// O, +// S, +// I, +// J, +// T, +// garbage, +// empty +// } -List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; -List>> shapes = [ - [ // Z - [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], - [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] - ], - [ // L - [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], - [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] - ], - [ // O - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] - ], - [ // S - [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], - [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], - [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] - ], - [ // I - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], - [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], - [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], - [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] - ], - [ // J - [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], - [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] - ], - [ // T - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] - ] -]; -List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; +// List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; +// List>> shapes = [ +// [ // Z +// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], +// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] +// ], +// [ // L +// [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] +// ], +// [ // O +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] +// ], +// [ // S +// [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], +// [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], +// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] +// ], +// [ // I +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], +// [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], +// [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] +// ], +// [ // J +// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] +// ], +// [ // T +// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], +// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] +// ] +// ]; +// List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; -const Map garbage = { - "single": 0, - "double": 1, - "triple": 2, - "quad": 4, - "penta": 5, - "t-spin": 0, - "t-spin single": 2, - "t-spin double": 4, - "t-spin triple": 6, - "t-spin quad": 10, - "t-spin penta": 12, - "t-spin mini": 0, - "t-spin mini single": 0, - "t-spin mini double": 1, - "allclear": 10 -}; -int btbBonus = 1; -double btbLog = 0.8; -double comboBonus = 0.25; -int comboMinifier = 1; -double comboMinifierLog = 1.25; -List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; +// const Map garbage = { +// "single": 0, +// "double": 1, +// "triple": 2, +// "quad": 4, +// "penta": 5, +// "t-spin": 0, +// "t-spin single": 2, +// "t-spin double": 4, +// "t-spin triple": 6, +// "t-spin quad": 10, +// "t-spin penta": 12, +// "t-spin mini": 0, +// "t-spin mini single": 0, +// "t-spin mini double": 1, +// "allclear": 10 +// }; +// int btbBonus = 1; +// double btbLog = 0.8; +// double comboBonus = 0.25; +// int comboMinifier = 1; +// double comboMinifierLog = 1.25; +// List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index 3911cd5..df67f3d 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -379,7 +379,6 @@ class TetrioService extends DB { TopTr result = TopTr(id, null); developer.log("fetchTopTR: Probably, player doesn't have top TR", name: "services/tetrio_crud", error: response.statusCode); _cache.store(result, DateTime.now().millisecondsSinceEpoch + 300000); - //_topTRcache[(DateTime.now().millisecondsSinceEpoch + 300000).toString()] = {id: null}; return result; // if not 200 or 404 - throw a unique for each code exception case 403: @@ -392,7 +391,10 @@ class TetrioService extends DB { case 502: case 503: case 504: - throw P1nkl0bst3rInternalProblem(); + TopTr result = TopTr(id, null); + developer.log("fetchTopTR: API returned ${response.statusCode}", name: "services/tetrio_crud", error: response.statusCode); + //_cache.store(result, DateTime.now().millisecondsSinceEpoch + 300000); + return result; default: developer.log("fetchTopTR: Failed to fetch top TR", name: "services/tetrio_crud", error: response.statusCode); throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason"); @@ -445,7 +447,8 @@ class TetrioService extends DB { case 502: case 503: case 504: - throw P1nkl0bst3rInternalProblem(); + developer.log("fetchCutoffs: Cutoffs are unavalable (${response.statusCode})", name: "services/tetrio_crud", error: response.statusCode); + return null; default: developer.log("fetchCutoffs: Failed to fetch top Cutoffs", name: "services/tetrio_crud", error: response.statusCode); throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason"); From f42fcfc5f60c025507f9f504a6974acb2ca7a323 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Thu, 20 Jun 2024 23:58:11 +0300 Subject: [PATCH 04/14] god that ige melts my brain --- lib/data_objects/freyhoe_test.dart | 44 +- .../tetrio_multiplayer_replay.dart | 974 +++++++++--------- 2 files changed, 528 insertions(+), 490 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index ee91554..29435e8 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -1,26 +1,26 @@ -// import 'dart:convert'; -// import 'dart:io'; +import 'dart:convert'; +import 'dart:io'; -// import 'package:path_provider/path_provider.dart'; +import 'package:path_provider/path_provider.dart'; -// import 'tetrio_multiplayer_replay.dart'; +import 'tetrio_multiplayer_replay.dart'; -// // That thing allows me to test my new staff i'm trying to implement -// void main() async { -// // List queue = List.from(tetrominoes); -// // TetrioRNG rng = TetrioRNG(0); -// // queue = rng.shuffleList(queue); -// // print(queue); -// // queue = List.from(tetrominoes); -// // queue = rng.shuffleList(queue); -// // print(queue); +// That thing allows me to test my new staff i'm trying to implement +void main() async { + // List queue = List.from(tetrominoes); + // TetrioRNG rng = TetrioRNG(0); + // queue = rng.shuffleList(queue); + // print(queue); + // queue = List.from(tetrominoes); + // queue = rng.shuffleList(queue); + // print(queue); -// //var downloadPath = await getDownloadsDirectory(); -// var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); -// ReplayData replay = ReplayData.fromJson(replayJson); -// //List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; -// List events = readEventList(replay.rawJson); -// events.retainWhere((element) => element.type == EventType.ige); -// print((events[1] as EventIGE).data.data); -// exit(0); -// } \ No newline at end of file + //var downloadPath = await getDownloadsDirectory(); + var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); + ReplayData replay = ReplayData.fromJson(replayJson); + //List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; + List events = readEventList(replay.rawJson); + //events.retainWhere((element) => element.runtimeType == EventIGE && (element as EventIGE).data.data['type'] == "interaction_confirm"); + print(events); + exit(0); +} \ 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 0ad4786..648727e 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -18,14 +18,14 @@ int biggestSpikeFromReplay(events){ spikeCounter = event['data']['data']['data']['amt']; biggestSpike = spikeCounter; }else{ - if (event['data']['data']['frame'] - previousIGEeventFrame < 60){ + if ((event['data']['data']['frame']??event['data']['frame']) - previousIGEeventFrame < 60){ spikeCounter = spikeCounter + event['data']['data']['data']['amt'] as int; }else{ spikeCounter = event['data']['data']['data']['amt']; } biggestSpike = max(biggestSpike, spikeCounter); } - previousIGEeventFrame = event['data']['data']['frame']; + previousIGEeventFrame = event['data']['data']['frame']??event['data']['frame']; } } return biggestSpike; @@ -218,8 +218,8 @@ class ReplayData{ List KPSmultipliedByWeights = [0, 0]; totalStats = [ReplayStats.createEmpty(), ReplayStats.createEmpty()]; for(var round in json['data']) { - int firstInEndContext = round['replays'][0]["events"].last['data']['export']['options']['gameid'].startsWith(endcontext[0].userId) ? 0 : 1; - int secondInEndContext = round['replays'][1]["events"].last['data']['export']['options']['gameid'].startsWith(endcontext[1].userId) ? 1 : 0; + int firstInEndContext = round['replays'][0]["events"].last['data']['export']['options']['username'].startsWith(endcontext[0].username) ? 0 : 1; + int secondInEndContext = round['replays'][1]["events"].last['data']['export']['options']['username'].startsWith(endcontext[1].username) ? 1 : 0; int roundLength = max(round['replays'][0]['frames'], round['replays'][1]['frames']); roundLengths.add(roundLength); totalLength = totalLength + max(round['replays'][0]['frames'], round['replays'][1]['frames']); @@ -230,7 +230,7 @@ class ReplayData{ VSmultipliedByWeights[0] += endcontext[0].extraTracking[roundID]*roundLength; VSmultipliedByWeights[1] += endcontext[1].extraTracking[roundID]*roundLength; int winner = round['board'].indexWhere((element) => element['success'] == true); - roundWinners.add([round['board'][winner]['id'], round['board'][winner]['username']]); + roundWinners.add([round['board'][winner]['id']??round['board'][winner]['user']['_id'], round['board'][winner]['username']??round['board'][winner]['user']['username']]); ReplayStats playerOne = ReplayStats.fromJson(round['replays'][firstInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][secondInEndContext]['events']), round['replays'][firstInEndContext]['frames']); // (events contain recived attacks) ReplayStats playerTwo = ReplayStats.fromJson(round['replays'][secondInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][firstInEndContext]['events']), round['replays'][secondInEndContext]['frames']); SPPmultipliedByWeights[0] += playerOne.spp*roundLength; @@ -271,516 +271,554 @@ class ReplayData{ // can't belive i have to implement that difficult shit -// List readEventList(Map json){ -// List events = []; -// int id = 0; -// for (var event in json['data'][0]['replays'][0]['events']){ -// int frame = event["frame"]; -// EventType type = EventType.values.byName(event['type']); -// switch (type) { -// case EventType.start: -// events.add(Event(id, frame, type)); -// break; -// case EventType.full: -// events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); -// break; -// case EventType.targets: -// events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); -// break; -// case EventType.keydown: -// events.add(EventKeyPress(id, frame, type, -// Keypress( -// KeyType.values.byName(event['data']['key']), -// event['data']['subframe'], -// false) -// )); -// break; -// case EventType.keyup: -// events.add(EventKeyPress(id, frame, type, -// Keypress( -// KeyType.values.byName(event['data']['key']), -// event['data']['subframe'], -// true) -// )); -// break; -// case EventType.end: -// events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); -// break; -// case EventType.ige: -// events.add(EventIGE(id, frame, type, IGE( -// event['data']['id'], -// event['data']['frame'], -// event['data']['type'], -// event['data']['data'] -// )) -// ); -// break; -// case EventType.exit: -// events.add(Event(id, frame, type)); -// break; -// } -// id++; -// } -// return events; -// } +List readEventList(Map json){ + List events = []; + int id = 0; + for (var event in json['data'][0]['replays'][0]['events']){ + int frame = event["frame"]; + EventType type = EventType.values.byName(event['type']); + switch (type) { + case EventType.start: + events.add(Event(id, frame, type)); + break; + case EventType.full: + events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); + break; + case EventType.targets: + events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); + break; + case EventType.keydown: + events.add(EventKeyPress(id, frame, type, + Keypress( + KeyType.values.byName(event['data']['key']), + event['data']['subframe'], + false) + )); + break; + case EventType.keyup: + events.add(EventKeyPress(id, frame, type, + Keypress( + KeyType.values.byName(event['data']['key']), + event['data']['subframe'], + true) + )); + break; + case EventType.end: + events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); + break; + case EventType.ige: + events.add(EventIGE(id, frame, type, IGE( + event['data']['id'], + event['data']['frame'], + event['data']['type'], + event['data']['data'] + )) + ); + break; + case EventType.exit: + events.add(Event(id, frame, type)); + break; + } + id++; + } + return events; +} -// enum EventType -// { -// start, -// end, -// full, -// keydown, -// keyup, -// targets, -// ige, -// exit -// } +enum EventType +{ + start, + end, + full, + keydown, + keyup, + targets, + ige, + exit +} -// enum KeyType -// { -// moveLeft, -// moveRight, -// softDrop, -// rotateCCW, -// rotateCW, -// rotate180, -// hardDrop, -// hold, -// chat, -// exit, -// retry -// } +enum KeyType +{ + moveLeft, + moveRight, + softDrop, + rotateCCW, + rotateCW, + rotate180, + hardDrop, + hold, + chat, + exit, + retry +} -// class Event{ -// int id; -// int frame; -// EventType type; -// //dynamic data; +class Event{ + int id; + int frame; + EventType type; + //dynamic data; -// Event(this.id, this.frame, this.type); + Event(this.id, this.frame, this.type); -// @override -// String toString(){ -// return "E#$id f#$frame: $type"; -// } -// } + @override + String toString(){ + return "E#$id f#$frame: $type"; + } +} -// class Keypress{ -// KeyType key; -// late double subframe; -// bool released; +class Keypress{ + KeyType key; + late double subframe; + bool released; -// Keypress(this.key, num sframe, this.released){ -// subframe = sframe.toDouble(); -// } -// } + Keypress(this.key, num sframe, this.released){ + subframe = sframe.toDouble(); + } +} -// class EventKeyPress extends Event{ -// Keypress data; +class EventKeyPress extends Event{ + Keypress data; -// EventKeyPress(super.id, super.frame, super.type, this.data); -// } + EventKeyPress(super.id, super.frame, super.type, this.data); +} -// class Targets{ -// String? id; -// int? frame; -// String? type; -// List? data; +class Targets{ + String? id; + int? frame; + String? type; + List? data; -// Targets(this.id, this.frame, this.type, this.data); + Targets(this.id, this.frame, this.type, this.data); -// Targets.fromJson(Map json){ -// id = json["id"]; -// frame = json["frame"]; -// type = json["type"]; -// data = json["data"]; -// } -// } + Targets.fromJson(Map json){ + id = json["id"]; + frame = json["frame"]; + type = json["type"]; + data = json["data"]; + } +} -// class EventTargets extends Event{ -// Targets data; +class EventTargets extends Event{ + Targets data; -// EventTargets(super.id, super.frame, super.type, this.data); -// } + EventTargets(super.id, super.frame, super.type, this.data); +} -// class IGEdata{ - -// } +class IGEdata{ + late String type; + late String? gameid; + late int? frame; -// enum GarbageStatus -// { -// sleeping, -// caution, -// spawn, -// danger -// } + IGEdata.fromJson(Map d){ + type = d['type']; + gameid = d['gameid']; + frame = d['frame']; + } +} -// class GarbageData{ -// int? id; -// late int iid; -// late int ackiid; -// String? username; -// late String type; -// bool? active; -// GarbageStatus? status; -// int? delay; -// bool? queued; -// late int amt; -// late int x; -// late int y; -// int? size; -// late int column; -// int? cid; -// bool? firstcycle; -// int? gid; +enum GarbageStatus +{ + sleeping, + caution, + spawn, + danger +} -// GarbageData.fromJson(Map data){ -// id = data['id']; -// iid = data['iid']; -// ackiid = data['ackiid']; -// username = data['username']; -// type = data['type']; -// active = data['active']; -// status = data['status'] != null ? GarbageStatus.values[data['status']] : null; -// delay = data['delay']; -// queued = data['queued']; -// amt = data['amt']; -// x = data['x']; -// y = data['y']; -// size = data['size']; -// column = data['column']; -// cid = data['cid']; -// firstcycle = data['firstcycle']; -// gid = data['gid']; -// } -// } +class GarbageData{ + int? id; + int? iid; + int? ackiid; + String? username; + late String type; + bool? active; + GarbageStatus? status; + int? delay; + bool? queued; + int? amt; + int? x; + int? y; + int? size; + int? column; + int? cid; + bool? firstcycle; + int? gid; + bool? value; -// class IGEdataTarget extends IGEdata{ -// late String type; -// late List targets; -// late int frame; + GarbageData.fromJson(Map data){ + id = data['id']; + iid = data['iid']; + ackiid = data['ackiid']; + username = data['username']; + type = data['type']; + active = data['active']; + status = data['status'] != null ? GarbageStatus.values[data['status']] : null; + delay = data['delay']; + queued = data['queued']; + amt = data['amt']; + x = data['x']; + y = data['y']; + size = data['size']; + column = data['column']; + cid = data['cid']; + firstcycle = data['firstcycle']; + gid = data['gid']; + value = data['value']; + } +} + +class IGEdataTarget extends IGEdata{ + late List targets; -// late String gameid; -// GarbageData? data; -// //compatibility for v15 targets event -// String? sender_id; + GarbageData? data; + //compatibility for v15 targets event + String? sender_id; -// IGEdataTarget.fromJson(Map d){ -// type = d['type']; -// targets = d['targets']; -// frame = d['targets']; -// gameid = d['gameid']; -// data = GarbageData.fromJson(d['data']); -// } -// } + IGEdataTarget.fromJson(Map d) : super.fromJson(d){ + targets = d['targets']; + data = d['data'] != null ? GarbageData.fromJson(d['data']) : null; + } +} -// class IGE{ -// int id; -// int frame; -// String type; -// Map data; +class IGEdataAllowTargeting extends IGEdata{ + late bool value; -// IGE(this.id, this.frame, this.type, this.data); -// } + IGEdataAllowTargeting.fromJson(Map d) : super.fromJson(d){ + value = d['value']; + frame = d['frame']; + } +} -// class EventIGE extends Event{ -// IGE data; +class IGEdataInteraction extends IGEdata{ + late GarbageData data; + String? sender; + String? senderID; + int? sentFrame; + bool confirm = false; + -// EventIGE(super.id, super.frame, super.type, this.data); -// } + IGEdataInteraction.fromJson(Map d) : super.fromJson(d){ + //data = Targeted(d['data']['targeted'], d['data']['value']); + data = GarbageData.fromJson(d['data']); + sender = d['sender']; + senderID = d['sender_id']; + confirm = type == "interaction_confirm"; + } +} -// class EndData { -// String reason; -// DataFull export; +class IGE{ + int id; + int frame; + String type; + late IGEdata data; -// EndData(this.reason, this.export); -// } + IGE(this.id, this.frame, this.type, Map d){ + data = switch (d["type"] as String) { + "interaction" => IGEdataInteraction.fromJson(d), + "interaction_confirm" => IGEdataInteraction.fromJson(d), + "target" => IGEdataTarget.fromJson(d), + "allow_targeting" => IGEdataAllowTargeting.fromJson(d), + _ => IGEdata.fromJson(d), + }; + } +} -// class EventEnd extends Event{ -// EndData data; +class EventIGE extends Event{ + IGE data; -// EventEnd(super.id, super.frame, super.type, this.data); -// } + EventIGE(super.id, super.frame, super.type, this.data); +} -// class Hold -// { -// String? piece; -// bool locked; +class EndData { + String reason; + DataFull export; -// Hold(this.piece, this.locked); -// } + EndData(this.reason, this.export); +} -// class DataFullOptions{ -// int? version; -// bool? seedRandom; -// int? seed; -// double? g; -// int? stock; -// int? gMargin; -// double? gIncrease; -// double? garbageMultiplier; -// int? garbageMargin; -// double? garbageIncrease; -// int? garbageCap; -// double? garbageCapIncrease; -// int? garbageCapMax; -// int? garbageHoleSize; -// String? garbageBlocking; // TODO: enum -// bool? hasGarbage; -// int? locktime; -// int? garbageSpeed; -// int? forfeitTime; -// int? are; -// int? areLineclear; -// bool? infiniteMovement; -// int? lockresets; -// bool? allow180; -// bool? btbChaining; -// bool? allclears; -// bool? clutch; -// bool? noLockout; -// String? passthrough; -// int? boardwidth; -// int? boardheight; -// Handling? handling; -// int? boardbuffer; +class EventEnd extends Event{ + EndData data; -// DataFullOptions.fromJson(Map json){ -// version = json["version"]; -// seedRandom = json["seed_random"]; -// seed = json["seed"]; -// g = json["g"]; -// stock = json["stock"]; -// gMargin = json["gmargin"]; -// gIncrease = json["gincrease"]; -// garbageMultiplier = json["garbagemultiplier"].toDouble(); -// garbageCapIncrease = json["garbagecapincrease"].toDouble(); -// garbageCapMax = json["garbagecapmax"]; -// garbageHoleSize = json["garbageholesize"]; -// garbageBlocking = json["garbageblocking"]; -// hasGarbage = json["hasgarbage"]; -// locktime = json["locktime"]; -// garbageSpeed = json["garbagespeed"]; -// forfeitTime = json["forfeit_time"]; -// are = json["are"]; -// areLineclear = json["lineclear_are"]; -// infiniteMovement = json["infinitemovement"]; -// lockresets = json["lockresets"]; -// allow180 = json["allow180"]; -// btbChaining = json["b2bchaining"]; -// allclears = json["allclears"]; -// clutch = json["clutch"]; -// noLockout = json["nolockout"]; -// passthrough = json["passthrough"]; -// boardwidth = json["boardwidth"]; -// boardheight = json["boardheight"]; -// handling = Handling.fromJson(json["handling"]); -// boardbuffer = json["boardbuffer"]; -// } -// } + EventEnd(super.id, super.frame, super.type, this.data); +} -// class DataFullStats -// { -// int? seed; -// int? lines; -// int? levelLines; -// int? levelLinesNeeded; -// int? inputs; -// int? holds; -// int? score; -// int? zenLevel; -// int? zenProgress; -// int? level; -// int? combo; -// int? currentComboPower; -// int? topCombo; -// int? btb; -// int? topbtb; -// int? tspins; -// int? piecesPlaced; -// Clears? clears; -// Garbage? garbage; -// int? kills; -// Finesse? finesse; +class Hold +{ + String? piece; + bool locked; -// DataFullStats.fromJson(Map json){ -// seed = json["seed"]; -// lines = json["lines"]; -// levelLines = json["level_lines"]; -// levelLinesNeeded = json["level_lines_needed"]; -// inputs = json["inputs"]; -// holds = json["holds"]; -// score = json["score"]; -// zenLevel = json["zenlevel"]; -// zenProgress = json["zenprogress"]; -// level = json["level"]; -// combo = json["combo"]; -// currentComboPower = json["currentcombopower"]; -// topCombo = json["topcombo"]; -// btb = json["btb"]; -// topbtb = json["topbtb"]; -// tspins = json["tspins"]; -// piecesPlaced = json["piecesplaced"]; -// clears = Clears.fromJson(json["clears"]); -// garbage = Garbage.fromJson(json["garbage"]); -// kills = json["kills"]; -// finesse = Finesse.fromJson(json["finesse"]); -// } -// } + Hold(this.piece, this.locked); +} -// class DataFullGame -// { -// List? board; -// List? bag; -// double? g; -// bool? playing; -// Hold? hold; -// String? piece; -// Handling? handling; +class DataFullOptions{ + int? version; + bool? seedRandom; + int? seed; + double? g; + int? stock; + int? gMargin; + double? gIncrease; + double? garbageMultiplier; + int? garbageMargin; + double? garbageIncrease; + int? garbageCap; + double? garbageCapIncrease; + int? garbageCapMax; + int? garbageHoleSize; + String? garbageBlocking; // TODO: enum + bool? hasGarbage; + int? locktime; + int? garbageSpeed; + int? forfeitTime; + int? are; + int? areLineclear; + bool? infiniteMovement; + int? lockresets; + bool? allow180; + bool? btbChaining; + bool? allclears; + bool? clutch; + bool? noLockout; + String? passthrough; + int? boardwidth; + int? boardheight; + Handling? handling; + int? boardbuffer; -// DataFullGame.fromJson(Map json){ -// board = json["board"]; -// bag = json["bag"]; -// hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); -// g = json["g"]; -// handling = Handling.fromJson(json["handling"]); -// } -// } + DataFullOptions.fromJson(Map json){ + version = json["version"]; + seedRandom = json["seed_random"]; + seed = json["seed"]; + g = json["g"]; + stock = json["stock"]; + gMargin = json["gmargin"]; + gIncrease = json["gincrease"]; + garbageMultiplier = json["garbagemultiplier"].toDouble(); + garbageCapIncrease = json["garbagecapincrease"].toDouble(); + garbageCapMax = json["garbagecapmax"]; + garbageHoleSize = json["garbageholesize"]; + garbageBlocking = json["garbageblocking"]; + hasGarbage = json["hasgarbage"]; + locktime = json["locktime"]; + garbageSpeed = json["garbagespeed"]; + forfeitTime = json["forfeit_time"]; + are = json["are"]; + areLineclear = json["lineclear_are"]; + infiniteMovement = json["infinitemovement"]; + lockresets = json["lockresets"]; + allow180 = json["allow180"]; + btbChaining = json["b2bchaining"]; + allclears = json["allclears"]; + clutch = json["clutch"]; + noLockout = json["nolockout"]; + passthrough = json["passthrough"]; + boardwidth = json["boardwidth"]; + boardheight = json["boardheight"]; + handling = Handling.fromJson(json["handling"]); + boardbuffer = json["boardbuffer"]; + } +} -// class DataFull{ -// bool? successful; -// String? gameOverReason; -// int? fire; -// DataFullOptions? options; -// DataFullStats? stats; -// DataFullGame? game; +class DataFullStats + { + int? seed; + int? lines; + int? levelLines; + int? levelLinesNeeded; + int? inputs; + int? holds; + int? score; + int? zenLevel; + int? zenProgress; + int? level; + int? combo; + int? currentComboPower; + int? topCombo; + int? btb; + int? topbtb; + int? tspins; + int? piecesPlaced; + Clears? clears; + Garbage? garbage; + int? kills; + Finesse? finesse; -// DataFull.fromJson(Map json){ -// successful = json["successful"]; -// gameOverReason = json["gameoverreason"]; -// fire = json["fire"]; -// options = DataFullOptions.fromJson(json["options"]); -// stats = DataFullStats.fromJson(json["stats"]); -// game = DataFullGame.fromJson(json["game"]); -// } -// } + DataFullStats.fromJson(Map json){ + seed = json["seed"]; + lines = json["lines"]; + levelLines = json["level_lines"]; + levelLinesNeeded = json["level_lines_needed"]; + inputs = json["inputs"]; + holds = json["holds"]; + score = json["score"]; + zenLevel = json["zenlevel"]; + zenProgress = json["zenprogress"]; + level = json["level"]; + combo = json["combo"]; + currentComboPower = json["currentcombopower"]; + topCombo = json["topcombo"]; + btb = json["btb"]; + topbtb = json["topbtb"]; + tspins = json["tspins"]; + piecesPlaced = json["piecesplaced"]; + clears = Clears.fromJson(json["clears"]); + garbage = Garbage.fromJson(json["garbage"]); + kills = json["kills"]; + finesse = Finesse.fromJson(json["finesse"]); + } + } -// class EventFull extends Event{ -// DataFull data; +class DataFullGame + { + List? board; + List? bag; + double? g; + bool? playing; + Hold? hold; + String? piece; + Handling? handling; -// EventFull(super.id, super.frame, super.type, this.data); -// } + DataFullGame.fromJson(Map json){ + board = json["board"]; + bag = json["bag"]; + hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); + g = json["g"]; + handling = Handling.fromJson(json["handling"]); + } + } -// class TetrioRNG{ -// late double _t; +class DataFull{ + bool? successful; + String? gameOverReason; + int? fire; + DataFullOptions? options; + DataFullStats? stats; + DataFullGame? game; -// TetrioRNG(int seed){ -// _t = seed % 2147483647; -// if (_t <= 0) _t += 2147483646; -// } + DataFull.fromJson(Map json){ + successful = json["successful"]; + gameOverReason = json["gameoverreason"]; + fire = json["fire"]; + options = DataFullOptions.fromJson(json["options"]); + stats = DataFullStats.fromJson(json["stats"]); + game = DataFullGame.fromJson(json["game"]); + } +} -// int next(){ -// _t = 16807 * _t % 2147483647; -// return _t.toInt(); -// } +class EventFull extends Event{ + DataFull data; -// double nextFloat(){ -// return (next() - 1) / 2147483646; -// } + EventFull(super.id, super.frame, super.type, this.data); +} -// List shuffleList(List array){ -// int length = array.length; -// if (length == 0) return []; +class TetrioRNG{ + late double _t; -// for (; --length > 0;){ -// int swapIndex = ((nextFloat()) * (length + 1)).toInt(); -// Tetromino tmp = array[length]; -// array[length] = array[swapIndex]; -// array[swapIndex] = tmp; -// } -// return array; -// } -// } + TetrioRNG(int seed){ + _t = seed % 2147483647; + if (_t <= 0) _t += 2147483646; + } -// enum Tetromino{ -// Z, -// L, -// O, -// S, -// I, -// J, -// T, -// garbage, -// empty -// } + int next(){ + _t = 16807 * _t % 2147483647; + return _t.toInt(); + } -// List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; -// List>> shapes = [ -// [ // Z -// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], -// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] -// ], -// [ // L -// [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] -// ], -// [ // O -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] -// ], -// [ // S -// [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], -// [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], -// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] -// ], -// [ // I -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], -// [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], -// [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] -// ], -// [ // J -// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] -// ], -// [ // T -// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], -// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], -// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], -// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] -// ] -// ]; -// List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; + double nextFloat(){ + return (next() - 1) / 2147483646; + } -// const Map garbage = { -// "single": 0, -// "double": 1, -// "triple": 2, -// "quad": 4, -// "penta": 5, -// "t-spin": 0, -// "t-spin single": 2, -// "t-spin double": 4, -// "t-spin triple": 6, -// "t-spin quad": 10, -// "t-spin penta": 12, -// "t-spin mini": 0, -// "t-spin mini single": 0, -// "t-spin mini double": 1, -// "allclear": 10 -// }; -// int btbBonus = 1; -// double btbLog = 0.8; -// double comboBonus = 0.25; -// int comboMinifier = 1; -// double comboMinifierLog = 1.25; -// List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; + List shuffleList(List array){ + int length = array.length; + if (length == 0) return []; + + for (; --length > 0;){ + int swapIndex = ((nextFloat()) * (length + 1)).toInt(); + Tetromino tmp = array[length]; + array[length] = array[swapIndex]; + array[swapIndex] = tmp; + } + return array; + } +} + +enum Tetromino{ + Z, + L, + O, + S, + I, + J, + T, + garbage, + empty +} + +List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; +List>> shapes = [ + [ // Z + [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], + [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], + [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] + ], + [ // L + [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], + [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], + [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] + ], + [ // O + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] + ], + [ // S + [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], + [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], + [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], + [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] + ], + [ // I + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], + [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], + [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], + [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] + ], + [ // J + [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], + [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], + [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] + ], + [ // T + [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], + [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], + [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], + [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] + ] +]; +List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; + +const Map garbage = { + "single": 0, + "double": 1, + "triple": 2, + "quad": 4, + "penta": 5, + "t-spin": 0, + "t-spin single": 2, + "t-spin double": 4, + "t-spin triple": 6, + "t-spin quad": 10, + "t-spin penta": 12, + "t-spin mini": 0, + "t-spin mini single": 0, + "t-spin mini double": 1, + "allclear": 10 +}; +int btbBonus = 1; +double btbLog = 0.8; +double comboBonus = 0.25; +int comboMinifier = 1; +double comboMinifierLog = 1.25; +List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; From f7a08286f8761e6f2ba1dd58b37958b1259e363d Mon Sep 17 00:00:00 2001 From: dan63047 Date: Sun, 23 Jun 2024 01:15:21 +0300 Subject: [PATCH 05/14] I feel a little stupid ...or maybe i'm stupid more, than a little... --- lib/data_objects/freyhoe_test.dart | 194 ++++++++++++++++++++++++++--- 1 file changed, 179 insertions(+), 15 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 29435e8..dec8153 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -1,26 +1,190 @@ import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:ffi'; +import 'dart:math'; +import 'package:logging/logging.dart' as logging; import 'dart:io'; - -import 'package:path_provider/path_provider.dart'; - import 'tetrio_multiplayer_replay.dart'; +class HandlingHandler{ + double das; + double arr; + late double dasLeft; // frames + late double arrLeft; // frames + bool sdfActive = false; + bool activeLeft = false; + bool activeRight = false; + int direction = 0; // -1 - left, 1 - right, 0 - none + + HandlingHandler(this.das, this.arr){ + dasLeft = das; + arrLeft = arr; + } + + void movement_key_pressed(bool left, bool right){ + if (left) { + activeLeft = left; + direction = -1; + } + if (right) { + activeRight = right; + direction = 1; + } + dasLeft = das; + } + + void movement_key_released(bool left, bool right){ + if (left) { + activeLeft = !left; + } + if (right) { + activeRight = !right; + } + if (activeLeft) { + direction = -1; + } + if (activeRight) { + direction = 1; + } + if (activeLeft && activeRight){ + arrLeft = arr; + dasLeft = das; + direction = 0; + } + } + + int process_movenent(double delta){ + if (!activeLeft && !activeRight) return 0; + if (dasLeft > 0.0) { + dasLeft -= delta; + if (dasLeft <= 0.0) { + arrLeft += dasLeft; + dasLeft = 0.0; + return direction; + }else{ + return 0; + } + }else{ + arrLeft -= delta; + if (arrLeft <= 0.0) { + arrLeft += arr; + return direction; + }else { + return 0; + } + } + } +} + // That thing allows me to test my new staff i'm trying to implement void main() async { - // List queue = List.from(tetrominoes); - // TetrioRNG rng = TetrioRNG(0); - // queue = rng.shuffleList(queue); - // print(queue); - // queue = List.from(tetrominoes); - // queue = rng.shuffleList(queue); - // print(queue); - - //var downloadPath = await getDownloadsDirectory(); var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); ReplayData replay = ReplayData.fromJson(replayJson); - //List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; + List queue = List.from(tetrominoes); + TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); + List bag = rng.shuffleList(tetrominoes); List events = readEventList(replay.rawJson); - //events.retainWhere((element) => element.runtimeType == EventIGE && (element as EventIGE).data.data['type'] == "interaction_confirm"); - print(events); + DataFullOptions? settings; + HandlingHandler? handling; + Map activeKeypresses = {}; + int currentFrame = 0; + events.removeAt(0); // get rig of Event.start + Event nextEvent = events.removeAt(0); + List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; + Tetromino current = bag.removeAt(0); + Tetromino? hold; + int rot = 0; + int x = 4; + int y = 21; + double gravityBucket = 0.00000000000000; + + x += spawnPositionFixes[current.index].x.toInt(); + y += spawnPositionFixes[current.index].y.toInt(); + for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ + gravityBucket += settings != null ? settings.g! : 0; + if (gravityBucket >= 1.0){ + y -= gravityBucket.truncate(); + gravityBucket -= gravityBucket.truncate(); + } + x += handling != null ? handling.process_movenent(1.0) : 0; + print("$currentFrame: $x $y"); + if (currentFrame == nextEvent.frame){ + print("Processing $nextEvent"); + switch (nextEvent.type){ + case EventType.start: + developer.log("go"); + break; + case EventType.full: + settings = (nextEvent as EventFull).data.options; + handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); + break; + case EventType.keydown: + nextEvent as EventKeyPress; + activeKeypresses[nextEvent.data.key] = nextEvent; + switch (nextEvent.data.key){ + case KeyType.rotateCCW: + rot = (rot-1)%4; + break; + case KeyType.rotateCW: + rot = (rot+1)%4; + break; + case KeyType.rotate180: + rot = (rot+2)%4; + break; + case KeyType.moveLeft: + handling!.movement_key_pressed(true, false); + case KeyType.moveRight: + handling!.movement_key_pressed(false, true); + case KeyType.softDrop: + // TODO: Handle this case. + case KeyType.hardDrop: + // TODO: Handle this case. + case KeyType.hold: + // TODO: Handle this case. + case KeyType.chat: + // TODO: Handle this case. + case KeyType.exit: + // TODO: Handle this case. + case KeyType.retry: + // TODO: Handle this case. + default: + developer.log(nextEvent.data.key.name); + } + break; + case EventType.keyup: + nextEvent as EventKeyPress; + switch (nextEvent.data.key){ + case KeyType.moveLeft: + handling!.movement_key_released(true, false); + case KeyType.moveRight: + handling!.movement_key_released(false, true); + case KeyType.softDrop: + // TODO: Handle this case. + case KeyType.rotateCCW: + // TODO: Handle this case. + case KeyType.rotateCW: + // TODO: Handle this case. + case KeyType.rotate180: + // TODO: Handle this case. + case KeyType.hardDrop: + // TODO: Handle this case. + case KeyType.hold: + // TODO: Handle this case. + case KeyType.chat: + // TODO: Handle this case. + case KeyType.exit: + // TODO: Handle this case. + case KeyType.retry: + // TODO: Handle this case. + } + activeKeypresses.remove(nextEvent.data.key); + break; + default: + developer.log("Event wasn't processed: ${nextEvent}", level: 900); + } + nextEvent = events.removeAt(0); + developer.log("Next is: $nextEvent"); + } + } exit(0); } \ No newline at end of file From 836f533e3a7ec32b6b610b1bb4f3be878bf99592 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Tue, 25 Jun 2024 01:07:56 +0300 Subject: [PATCH 06/14] Simulation progress?.. (works like shit but at least something) --- lib/data_objects/freyhoe_test.dart | 277 ++++++++++++------ .../tetrio_multiplayer_replay.dart | 82 ++++-- 2 files changed, 242 insertions(+), 117 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index dec8153..38f3d8e 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -3,6 +3,7 @@ import 'dart:developer' as developer; import 'dart:ffi'; import 'dart:math'; import 'package:logging/logging.dart' as logging; +import 'package:vector_math/vector_math_64.dart'; import 'dart:io'; import 'tetrio_multiplayer_replay.dart'; @@ -76,13 +77,64 @@ class HandlingHandler{ } } +class Board{ + int width; + int height; + int bufferHeight; + late List> board; + late int totalHeight; + + Board(this.width, this.height, this.bufferHeight){ + totalHeight = height+bufferHeight; + board = [for (var i = 0 ; i < totalHeight; i++) [for (var i = 0 ; i < width; i++) Tetromino.empty]]; + } + + @override + String toString() { + String result = ""; + for (var row in board){ + for (var cell in row) result += cell.name[0]; + result += "\n"; + } + return result; + } + + bool isOccupied(Coords coords) + { + if (coords.x < 0 || coords.x >= width || + coords.y < 0 || coords.y >= totalHeight || + board[coords.y][coords.x] != Tetromino.empty) return true; + return false; + } + + bool positionIsValid(Tetromino type, Coords coords, int r){ + List shape = shapes[type.index][r]; + for (Coords mino in shape){ + if (isOccupied(coords+mino)) return false; + } + return true; + } + + void writeToBoard(Tetromino type, Coords coords, int rot) { + if (!positionIsValid(type, coords, rot)) return; + List shape = shapes[type.index][rot]; + for (Coords mino in shape){ + var finalCoords = coords+mino; + board[finalCoords.y][finalCoords.x] = type; + } + } +} + +class Simulation{ + +} + // That thing allows me to test my new staff i'm trying to implement void main() async { var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); ReplayData replay = ReplayData.fromJson(replayJson); - List queue = List.from(tetrominoes); TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); - List bag = rng.shuffleList(tetrominoes); + List queue = rng.shuffleList(tetrominoes); List events = readEventList(replay.rawJson); DataFullOptions? settings; HandlingHandler? handling; @@ -90,100 +142,155 @@ void main() async { int currentFrame = 0; events.removeAt(0); // get rig of Event.start Event nextEvent = events.removeAt(0); - List> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]]; - Tetromino current = bag.removeAt(0); + Board board = Board(10, 20, 20); Tetromino? hold; int rot = 0; - int x = 4; - int y = 21; + Coords coords = Coords(4, 21); double gravityBucket = 0.00000000000000; - x += spawnPositionFixes[current.index].x.toInt(); - y += spawnPositionFixes[current.index].y.toInt(); + developer.log("Seed is ${replay.stats[0][0].seed}, first bag is $queue"); + Tetromino current = queue.removeAt(0); + //developer.log("Second bag is ${rng.shuffleList(tetrominoes)}"); + + int sonicDrop(){ + int height = coords.y; + while (board.positionIsValid(current, Coords(coords.x, height), rot)){ + height -= 1; + } + height += 1; + return height; + } + + Tetromino getNewOne(){ + if (queue.length <= 1) queue.addAll(rng.shuffleList(tetrominoes)); + developer.log("Next queue is $queue"); + return queue.removeAt(0); + } + + coords += spawnPositionFixes[current.index]; for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ - gravityBucket += settings != null ? settings.g! : 0; + gravityBucket += settings != null ? (handling!.sdfActive ? settings.g! * settings.handling!.sdf : settings.g!) : 0; + + int movement = handling != null ? handling.process_movenent(1.0) : 0; + if (board.positionIsValid(current, Coords(coords.x+movement, coords.y), rot)) coords.x += movement; + + int gravityImpact = 0; if (gravityBucket >= 1.0){ - y -= gravityBucket.truncate(); + gravityImpact = gravityBucket.truncate(); gravityBucket -= gravityBucket.truncate(); } - x += handling != null ? handling.process_movenent(1.0) : 0; - print("$currentFrame: $x $y"); + if (board.positionIsValid(current, Coords(coords.x, coords.y-gravityImpact), rot)) coords.y -= gravityImpact; + print("$currentFrame: $current at $coords\n$board"); + if (currentFrame == nextEvent.frame){ - print("Processing $nextEvent"); - switch (nextEvent.type){ - case EventType.start: - developer.log("go"); - break; - case EventType.full: - settings = (nextEvent as EventFull).data.options; - handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); - break; - case EventType.keydown: - nextEvent as EventKeyPress; - activeKeypresses[nextEvent.data.key] = nextEvent; - switch (nextEvent.data.key){ - case KeyType.rotateCCW: - rot = (rot-1)%4; - break; - case KeyType.rotateCW: - rot = (rot+1)%4; - break; - case KeyType.rotate180: - rot = (rot+2)%4; - break; - case KeyType.moveLeft: - handling!.movement_key_pressed(true, false); - case KeyType.moveRight: - handling!.movement_key_pressed(false, true); - case KeyType.softDrop: - // TODO: Handle this case. - case KeyType.hardDrop: - // TODO: Handle this case. - case KeyType.hold: - // TODO: Handle this case. - case KeyType.chat: - // TODO: Handle this case. - case KeyType.exit: - // TODO: Handle this case. - case KeyType.retry: - // TODO: Handle this case. - default: - developer.log(nextEvent.data.key.name); + while (currentFrame == nextEvent.frame){ + //print("Processing $nextEvent"); + switch (nextEvent.type){ + case EventType.start: + developer.log("go"); + break; + case EventType.full: + settings = (nextEvent as EventFull).data.options; + handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); + break; + case EventType.keydown: + nextEvent as EventKeyPress; + activeKeypresses[nextEvent.data.key] = nextEvent; + switch (nextEvent.data.key){ + case KeyType.rotateCCW: + rot = (rot+1)%4; + break; + case KeyType.rotateCW: + rot = (rot-1)%4; + break; + case KeyType.rotate180: + rot = (rot+2)%4; + break; + case KeyType.moveLeft: + handling!.movement_key_pressed(true, false); + break; + case KeyType.moveRight: + handling!.movement_key_pressed(false, true); + break; + case KeyType.softDrop: + handling!.sdfActive = true; + break; + case KeyType.hardDrop: + coords.y = sonicDrop(); + board.writeToBoard(current, coords, rot); + current = getNewOne(); + coords = Coords(4, 21) + spawnPositionFixes[current.index]; + //handling!.movement_key_released(true, true); + case KeyType.hold: + switch (hold){ + case null: + hold = current; + current = getNewOne(); + break; + case _: + Tetromino temp; + temp = hold; + hold = current; + current = temp; + break; + } + coords = Coords(4, 21) + spawnPositionFixes[current.index]; + break; + case KeyType.chat: + // TODO: Handle this case. + case KeyType.exit: + // TODO: Handle this case. + case KeyType.retry: + // TODO: Handle this case. + default: + developer.log(nextEvent.data.key.name); + } + break; + case EventType.keyup: + nextEvent as EventKeyPress; + switch (nextEvent.data.key){ + case KeyType.moveLeft: + handling!.movement_key_released(true, false); + break; + case KeyType.moveRight: + handling!.movement_key_released(false, true); + break; + case KeyType.softDrop: + handling?.sdfActive = false; + break; + case KeyType.rotateCCW: + // TODO: Handle this case. + case KeyType.rotateCW: + // TODO: Handle this case. + case KeyType.rotate180: + // TODO: Handle this case. + case KeyType.hardDrop: + // TODO: Handle this case. + case KeyType.hold: + // TODO: Handle this case. + case KeyType.chat: + // TODO: Handle this case. + case KeyType.exit: + // TODO: Handle this case. + case KeyType.retry: + // TODO: Handle this case. + } + activeKeypresses.remove(nextEvent.data.key); + break; + case EventType.end: + currentFrame = replay.roundLengths[0]+1; + break; + default: + developer.log("Event wasn't processed: ${nextEvent}", level: 900); + } + try{ + nextEvent = events.removeAt(0); } - break; - case EventType.keyup: - nextEvent as EventKeyPress; - switch (nextEvent.data.key){ - case KeyType.moveLeft: - handling!.movement_key_released(true, false); - case KeyType.moveRight: - handling!.movement_key_released(false, true); - case KeyType.softDrop: - // TODO: Handle this case. - case KeyType.rotateCCW: - // TODO: Handle this case. - case KeyType.rotateCW: - // TODO: Handle this case. - case KeyType.rotate180: - // TODO: Handle this case. - case KeyType.hardDrop: - // TODO: Handle this case. - case KeyType.hold: - // TODO: Handle this case. - case KeyType.chat: - // TODO: Handle this case. - case KeyType.exit: - // TODO: Handle this case. - case KeyType.retry: - // TODO: Handle this case. + catch (e){ + developer.log(e.toString()); } - activeKeypresses.remove(nextEvent.data.key); - break; - default: - developer.log("Event wasn't processed: ${nextEvent}", level: 900); - } - nextEvent = events.removeAt(0); - developer.log("Next is: $nextEvent"); + } + //developer.log("Next is: $nextEvent"); } } exit(0); diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index 648727e..ef8dc34 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -1,8 +1,6 @@ import 'dart:math'; import 'dart:typed_data'; -import 'package:vector_math/vector_math_64.dart'; - import 'tetrio.dart'; // I want to implement those fancy TWC stats @@ -752,52 +750,72 @@ enum Tetromino{ empty } +class Coords{ + int x; + int y; + + Coords(this.x, this.y); + + @override + String toString() { + return "($x; $y)"; + } + + Coords operator+(Coords other){ + return Coords(x+other.x, y+other.y); + } + + Coords operator-(Coords other){ + return Coords(x-other.x, y-other.y); + } +} + List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; -List>> shapes = [ +List>> shapes = [ [ // Z - [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], - [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] + [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(2, 1)], + [Coords(2, 0), Coords(1, 1), Coords(2, 1), Coords(1, 2)], + [Coords(0, 1), Coords(1, 1), Coords(1, 2), Coords(2, 2)], + [Coords(1, 0), Coords(0, 1), Coords(1, 1), Coords(0, 2)] ], [ // L - [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], - [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] + [Coords(2, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], + [Coords(1, 0), Coords(1, 1), Coords(1, 2), Coords(2, 2)], + [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(0, 2)], + [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)] ], [ // O - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] + [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], + [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], + [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], + [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)] ], [ // S - [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], - [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], - [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] + [Coords(1, 0), Coords(2, 0), Coords(0, 1), Coords(1, 1)], + [Coords(1, 0), Coords(1, 1), Coords(2, 1), Coords(2, 2)], + [Coords(1, 1), Coords(2, 1), Coords(0, 2), Coords(1, 2)], + [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] ], [ // I - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], - [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], - [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], - [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] + [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(3, 1)], + [Coords(2, 0), Coords(2, 1), Coords(2, 2), Coords(2, 3)], + [Coords(0, 2), Coords(1, 2), Coords(2, 2), Coords(3, 2)], + [Coords(1, 0), Coords(1, 1), Coords(1, 2), Coords(1, 3)] ], [ // J - [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], - [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] + [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], + [Coords(1, 0), Coords(2, 0), Coords(1, 1), Coords(1, 2)], + [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(2, 2)], + [Coords(1, 0), Coords(1, 1), Coords(0, 2), Coords(1, 2)] ], [ // T - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] + [Coords(1, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], + [Coords(1, 0), Coords(1, 1), Coords(2, 1), Coords(1, 2)], + [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(1, 2)], + [Coords(1, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] ] ]; -List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; +List spawnPositionFixes = [Coords(1, 1), Coords(1, 1), Coords(0, 1), Coords(1, 1), Coords(1, 1), Coords(1, 1), Coords(1, 1)]; const Map garbage = { "single": 0, From ccb4909021054f0ed7231292d4eb707a8658b61c Mon Sep 17 00:00:00 2001 From: dan63047 Date: Fri, 28 Jun 2024 00:25:31 +0300 Subject: [PATCH 07/14] sometimes, stealing someone else code is a bad idea... --- lib/data_objects/freyhoe_test.dart | 45 ++++++++++------- .../tetrio_multiplayer_replay.dart | 48 +++++++++---------- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 38f3d8e..532e0b6 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -22,7 +22,7 @@ class HandlingHandler{ arrLeft = arr; } - void movement_key_pressed(bool left, bool right){ + void movementKeyPressed(bool left, bool right, double subframe){ if (left) { activeLeft = left; direction = -1; @@ -31,10 +31,11 @@ class HandlingHandler{ activeRight = right; direction = 1; } - dasLeft = das; + dasLeft = das - (1 - subframe); } - void movement_key_released(bool left, bool right){ + int movementKeyReleased(bool left, bool right, double subframe){ + int lastFrameMovement = processMovenent(subframe); if (left) { activeLeft = !left; } @@ -52,9 +53,10 @@ class HandlingHandler{ dasLeft = das; direction = 0; } + return lastFrameMovement; } - int process_movenent(double delta){ + int processMovenent(double delta){ if (!activeLeft && !activeRight) return 0; if (dasLeft > 0.0) { dasLeft -= delta; @@ -92,7 +94,7 @@ class Board{ @override String toString() { String result = ""; - for (var row in board){ + for (var row in board.reversed){ for (var cell in row) result += cell.name[0]; result += "\n"; } @@ -116,7 +118,7 @@ class Board{ } void writeToBoard(Tetromino type, Coords coords, int rot) { - if (!positionIsValid(type, coords, rot)) return; + if (!positionIsValid(type, coords, rot)) throw Exception("Attempted to write $type to $coords in $rot rot"); List shape = shapes[type.index][rot]; for (Coords mino in shape){ var finalCoords = coords+mino; @@ -134,7 +136,7 @@ void main() async { var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); ReplayData replay = ReplayData.fromJson(replayJson); TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); - List queue = rng.shuffleList(tetrominoes); + List queue = rng.shuffleList(tetrominoes.toList()); List events = readEventList(replay.rawJson); DataFullOptions? settings; HandlingHandler? handling; @@ -162,8 +164,13 @@ void main() async { } Tetromino getNewOne(){ - if (queue.length <= 1) queue.addAll(rng.shuffleList(tetrominoes)); - developer.log("Next queue is $queue"); + + if (queue.length <= 1) { + List nextPieces = rng.shuffleList(tetrominoes.toList()); + queue.addAll(nextPieces); + } + //developer.log("Next queue is $queue"); + rot = 0; return queue.removeAt(0); } @@ -171,7 +178,7 @@ void main() async { for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ gravityBucket += settings != null ? (handling!.sdfActive ? settings.g! * settings.handling!.sdf : settings.g!) : 0; - int movement = handling != null ? handling.process_movenent(1.0) : 0; + int movement = handling != null ? handling.processMovenent(1.0) : 0; if (board.positionIsValid(current, Coords(coords.x+movement, coords.y), rot)) coords.x += movement; int gravityImpact = 0; @@ -184,7 +191,7 @@ void main() async { if (currentFrame == nextEvent.frame){ while (currentFrame == nextEvent.frame){ - //print("Processing $nextEvent"); + print("Processing $nextEvent"); switch (nextEvent.type){ case EventType.start: developer.log("go"); @@ -198,19 +205,19 @@ void main() async { activeKeypresses[nextEvent.data.key] = nextEvent; switch (nextEvent.data.key){ case KeyType.rotateCCW: - rot = (rot+1)%4; + rot = (rot-1)%4; break; case KeyType.rotateCW: - rot = (rot-1)%4; + rot = (rot+1)%4; break; case KeyType.rotate180: rot = (rot+2)%4; break; case KeyType.moveLeft: - handling!.movement_key_pressed(true, false); + handling!.movementKeyPressed(true, false, nextEvent.data.subframe); break; case KeyType.moveRight: - handling!.movement_key_pressed(false, true); + handling!.movementKeyPressed(false, true, nextEvent.data.subframe); break; case KeyType.softDrop: handling!.sdfActive = true; @@ -220,7 +227,7 @@ void main() async { board.writeToBoard(current, coords, rot); current = getNewOne(); coords = Coords(4, 21) + spawnPositionFixes[current.index]; - //handling!.movement_key_released(true, true); + //handling!.movementKeyReleased(true, true); case KeyType.hold: switch (hold){ case null: @@ -250,10 +257,12 @@ void main() async { nextEvent as EventKeyPress; switch (nextEvent.data.key){ case KeyType.moveLeft: - handling!.movement_key_released(true, false); + int pontencialMovement = handling!.movementKeyReleased(true, false, nextEvent.data.subframe); + if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; break; case KeyType.moveRight: - handling!.movement_key_released(false, true); + int pontencialMovement = handling!.movementKeyReleased(false, true, nextEvent.data.subframe); + if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; break; case KeyType.softDrop: handling?.sdfActive = false; diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index ef8dc34..e018c69 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -773,16 +773,16 @@ class Coords{ List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; List>> shapes = [ [ // Z - [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(2, 1)], - [Coords(2, 0), Coords(1, 1), Coords(2, 1), Coords(1, 2)], - [Coords(0, 1), Coords(1, 1), Coords(1, 2), Coords(2, 2)], - [Coords(1, 0), Coords(0, 1), Coords(1, 1), Coords(0, 2)] + [Coords(0, 2), Coords(1, 2), Coords(1, 1), Coords(2, 1)], + [Coords(2, 2), Coords(2, 1), Coords(1, 1), Coords(1, 0)], + [Coords(2, 0), Coords(1, 0), Coords(1, 1), Coords(0, 1)], + [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] ], [ // L - [Coords(2, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], - [Coords(1, 0), Coords(1, 1), Coords(1, 2), Coords(2, 2)], - [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(0, 2)], - [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)] + [Coords(2, 2), Coords(2, 1), Coords(1, 1), Coords(0, 1)], + [Coords(2, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)], + [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], + [Coords(0, 2), Coords(1, 2), Coords(1, 1), Coords(1, 0)] ], [ // O [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], @@ -791,31 +791,31 @@ List>> shapes = [ [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)] ], [ // S - [Coords(1, 0), Coords(2, 0), Coords(0, 1), Coords(1, 1)], - [Coords(1, 0), Coords(1, 1), Coords(2, 1), Coords(2, 2)], - [Coords(1, 1), Coords(2, 1), Coords(0, 2), Coords(1, 2)], - [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] + [Coords(2, 2), Coords(1, 2), Coords(1, 1), Coords(0, 1)], + [Coords(2, 0), Coords(2, 1), Coords(1, 1), Coords(1, 2)], + [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(2, 1)], + [Coords(0, 2), Coords(0, 1), Coords(1, 1), Coords(1, 0)] ], [ // I - [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(3, 1)], - [Coords(2, 0), Coords(2, 1), Coords(2, 2), Coords(2, 3)], - [Coords(0, 2), Coords(1, 2), Coords(2, 2), Coords(3, 2)], + [Coords(0, 2), Coords(1, 2), Coords(2, 2), Coords(3, 2)], + [Coords(2, 3), Coords(2, 2), Coords(2, 1), Coords(2, 0)], + [Coords(3, 1), Coords(2, 1), Coords(1, 1), Coords(0, 1)], [Coords(1, 0), Coords(1, 1), Coords(1, 2), Coords(1, 3)] ], [ // J - [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], - [Coords(1, 0), Coords(2, 0), Coords(1, 1), Coords(1, 2)], - [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(2, 2)], - [Coords(1, 0), Coords(1, 1), Coords(0, 2), Coords(1, 2)] + [Coords(0, 2), Coords(0, 1), Coords(1, 1), Coords(2, 1)], + [Coords(2, 2), Coords(1, 2), Coords(1, 1), Coords(1, 0)], + [Coords(2, 0), Coords(2, 1), Coords(1, 1), Coords(0, 1)], + [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)] ], [ // T - [Coords(1, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], - [Coords(1, 0), Coords(1, 1), Coords(2, 1), Coords(1, 2)], - [Coords(0, 1), Coords(1, 1), Coords(2, 1), Coords(1, 2)], - [Coords(1, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] + [Coords(1, 2), Coords(0, 1), Coords(1, 1), Coords(2, 1)], + [Coords(2, 1), Coords(1, 2), Coords(1, 1), Coords(1, 0)], + [Coords(1, 0), Coords(2, 1), Coords(1, 1), Coords(0, 1)], + [Coords(0, 1), Coords(1, 0), Coords(1, 1), Coords(1, 2)] ] ]; -List spawnPositionFixes = [Coords(1, 1), Coords(1, 1), Coords(0, 1), Coords(1, 1), Coords(1, 1), Coords(1, 1), Coords(1, 1)]; +List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(1, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; const Map garbage = { "single": 0, From f0d4d809a3aeb711b0e4a417a2fc6106d4bcc17f Mon Sep 17 00:00:00 2001 From: dan63047 Date: Sun, 30 Jun 2024 01:30:41 +0300 Subject: [PATCH 08/14] Still need to fix 0arr, gravity and implement ige --- lib/data_objects/freyhoe_test.dart | 29 ++++++++++--------- .../tetrio_multiplayer_replay.dart | 2 +- lib/views/settings_view.dart | 7 +++++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 532e0b6..ae0d1cd 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -22,7 +22,12 @@ class HandlingHandler{ arrLeft = arr; } - void movementKeyPressed(bool left, bool right, double subframe){ + @override + String toString(){ + return "das: ${das}f; arr: ${arr}f"; + } + + int movementKeyPressed(bool left, bool right, double subframe){ if (left) { activeLeft = left; direction = -1; @@ -32,6 +37,7 @@ class HandlingHandler{ direction = 1; } dasLeft = das - (1 - subframe); + return direction; } int movementKeyReleased(bool left, bool right, double subframe){ @@ -60,7 +66,7 @@ class HandlingHandler{ if (!activeLeft && !activeRight) return 0; if (dasLeft > 0.0) { dasLeft -= delta; - if (dasLeft <= 0.0) { + if (dasLeft < 0.0) { arrLeft += dasLeft; dasLeft = 0.0; return direction; @@ -69,7 +75,7 @@ class HandlingHandler{ } }else{ arrLeft -= delta; - if (arrLeft <= 0.0) { + if (arrLeft < 0.0) { arrLeft += arr; return direction; }else { @@ -147,7 +153,7 @@ void main() async { Board board = Board(10, 20, 20); Tetromino? hold; int rot = 0; - Coords coords = Coords(4, 21); + Coords coords = Coords(3, 21); double gravityBucket = 0.00000000000000; developer.log("Seed is ${replay.stats[0][0].seed}, first bag is $queue"); @@ -199,6 +205,7 @@ void main() async { case EventType.full: settings = (nextEvent as EventFull).data.options; handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); + print(handling); break; case EventType.keydown: nextEvent as EventKeyPress; @@ -214,10 +221,9 @@ void main() async { rot = (rot+2)%4; break; case KeyType.moveLeft: - handling!.movementKeyPressed(true, false, nextEvent.data.subframe); - break; case KeyType.moveRight: - handling!.movementKeyPressed(false, true, nextEvent.data.subframe); + int pontencialMovement = handling!.movementKeyPressed(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); + if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; break; case KeyType.softDrop: handling!.sdfActive = true; @@ -226,7 +232,7 @@ void main() async { coords.y = sonicDrop(); board.writeToBoard(current, coords, rot); current = getNewOne(); - coords = Coords(4, 21) + spawnPositionFixes[current.index]; + coords = Coords(3, 21) + spawnPositionFixes[current.index]; //handling!.movementKeyReleased(true, true); case KeyType.hold: switch (hold){ @@ -241,7 +247,7 @@ void main() async { current = temp; break; } - coords = Coords(4, 21) + spawnPositionFixes[current.index]; + coords = Coords(3, 21) + spawnPositionFixes[current.index]; break; case KeyType.chat: // TODO: Handle this case. @@ -257,11 +263,8 @@ void main() async { nextEvent as EventKeyPress; switch (nextEvent.data.key){ case KeyType.moveLeft: - int pontencialMovement = handling!.movementKeyReleased(true, false, nextEvent.data.subframe); - if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; - break; case KeyType.moveRight: - int pontencialMovement = handling!.movementKeyReleased(false, true, nextEvent.data.subframe); + int pontencialMovement = handling!.movementKeyReleased(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; break; case KeyType.softDrop: diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index e018c69..4262c9d 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -815,7 +815,7 @@ List>> shapes = [ [Coords(0, 1), Coords(1, 0), Coords(1, 1), Coords(1, 2)] ] ]; -List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(1, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; +List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(2, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; const Map garbage = { "single": 0, diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 07a15d6..fb373b9 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -288,6 +288,13 @@ class SettingsState extends State { subtitle: Text(t.aboutAppText(appName: packageInfo.appName, packageName: packageInfo.packageName, version: packageInfo.version, buildNumber: packageInfo.buildNumber)), trailing: const Icon(Icons.arrow_right) ), + Wrap( + alignment: WrapAlignment.center, + spacing: 8, + children: [ + TextButton(child: Text("Donate to me"), onPressed: (){},),TextButton(child: Text("Donate to NOT me"), onPressed: (){},),TextButton(child: Text("Donate to someone else"), onPressed: (){},), + ], + ), ], )), ); From f5baf493cad59ede3cea0c591477f6b9aef651c7 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Thu, 4 Jul 2024 00:01:23 +0300 Subject: [PATCH 09/14] Still no inf SDF, incorrect SRS kicks, issues with incoming garbage and lots of shit shit --- lib/data_objects/freyhoe_test.dart | 207 +++++++++++++++++- .../tetrio_multiplayer_replay.dart | 63 +++++- lib/views/main_view.dart | 2 +- 3 files changed, 263 insertions(+), 9 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index ae0d1cd..24f1cc7 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -123,6 +123,17 @@ class Board{ return true; } + bool wasATSpin(Tetromino type, Coords coords, int rot){ + if (!(positionIsValid(type, Coords(coords.x+1, coords.y), rot) || + positionIsValid(type, Coords(coords.x-1, coords.y), rot) || + positionIsValid(type, Coords(coords.x, coords.y+1), rot) || + positionIsValid(type, Coords(coords.x, coords.y-1), rot)) + ){ + return true; + } + return false; + } + void writeToBoard(Tetromino type, Coords coords, int rot) { if (!positionIsValid(type, coords, rot)) throw Exception("Attempted to write $type to $coords in $rot rot"); List shape = shapes[type.index][rot]; @@ -131,6 +142,117 @@ class Board{ board[finalCoords.y][finalCoords.x] = type; } } + + void writeGarbage(GarbageData data, [int? amt]){ + List> garbage = [for (int i = 0; i < (amt??data.amt!); i++) [for (int k = 0; k < width; k++) k == data.column! ? Tetromino.empty : Tetromino.garbage]]; + board.insertAll(0, garbage); + board.removeRange(height-garbage.length, height); + } + + List clearFullLines(){ + int linesCleared = 0; + int garbageLines = 0; + int difficultLineClear = 0; + for (int i = 0; i < board.length; i++){ + if (board[i-linesCleared].every((element) => element != Tetromino.empty)){ + if (board[i-linesCleared].any((element) => element == Tetromino.garbage)) garbageLines++; + board.removeAt(i-linesCleared); + List emptyRow = [for (int t = 0; t < width; t++) Tetromino.empty]; + board.add(emptyRow); + linesCleared += 1; + } + } + if (linesCleared >= 4) difficultLineClear = 1; + return [linesCleared, garbageLines, difficultLineClear]; + } +} + +class IncomingGarbage{ + int? frameOfThreat; // will enter board after this frame, null if unconfirmed + GarbageData data; + + IncomingGarbage(this.data); + + @override + String toString(){ + return "f$frameOfThreat: col${data.column} amt${data.amt}"; + } + + void confirm(int confirmationFrame, int garbageSpeed){ + frameOfThreat = confirmationFrame+garbageSpeed; + } +} + +class LineClearResult{ + int linesCleared; + Tetromino piece; + bool spin; + int garbageCleared; + int column; + int attackProduced; + + LineClearResult(this.linesCleared, this.piece, this.spin, this.garbageCleared, this.column, this.attackProduced); +} + +class Stats{ + int combo = -1; + int btb = -1; + int attackRecived = 0; + int attackTanked = 0; + + LineClearResult processLineClear(List clearFullLinesResult, Tetromino current, Coords pos, bool spinWasLastMove, bool tspin){ + if (clearFullLinesResult[0] > 0) combo++; + else combo = -1; + if (clearFullLinesResult[2] > 0) btb++; + else btb = -1; + int attack = 0; + switch (clearFullLinesResult[0]){ + case 0: + if (spinWasLastMove && tspin) { + attack = garbage['t-spin']!; + } + break; + case 1: + if (spinWasLastMove && tspin) { + attack = garbage['t-spin single']!; + }else{ + attack = garbage['single']!; + } + break; + case 2: + if (spinWasLastMove && tspin) { + attack = garbage['t-spin double']!; + }else{ + attack = garbage['double']!; + } + break; + case 3: + if (spinWasLastMove && tspin) { + attack = garbage['t-spin triple']!; + }else{ + attack = garbage['triple']!; + } + break; + case 4: + if (spinWasLastMove && tspin) { + attack = garbage['t-spin quad']!; + }else{ + attack = garbage['quad']!; + } + break; + case 5: + if (spinWasLastMove && tspin) { + attack = garbage['t-spin penta']!; + }else{ + attack = garbage['penta']!; + } + break; + case _: + developer.log("${clearFullLinesResult[0]} lines cleared"); + break; + } + return LineClearResult(clearFullLinesResult[0], Tetromino.empty, false, clearFullLinesResult[1], 0, attack); + } } class Simulation{ @@ -150,9 +272,13 @@ void main() async { int currentFrame = 0; events.removeAt(0); // get rig of Event.start Event nextEvent = events.removeAt(0); - Board board = Board(10, 20, 20); + Stats stats = Stats(); + Board board = Board(10, 20, 20); + KicksetBase kickset = SRSPlus(); + List garbageQueue = []; Tetromino? hold; int rot = 0; + bool spinWasLastMove = false; Coords coords = Coords(3, 21); double gravityBucket = 0.00000000000000; @@ -180,6 +306,20 @@ void main() async { return queue.removeAt(0); } + bool handleRotation(int r){ + if (r == 0) return true; + int future_rotation = (rot + r) % 4; + List tests = (current == Tetromino.I ? kickset.kickTableI : kickset.kickTable)[rot][r == -1 ? 0 : r]; + for (Coords test in tests){ + if (board.positionIsValid(current, coords+test, future_rotation)){ + coords += test; + rot = future_rotation; + return true; + } + } + return false; + } + coords += spawnPositionFixes[current.index]; for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ gravityBucket += settings != null ? (handling!.sdfActive ? settings.g! * settings.handling!.sdf : settings.g!) : 0; @@ -194,7 +334,7 @@ void main() async { } if (board.positionIsValid(current, Coords(coords.x, coords.y-gravityImpact), rot)) coords.y -= gravityImpact; print("$currentFrame: $current at $coords\n$board"); - + //print(stats.combo); if (currentFrame == nextEvent.frame){ while (currentFrame == nextEvent.frame){ print("Processing $nextEvent"); @@ -212,13 +352,13 @@ void main() async { activeKeypresses[nextEvent.data.key] = nextEvent; switch (nextEvent.data.key){ case KeyType.rotateCCW: - rot = (rot-1)%4; + handleRotation(-1); break; case KeyType.rotateCW: - rot = (rot+1)%4; + handleRotation(1); break; case KeyType.rotate180: - rot = (rot+2)%4; + handleRotation(2); break; case KeyType.moveLeft: case KeyType.moveRight: @@ -231,9 +371,42 @@ void main() async { case KeyType.hardDrop: coords.y = sonicDrop(); board.writeToBoard(current, coords, rot); + bool tspin = board.wasATSpin(current, coords, rot); + LineClearResult lineClear = stats.processLineClear(board.clearFullLines(), current, coords, spinWasLastMove, tspin); + print("${lineClear.linesCleared} lines, ${lineClear.garbageCleared} garbage"); + if (garbageQueue.isNotEmpty) { + if (lineClear.linesCleared > 0){ + int garbageToDelete = lineClear.attackProduced; + for (IncomingGarbage garbage in garbageQueue){ + if (garbage.data.amt! >= garbageToDelete) { + garbageToDelete -= garbage.data.amt!; + lineClear.attackProduced = garbageToDelete; + garbage.data.amt = 0; + }else{ + garbage.data.amt = garbage.data.amt! - garbageToDelete; + lineClear.attackProduced = 0; + break; + } + } + }else{ + int needToTake = settings!.garbageCap!; + for (IncomingGarbage garbage in garbageQueue){ + if ((garbage.frameOfThreat??99999999) > currentFrame) break; + if (garbage.data.amt! > needToTake) { + board.writeGarbage(garbage.data, needToTake); + garbage.data.amt = garbage.data.amt! - needToTake; + break; + } else { + board.writeGarbage(garbage.data); + needToTake -= garbage.data.amt!; + garbage.data.amt = 0; + } + } + } + garbageQueue.removeWhere((element) => element.data.amt == 0); + } current = getNewOne(); coords = Coords(3, 21) + spawnPositionFixes[current.index]; - //handling!.movementKeyReleased(true, true); case KeyType.hold: switch (hold){ case null: @@ -247,6 +420,7 @@ void main() async { current = temp; break; } + rot = 0; coords = Coords(3, 21) + spawnPositionFixes[current.index]; break; case KeyType.chat: @@ -258,6 +432,11 @@ void main() async { default: developer.log(nextEvent.data.key.name); } + if (nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW){ + spinWasLastMove = true; + }else{ + spinWasLastMove = false; + } break; case EventType.keyup: nextEvent as EventKeyPress; @@ -292,6 +471,22 @@ void main() async { case EventType.end: currentFrame = replay.roundLengths[0]+1; break; + case EventType.ige: + nextEvent as EventIGE; + switch (nextEvent.data.data.type){ + case "interaction": + garbageQueue.add(IncomingGarbage((nextEvent.data.data as IGEdataInteraction).data)); + case "interaction_confirm": + GarbageData data = (nextEvent.data.data as IGEdataInteraction).data; + if(data.type != "targeted") garbageQueue.firstWhere((element) => element.data.iid == data.iid).confirm(currentFrame, settings!.garbageSpeed!); + case "allow_targeting": + case "target": + default: + developer.log("Unknown IGE type: ${nextEvent.data.type}", level: 900); + break; + } + // garbage speed counts from interaction comfirm + break; default: developer.log("Event wasn't processed: ${nextEvent}", level: 900); } diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index 4262c9d..9ff575a 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -590,6 +590,7 @@ class DataFullOptions{ gMargin = json["gmargin"]; gIncrease = json["gincrease"]; garbageMultiplier = json["garbagemultiplier"].toDouble(); + garbageCap = json["garbagecap"]; garbageCapIncrease = json["garbagecapincrease"].toDouble(); garbageCapMax = json["garbagecapmax"]; garbageHoleSize = json["garbageholesize"]; @@ -815,9 +816,9 @@ List>> shapes = [ [Coords(0, 1), Coords(1, 0), Coords(1, 1), Coords(1, 2)] ] ]; -List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(2, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; +List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(1, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; -const Map garbage = { +const Map garbage = { "single": 0, "double": 1, "triple": 2, @@ -840,3 +841,61 @@ double comboBonus = 0.25; int comboMinifier = 1; double comboMinifierLog = 1.25; List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; + +class KicksetBase { + List? additionalOffsets; + late List additionalOffsetEmpty; + List? spawnRotation; + late List>> kickTable; //kickTable[initRot][rotDirection-1][kick] + late List>> kickTableI; +} + +class SRSPlus extends KicksetBase{ + SRSPlus(){ + kickTable = [ + [ + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 270 + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 90 + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 180 + ], + [ + [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 0 + [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 180 + [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 270 + ], + [ + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 90 + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 270 + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 0 + ], + [ + [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 180 + [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 0 + [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 90 + ] + ]; + kickTableI = [ + [ + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 270 + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 90 + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 180 + ], + [ + [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 0 + [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 180 + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 90 -> 270 + ], + [ + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 90 + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 270 + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 0 + ], + [ + [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 180 + [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 0 + [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 90 + ] + ]; + additionalOffsetEmpty = [Coords( 0, 0),Coords( 0, 0),Coords( 0, 0),Coords( 0, 0)]; + } +} diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 8680e59..b3a845f 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -1184,7 +1184,7 @@ class _TwoRecordsThingy extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - for (int i = 1; i < sprintStream.records.length; i++) ListTile( + for (int i = 1; i < blitzStream.records.length; i++) ListTile( onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: blitzStream.records[i]))), leading: Text("#${i+1}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9) ), title: Text("${NumberFormat.decimalPattern().format(blitzStream.records[i].endContext.score)} points", From 1c29cce71b37f3e52ffc0a4393bc7393db6ecd64 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Fri, 5 Jul 2024 02:04:39 +0300 Subject: [PATCH 10/14] inf SDF, 0 ARR, fixed kicks for SRS+, yet softdrop still works like shit --- lib/data_objects/freyhoe_test.dart | 60 +++++++++++++------ .../tetrio_multiplayer_replay.dart | 32 +++++----- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 24f1cc7..af17440 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -40,8 +40,7 @@ class HandlingHandler{ return direction; } - int movementKeyReleased(bool left, bool right, double subframe){ - int lastFrameMovement = processMovenent(subframe); + void movementKeyReleased(bool left, bool right, double subframe){ if (left) { activeLeft = !left; } @@ -59,7 +58,6 @@ class HandlingHandler{ dasLeft = das; direction = 0; } - return lastFrameMovement; } int processMovenent(double delta){ @@ -75,6 +73,7 @@ class HandlingHandler{ } }else{ arrLeft -= delta; + if (arr == 0.0) return direction*10; if (arrLeft < 0.0) { arrLeft += arr; return direction; @@ -262,6 +261,8 @@ class Simulation{ // That thing allows me to test my new staff i'm trying to implement void main() async { var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); + // frame 994: garbage lost + // frame 1550: T-spin failed ReplayData replay = ReplayData.fromJson(replayJson); TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); List queue = rng.shuffleList(tetrominoes.toList()); @@ -270,6 +271,7 @@ void main() async { HandlingHandler? handling; Map activeKeypresses = {}; int currentFrame = 0; + double subframesWent = 0; events.removeAt(0); // get rig of Event.start Event nextEvent = events.removeAt(0); Stats stats = Stats(); @@ -308,31 +310,48 @@ void main() async { bool handleRotation(int r){ if (r == 0) return true; - int future_rotation = (rot + r) % 4; + int futureRotation = (rot + r) % 4; List tests = (current == Tetromino.I ? kickset.kickTableI : kickset.kickTable)[rot][r == -1 ? 0 : r]; for (Coords test in tests){ - if (board.positionIsValid(current, coords+test, future_rotation)){ + if (board.positionIsValid(current, coords+test, futureRotation)){ coords += test; - rot = future_rotation; + rot = futureRotation; return true; } } return false; } - coords += spawnPositionFixes[current.index]; - for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ - gravityBucket += settings != null ? (handling!.sdfActive ? settings.g! * settings.handling!.sdf : settings.g!) : 0; - - int movement = handling != null ? handling.processMovenent(1.0) : 0; - if (board.positionIsValid(current, Coords(coords.x+movement, coords.y), rot)) coords.x += movement; - + void handleGravity(double frames){ + if (frames == 0) return; + gravityBucket += settings != null ? (handling!.sdfActive ? settings.g! * settings.handling!.sdf : settings.g!) * frames : 0; int gravityImpact = 0; if (gravityBucket >= 1.0){ gravityImpact = gravityBucket.truncate(); gravityBucket -= gravityBucket.truncate(); } - if (board.positionIsValid(current, Coords(coords.x, coords.y-gravityImpact), rot)) coords.y -= gravityImpact; + while (gravityImpact > 0){ + if (board.positionIsValid(current, Coords(coords.x, coords.y-1), rot)) coords.y -= 1; + gravityImpact--; + } + } + + void handleMovement(double frames){ + if (frames == 0 || handling == null) return; + int movement = handling.processMovenent(frames); + while (movement.abs() > 0){ + if (board.positionIsValid(current, Coords(movement.isNegative ? coords.x-1 : coords.x+1, coords.y), rot)) movement.isNegative ? coords.x-- : coords.x++; + movement.isNegative ? movement++ : movement--; + } + } + + coords += spawnPositionFixes[current.index]; + for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ + handleMovement(1-subframesWent); + handleGravity(1-subframesWent); + subframesWent = 0; + + if (settings?.handling?.sdf == 41) coords.y = sonicDrop(); print("$currentFrame: $current at $coords\n$board"); //print(stats.combo); if (currentFrame == nextEvent.frame){ @@ -349,7 +368,11 @@ void main() async { break; case EventType.keydown: nextEvent as EventKeyPress; - activeKeypresses[nextEvent.data.key] = nextEvent; + double subframesDiff = nextEvent.data.subframe - subframesWent; + subframesWent += subframesDiff; + handleMovement(subframesDiff); + handleGravity(subframesDiff); + //activeKeypresses[nextEvent.data.key] = nextEvent; switch (nextEvent.data.key){ case KeyType.rotateCCW: handleRotation(-1); @@ -440,11 +463,14 @@ void main() async { break; case EventType.keyup: nextEvent as EventKeyPress; + double subframesDiff = nextEvent.data.subframe - subframesWent; + subframesWent += subframesDiff; + handleMovement(subframesDiff); + handleGravity(subframesDiff); switch (nextEvent.data.key){ case KeyType.moveLeft: case KeyType.moveRight: - int pontencialMovement = handling!.movementKeyReleased(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); - if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; + handling!.movementKeyReleased(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); break; case KeyType.softDrop: handling?.sdfActive = false; diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index 9ff575a..7f1a7a8 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -856,44 +856,44 @@ class SRSPlus extends KicksetBase{ [ [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 270 [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 90 - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 180 + [Coords( 0, 0), Coords( 0, 1), Coords( 1, 1), Coords(-1, 1), Coords( 1, 0), Coords(-1, 0)], // 0 -> 180 ], [ [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 0 [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 180 - [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 270 + [Coords( 0, 0), Coords( 1, 0), Coords( 1, 2), Coords( 1, 1), Coords( 0, 2), Coords( 0, 1)], // 90 -> 270 ], [ [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 90 [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 270 - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 0 + [Coords( 0, 0), Coords( 0,-1), Coords(-1,-1), Coords( 1,-1), Coords(-1, 0), Coords( 1, 0)], // 180 -> 0 ], [ [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 180 [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 0 - [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 90 + [Coords( 0, 0), Coords(-1, 0), Coords(-1, 2), Coords(-1, 1), Coords( 0, 2), Coords( 0, 1)], // 270 -> 90 ] ]; kickTableI = [ [ - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 270 - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 90 - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 180 + [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords( 2,-1), Coords(-1, 2)], // 0 -> 270 + [Coords( 0, 0), Coords( 1, 0), Coords( 2, 0), Coords(-1,-1), Coords( 1, 2)], // 0 -> 90 + [Coords( 0, 0), Coords( 0, 1)], // 0 -> 180 ], [ - [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 0 - [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 180 - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 90 -> 270 + [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords(-1,-2), Coords( 2,-1)], // 90 -> 0 + [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords(-1, 2), Coords( 2, 1)], // 90 -> 180 + [Coords( 0, 0), Coords( 1, 0)], // 90 -> 270 ], [ - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 90 - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 270 - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 0 + [Coords( 0, 0), Coords(-2, 0), Coords( 1, 0), Coords(-2, 1), Coords( 1,-2)], // 180 -> 90 + [Coords( 0, 0), Coords(-2, 0), Coords(-1, 0), Coords( 2, 1), Coords(-1,-2)], // 180 -> 270 + [Coords( 0, 0), Coords( 0,-1)], // 180 -> 0 ], [ - [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 180 - [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 0 - [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 90 + [Coords( 0, 0), Coords( 1, 0), Coords(-2, 0), Coords( 1, 2), Coords(-2,-1)], // 270 -> 180 + [Coords( 0, 0), Coords( 1, 0), Coords(-2, 0), Coords( 1,-2), Coords(-2, 1)], // 270 -> 0 + [Coords( 0, 0), Coords(-1, 0)], // 270 -> 90 ] ]; additionalOffsetEmpty = [Coords( 0, 0),Coords( 0, 0),Coords( 0, 0),Coords( 0, 0)]; From d34b072fcd6c7479cbbabb9438523de31e45c154 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Sun, 7 Jul 2024 01:39:15 +0300 Subject: [PATCH 11/14] whar? --- lib/data_objects/freyhoe_test.dart | 107 +++++++++++++++++------------ web/index.html | 66 +++++++++++++----- 2 files changed, 113 insertions(+), 60 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index af17440..e92fd96 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -282,7 +282,10 @@ void main() async { int rot = 0; bool spinWasLastMove = false; Coords coords = Coords(3, 21); - double gravityBucket = 0.00000000000000; + double lockDelay = 30; // frames + int lockResets = 15; + bool floored = false; + double gravityBucket = 1.0; developer.log("Seed is ${replay.stats[0][0].seed}, first bag is $queue"); Tetromino current = queue.removeAt(0); @@ -305,6 +308,10 @@ void main() async { } //developer.log("Next queue is $queue"); rot = 0; + lockResets = 15; + lockDelay = 30; + floored = false; + gravityBucket = 1.0; return queue.removeAt(0); } @@ -322,18 +329,63 @@ void main() async { return false; } + void handleHardDrop(){ + board.writeToBoard(current, coords, rot); + bool tspin = board.wasATSpin(current, coords, rot); + LineClearResult lineClear = stats.processLineClear(board.clearFullLines(), current, coords, spinWasLastMove, tspin); + print("${lineClear.linesCleared} lines, ${lineClear.garbageCleared} garbage"); + if (garbageQueue.isNotEmpty) { + if (lineClear.linesCleared > 0){ + int garbageToDelete = lineClear.attackProduced; + for (IncomingGarbage garbage in garbageQueue){ + if (garbage.data.amt! >= garbageToDelete) { + garbageToDelete -= garbage.data.amt!; + lineClear.attackProduced = garbageToDelete; + garbage.data.amt = 0; + }else{ + garbage.data.amt = garbage.data.amt! - garbageToDelete; + lineClear.attackProduced = 0; + break; + } + } + }else{ + int needToTake = settings!.garbageCap!; + for (IncomingGarbage garbage in garbageQueue){ + if ((garbage.frameOfThreat??99999999) > currentFrame) break; + if (garbage.data.amt! > needToTake) { + board.writeGarbage(garbage.data, needToTake); + garbage.data.amt = garbage.data.amt! - needToTake; + break; + } else { + board.writeGarbage(garbage.data); + needToTake -= garbage.data.amt!; + garbage.data.amt = 0; + } + } + } + garbageQueue.removeWhere((element) => element.data.amt == 0); + } + current = getNewOne(); + coords = Coords(3, 21) + spawnPositionFixes[current.index]; + } + void handleGravity(double frames){ if (frames == 0) return; - gravityBucket += settings != null ? (handling!.sdfActive ? settings.g! * settings.handling!.sdf : settings.g!) * frames : 0; + gravityBucket += settings != null ? (handling!.sdfActive ? max(settings.g! * settings.handling!.sdf, 0.05 * settings.handling!.sdf) : settings.g!) * frames : 0; int gravityImpact = 0; if (gravityBucket >= 1.0){ gravityImpact = gravityBucket.truncate(); gravityBucket -= gravityBucket.truncate(); } while (gravityImpact > 0){ - if (board.positionIsValid(current, Coords(coords.x, coords.y-1), rot)) coords.y -= 1; + if (board.positionIsValid(current, Coords(coords.x, coords.y-1), rot)) {coords.y -= 1; floored = false;} + else floored = true; gravityImpact--; } + if (floored) lockDelay -= frames; + if (lockDelay <= 0 && floored){ + handleHardDrop(); + } } void handleMovement(double frames){ @@ -364,7 +416,8 @@ void main() async { case EventType.full: settings = (nextEvent as EventFull).data.options; handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); - print(handling); + lockDelay = settings.locktime!.toDouble(); + lockResets = settings.lockresets!; break; case EventType.keydown: nextEvent as EventKeyPress; @@ -393,43 +446,7 @@ void main() async { break; case KeyType.hardDrop: coords.y = sonicDrop(); - board.writeToBoard(current, coords, rot); - bool tspin = board.wasATSpin(current, coords, rot); - LineClearResult lineClear = stats.processLineClear(board.clearFullLines(), current, coords, spinWasLastMove, tspin); - print("${lineClear.linesCleared} lines, ${lineClear.garbageCleared} garbage"); - if (garbageQueue.isNotEmpty) { - if (lineClear.linesCleared > 0){ - int garbageToDelete = lineClear.attackProduced; - for (IncomingGarbage garbage in garbageQueue){ - if (garbage.data.amt! >= garbageToDelete) { - garbageToDelete -= garbage.data.amt!; - lineClear.attackProduced = garbageToDelete; - garbage.data.amt = 0; - }else{ - garbage.data.amt = garbage.data.amt! - garbageToDelete; - lineClear.attackProduced = 0; - break; - } - } - }else{ - int needToTake = settings!.garbageCap!; - for (IncomingGarbage garbage in garbageQueue){ - if ((garbage.frameOfThreat??99999999) > currentFrame) break; - if (garbage.data.amt! > needToTake) { - board.writeGarbage(garbage.data, needToTake); - garbage.data.amt = garbage.data.amt! - needToTake; - break; - } else { - board.writeGarbage(garbage.data); - needToTake -= garbage.data.amt!; - garbage.data.amt = 0; - } - } - } - garbageQueue.removeWhere((element) => element.data.amt == 0); - } - current = getNewOne(); - coords = Coords(3, 21) + spawnPositionFixes[current.index]; + handleHardDrop(); case KeyType.hold: switch (hold){ case null: @@ -441,10 +458,14 @@ void main() async { temp = hold; hold = current; current = temp; + rot = 0; + lockResets = 15; + lockDelay = 30; + gravityBucket = 1.0; + floored = false; + coords = Coords(3, 21) + spawnPositionFixes[current.index]; break; } - rot = 0; - coords = Coords(3, 21) + spawnPositionFixes[current.index]; break; case KeyType.chat: // TODO: Handle this case. diff --git a/web/index.html b/web/index.html index 745bea0..ad7b67e 100644 --- a/web/index.html +++ b/web/index.html @@ -80,6 +80,9 @@ font-weight: 500; font-style: normal; } + a{ + color: aqua; + } #preloader{ display: flex; width: fit-content; @@ -111,6 +114,15 @@ padding-top: 8px; animation: 1s cubic-bezier(.46,.03,.52,.96) infinite alternate breathing; } + .error{ + color: red; + } + #tip{ + position: absolute; + bottom: 5%; + color: gray; + text-align: center; + } @media (max-width: 502px){ #preloader{ flex-direction: column; @@ -130,24 +142,44 @@

Loading...

- From 0e89b2bf3e5d9807bdc86605bb45bceb1320fb9a Mon Sep 17 00:00:00 2001 From: dan63047 Date: Wed, 10 Jul 2024 18:31:00 +0300 Subject: [PATCH 12/14] Season 1 end is near, 1.6.1 is here --- lib/data_objects/freyhoe_test.dart | 1030 +++++++-------- lib/data_objects/tetrio.dart | 14 +- .../tetrio_multiplayer_replay.dart | 1134 ++++++++--------- lib/gen/strings.g.dart | 10 +- lib/services/tetrio_crud.dart | 61 +- lib/views/main_view.dart | 3 +- lib/views/ranks_averages_view.dart | 5 +- lib/views/tl_leaderboard_view.dart | 18 +- lib/views/tl_match_view.dart | 2 +- lib/widgets/tl_rating_thingy.dart | 14 +- lib/widgets/tl_thingy.dart | 5 +- pubspec.yaml | 2 +- res/i18n/strings.i18n.json | 2 +- res/i18n/strings_ru.i18n.json | 2 +- web/index.html | 3 +- 15 files changed, 1132 insertions(+), 1173 deletions(-) diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index e92fd96..6b74a6b 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -1,551 +1,551 @@ -import 'dart:convert'; -import 'dart:developer' as developer; -import 'dart:ffi'; -import 'dart:math'; -import 'package:logging/logging.dart' as logging; -import 'package:vector_math/vector_math_64.dart'; -import 'dart:io'; -import 'tetrio_multiplayer_replay.dart'; +// import 'dart:convert'; +// import 'dart:developer' as developer; +// import 'dart:ffi'; +// import 'dart:math'; +// import 'package:logging/logging.dart' as logging; +// import 'package:vector_math/vector_math_64.dart'; +// import 'dart:io'; +// import 'tetrio_multiplayer_replay.dart'; -class HandlingHandler{ - double das; - double arr; - late double dasLeft; // frames - late double arrLeft; // frames - bool sdfActive = false; - bool activeLeft = false; - bool activeRight = false; - int direction = 0; // -1 - left, 1 - right, 0 - none +// class HandlingHandler{ +// double das; +// double arr; +// late double dasLeft; // frames +// late double arrLeft; // frames +// bool sdfActive = false; +// bool activeLeft = false; +// bool activeRight = false; +// int direction = 0; // -1 - left, 1 - right, 0 - none - HandlingHandler(this.das, this.arr){ - dasLeft = das; - arrLeft = arr; - } +// HandlingHandler(this.das, this.arr){ +// dasLeft = das; +// arrLeft = arr; +// } - @override - String toString(){ - return "das: ${das}f; arr: ${arr}f"; - } +// @override +// String toString(){ +// return "das: ${das}f; arr: ${arr}f"; +// } - int movementKeyPressed(bool left, bool right, double subframe){ - if (left) { - activeLeft = left; - direction = -1; - } - if (right) { - activeRight = right; - direction = 1; - } - dasLeft = das - (1 - subframe); - return direction; - } +// int movementKeyPressed(bool left, bool right, double subframe){ +// if (left) { +// activeLeft = left; +// direction = -1; +// } +// if (right) { +// activeRight = right; +// direction = 1; +// } +// dasLeft = das - (1 - subframe); +// return direction; +// } - void movementKeyReleased(bool left, bool right, double subframe){ - if (left) { - activeLeft = !left; - } - if (right) { - activeRight = !right; - } - if (activeLeft) { - direction = -1; - } - if (activeRight) { - direction = 1; - } - if (activeLeft && activeRight){ - arrLeft = arr; - dasLeft = das; - direction = 0; - } - } +// void movementKeyReleased(bool left, bool right, double subframe){ +// if (left) { +// activeLeft = !left; +// } +// if (right) { +// activeRight = !right; +// } +// if (activeLeft) { +// direction = -1; +// } +// if (activeRight) { +// direction = 1; +// } +// if (activeLeft && activeRight){ +// arrLeft = arr; +// dasLeft = das; +// direction = 0; +// } +// } - int processMovenent(double delta){ - if (!activeLeft && !activeRight) return 0; - if (dasLeft > 0.0) { - dasLeft -= delta; - if (dasLeft < 0.0) { - arrLeft += dasLeft; - dasLeft = 0.0; - return direction; - }else{ - return 0; - } - }else{ - arrLeft -= delta; - if (arr == 0.0) return direction*10; - if (arrLeft < 0.0) { - arrLeft += arr; - return direction; - }else { - return 0; - } - } - } -} +// int processMovenent(double delta){ +// if (!activeLeft && !activeRight) return 0; +// if (dasLeft > 0.0) { +// dasLeft -= delta; +// if (dasLeft < 0.0) { +// arrLeft += dasLeft; +// dasLeft = 0.0; +// return direction; +// }else{ +// return 0; +// } +// }else{ +// arrLeft -= delta; +// if (arr == 0.0) return direction*10; +// if (arrLeft < 0.0) { +// arrLeft += arr; +// return direction; +// }else { +// return 0; +// } +// } +// } +// } -class Board{ - int width; - int height; - int bufferHeight; - late List> board; - late int totalHeight; +// class Board{ +// int width; +// int height; +// int bufferHeight; +// late List> board; +// late int totalHeight; - Board(this.width, this.height, this.bufferHeight){ - totalHeight = height+bufferHeight; - board = [for (var i = 0 ; i < totalHeight; i++) [for (var i = 0 ; i < width; i++) Tetromino.empty]]; - } +// Board(this.width, this.height, this.bufferHeight){ +// totalHeight = height+bufferHeight; +// board = [for (var i = 0 ; i < totalHeight; i++) [for (var i = 0 ; i < width; i++) Tetromino.empty]]; +// } - @override - String toString() { - String result = ""; - for (var row in board.reversed){ - for (var cell in row) result += cell.name[0]; - result += "\n"; - } - return result; - } +// @override +// String toString() { +// String result = ""; +// for (var row in board.reversed){ +// for (var cell in row) result += cell.name[0]; +// result += "\n"; +// } +// return result; +// } - bool isOccupied(Coords coords) - { - if (coords.x < 0 || coords.x >= width || - coords.y < 0 || coords.y >= totalHeight || - board[coords.y][coords.x] != Tetromino.empty) return true; - return false; - } +// bool isOccupied(Coords coords) +// { +// if (coords.x < 0 || coords.x >= width || +// coords.y < 0 || coords.y >= totalHeight || +// board[coords.y][coords.x] != Tetromino.empty) return true; +// return false; +// } - bool positionIsValid(Tetromino type, Coords coords, int r){ - List shape = shapes[type.index][r]; - for (Coords mino in shape){ - if (isOccupied(coords+mino)) return false; - } - return true; - } +// bool positionIsValid(Tetromino type, Coords coords, int r){ +// List shape = shapes[type.index][r]; +// for (Coords mino in shape){ +// if (isOccupied(coords+mino)) return false; +// } +// return true; +// } - bool wasATSpin(Tetromino type, Coords coords, int rot){ - if (!(positionIsValid(type, Coords(coords.x+1, coords.y), rot) || - positionIsValid(type, Coords(coords.x-1, coords.y), rot) || - positionIsValid(type, Coords(coords.x, coords.y+1), rot) || - positionIsValid(type, Coords(coords.x, coords.y-1), rot)) - ){ - return true; - } - return false; - } +// bool wasATSpin(Tetromino type, Coords coords, int rot){ +// if (!(positionIsValid(type, Coords(coords.x+1, coords.y), rot) || +// positionIsValid(type, Coords(coords.x-1, coords.y), rot) || +// positionIsValid(type, Coords(coords.x, coords.y+1), rot) || +// positionIsValid(type, Coords(coords.x, coords.y-1), rot)) +// ){ +// return true; +// } +// return false; +// } - void writeToBoard(Tetromino type, Coords coords, int rot) { - if (!positionIsValid(type, coords, rot)) throw Exception("Attempted to write $type to $coords in $rot rot"); - List shape = shapes[type.index][rot]; - for (Coords mino in shape){ - var finalCoords = coords+mino; - board[finalCoords.y][finalCoords.x] = type; - } - } +// void writeToBoard(Tetromino type, Coords coords, int rot) { +// if (!positionIsValid(type, coords, rot)) throw Exception("Attempted to write $type to $coords in $rot rot"); +// List shape = shapes[type.index][rot]; +// for (Coords mino in shape){ +// var finalCoords = coords+mino; +// board[finalCoords.y][finalCoords.x] = type; +// } +// } - void writeGarbage(GarbageData data, [int? amt]){ - List> garbage = [for (int i = 0; i < (amt??data.amt!); i++) [for (int k = 0; k < width; k++) k == data.column! ? Tetromino.empty : Tetromino.garbage]]; - board.insertAll(0, garbage); - board.removeRange(height-garbage.length, height); - } +// void writeGarbage(GarbageData data, [int? amt]){ +// List> garbage = [for (int i = 0; i < (amt??data.amt!); i++) [for (int k = 0; k < width; k++) k == data.column! ? Tetromino.empty : Tetromino.garbage]]; +// board.insertAll(0, garbage); +// board.removeRange(height-garbage.length, height); +// } - List clearFullLines(){ - int linesCleared = 0; - int garbageLines = 0; - int difficultLineClear = 0; - for (int i = 0; i < board.length; i++){ - if (board[i-linesCleared].every((element) => element != Tetromino.empty)){ - if (board[i-linesCleared].any((element) => element == Tetromino.garbage)) garbageLines++; - board.removeAt(i-linesCleared); - List emptyRow = [for (int t = 0; t < width; t++) Tetromino.empty]; - board.add(emptyRow); - linesCleared += 1; - } - } - if (linesCleared >= 4) difficultLineClear = 1; - return [linesCleared, garbageLines, difficultLineClear]; - } -} +// List clearFullLines(){ +// int linesCleared = 0; +// int garbageLines = 0; +// int difficultLineClear = 0; +// for (int i = 0; i < board.length; i++){ +// if (board[i-linesCleared].every((element) => element != Tetromino.empty)){ +// if (board[i-linesCleared].any((element) => element == Tetromino.garbage)) garbageLines++; +// board.removeAt(i-linesCleared); +// List emptyRow = [for (int t = 0; t < width; t++) Tetromino.empty]; +// board.add(emptyRow); +// linesCleared += 1; +// } +// } +// if (linesCleared >= 4) difficultLineClear = 1; +// return [linesCleared, garbageLines, difficultLineClear]; +// } +// } -class IncomingGarbage{ - int? frameOfThreat; // will enter board after this frame, null if unconfirmed - GarbageData data; +// class IncomingGarbage{ +// int? frameOfThreat; // will enter board after this frame, null if unconfirmed +// GarbageData data; - IncomingGarbage(this.data); +// IncomingGarbage(this.data); - @override - String toString(){ - return "f$frameOfThreat: col${data.column} amt${data.amt}"; - } +// @override +// String toString(){ +// return "f$frameOfThreat: col${data.column} amt${data.amt}"; +// } - void confirm(int confirmationFrame, int garbageSpeed){ - frameOfThreat = confirmationFrame+garbageSpeed; - } -} +// void confirm(int confirmationFrame, int garbageSpeed){ +// frameOfThreat = confirmationFrame+garbageSpeed; +// } +// } -class LineClearResult{ - int linesCleared; - Tetromino piece; - bool spin; - int garbageCleared; - int column; - int attackProduced; +// class LineClearResult{ +// int linesCleared; +// Tetromino piece; +// bool spin; +// int garbageCleared; +// int column; +// int attackProduced; - LineClearResult(this.linesCleared, this.piece, this.spin, this.garbageCleared, this.column, this.attackProduced); -} +// LineClearResult(this.linesCleared, this.piece, this.spin, this.garbageCleared, this.column, this.attackProduced); +// } -class Stats{ - int combo = -1; - int btb = -1; - int attackRecived = 0; - int attackTanked = 0; +// class Stats{ +// int combo = -1; +// int btb = -1; +// int attackRecived = 0; +// int attackTanked = 0; - LineClearResult processLineClear(List clearFullLinesResult, Tetromino current, Coords pos, bool spinWasLastMove, bool tspin){ - if (clearFullLinesResult[0] > 0) combo++; - else combo = -1; - if (clearFullLinesResult[2] > 0) btb++; - else btb = -1; - int attack = 0; - switch (clearFullLinesResult[0]){ - case 0: - if (spinWasLastMove && tspin) { - attack = garbage['t-spin']!; - } - break; - case 1: - if (spinWasLastMove && tspin) { - attack = garbage['t-spin single']!; - }else{ - attack = garbage['single']!; - } - break; - case 2: - if (spinWasLastMove && tspin) { - attack = garbage['t-spin double']!; - }else{ - attack = garbage['double']!; - } - break; - case 3: - if (spinWasLastMove && tspin) { - attack = garbage['t-spin triple']!; - }else{ - attack = garbage['triple']!; - } - break; - case 4: - if (spinWasLastMove && tspin) { - attack = garbage['t-spin quad']!; - }else{ - attack = garbage['quad']!; - } - break; - case 5: - if (spinWasLastMove && tspin) { - attack = garbage['t-spin penta']!; - }else{ - attack = garbage['penta']!; - } - break; - case _: - developer.log("${clearFullLinesResult[0]} lines cleared"); - break; - } - return LineClearResult(clearFullLinesResult[0], Tetromino.empty, false, clearFullLinesResult[1], 0, attack); - } -} +// LineClearResult processLineClear(List clearFullLinesResult, Tetromino current, Coords pos, bool spinWasLastMove, bool tspin){ +// if (clearFullLinesResult[0] > 0) combo++; +// else combo = -1; +// if (clearFullLinesResult[2] > 0) btb++; +// else btb = -1; +// int attack = 0; +// switch (clearFullLinesResult[0]){ +// case 0: +// if (spinWasLastMove && tspin) { +// attack = garbage['t-spin']!; +// } +// break; +// case 1: +// if (spinWasLastMove && tspin) { +// attack = garbage['t-spin single']!; +// }else{ +// attack = garbage['single']!; +// } +// break; +// case 2: +// if (spinWasLastMove && tspin) { +// attack = garbage['t-spin double']!; +// }else{ +// attack = garbage['double']!; +// } +// break; +// case 3: +// if (spinWasLastMove && tspin) { +// attack = garbage['t-spin triple']!; +// }else{ +// attack = garbage['triple']!; +// } +// break; +// case 4: +// if (spinWasLastMove && tspin) { +// attack = garbage['t-spin quad']!; +// }else{ +// attack = garbage['quad']!; +// } +// break; +// case 5: +// if (spinWasLastMove && tspin) { +// attack = garbage['t-spin penta']!; +// }else{ +// attack = garbage['penta']!; +// } +// break; +// case _: +// developer.log("${clearFullLinesResult[0]} lines cleared"); +// break; +// } +// return LineClearResult(clearFullLinesResult[0], Tetromino.empty, false, clearFullLinesResult[1], 0, attack); +// } +// } -class Simulation{ +// class Simulation{ -} +// } -// That thing allows me to test my new staff i'm trying to implement -void main() async { - var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); - // frame 994: garbage lost - // frame 1550: T-spin failed - ReplayData replay = ReplayData.fromJson(replayJson); - TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); - List queue = rng.shuffleList(tetrominoes.toList()); - List events = readEventList(replay.rawJson); - DataFullOptions? settings; - HandlingHandler? handling; - Map activeKeypresses = {}; - int currentFrame = 0; - double subframesWent = 0; - events.removeAt(0); // get rig of Event.start - Event nextEvent = events.removeAt(0); - Stats stats = Stats(); - Board board = Board(10, 20, 20); - KicksetBase kickset = SRSPlus(); - List garbageQueue = []; - Tetromino? hold; - int rot = 0; - bool spinWasLastMove = false; - Coords coords = Coords(3, 21); - double lockDelay = 30; // frames - int lockResets = 15; - bool floored = false; - double gravityBucket = 1.0; +// // That thing allows me to test my new staff i'm trying to implement +// void main() async { +// var replayJson = jsonDecode(File("/home/dan63047/Документы/replays/6550eecf2ffc5604e6224fc5.ttrm").readAsStringSync()); +// // frame 994: garbage lost +// // frame 1550: T-spin failed +// ReplayData replay = ReplayData.fromJson(replayJson); +// TetrioRNG rng = TetrioRNG(replay.stats[0][0].seed); +// List queue = rng.shuffleList(tetrominoes.toList()); +// List events = readEventList(replay.rawJson); +// DataFullOptions? settings; +// HandlingHandler? handling; +// Map activeKeypresses = {}; +// int currentFrame = 0; +// double subframesWent = 0; +// events.removeAt(0); // get rig of Event.start +// Event nextEvent = events.removeAt(0); +// Stats stats = Stats(); +// Board board = Board(10, 20, 20); +// KicksetBase kickset = SRSPlus(); +// List garbageQueue = []; +// Tetromino? hold; +// int rot = 0; +// bool spinWasLastMove = false; +// Coords coords = Coords(3, 21); +// double lockDelay = 30; // frames +// int lockResets = 15; +// bool floored = false; +// double gravityBucket = 1.0; - developer.log("Seed is ${replay.stats[0][0].seed}, first bag is $queue"); - Tetromino current = queue.removeAt(0); - //developer.log("Second bag is ${rng.shuffleList(tetrominoes)}"); +// developer.log("Seed is ${replay.stats[0][0].seed}, first bag is $queue"); +// Tetromino current = queue.removeAt(0); +// //developer.log("Second bag is ${rng.shuffleList(tetrominoes)}"); - int sonicDrop(){ - int height = coords.y; - while (board.positionIsValid(current, Coords(coords.x, height), rot)){ - height -= 1; - } - height += 1; - return height; - } +// int sonicDrop(){ +// int height = coords.y; +// while (board.positionIsValid(current, Coords(coords.x, height), rot)){ +// height -= 1; +// } +// height += 1; +// return height; +// } - Tetromino getNewOne(){ +// Tetromino getNewOne(){ - if (queue.length <= 1) { - List nextPieces = rng.shuffleList(tetrominoes.toList()); - queue.addAll(nextPieces); - } - //developer.log("Next queue is $queue"); - rot = 0; - lockResets = 15; - lockDelay = 30; - floored = false; - gravityBucket = 1.0; - return queue.removeAt(0); - } +// if (queue.length <= 1) { +// List nextPieces = rng.shuffleList(tetrominoes.toList()); +// queue.addAll(nextPieces); +// } +// //developer.log("Next queue is $queue"); +// rot = 0; +// lockResets = 15; +// lockDelay = 30; +// floored = false; +// gravityBucket = 1.0; +// return queue.removeAt(0); +// } - bool handleRotation(int r){ - if (r == 0) return true; - int futureRotation = (rot + r) % 4; - List tests = (current == Tetromino.I ? kickset.kickTableI : kickset.kickTable)[rot][r == -1 ? 0 : r]; - for (Coords test in tests){ - if (board.positionIsValid(current, coords+test, futureRotation)){ - coords += test; - rot = futureRotation; - return true; - } - } - return false; - } +// bool handleRotation(int r){ +// if (r == 0) return true; +// int futureRotation = (rot + r) % 4; +// List tests = (current == Tetromino.I ? kickset.kickTableI : kickset.kickTable)[rot][r == -1 ? 0 : r]; +// for (Coords test in tests){ +// if (board.positionIsValid(current, coords+test, futureRotation)){ +// coords += test; +// rot = futureRotation; +// return true; +// } +// } +// return false; +// } - void handleHardDrop(){ - board.writeToBoard(current, coords, rot); - bool tspin = board.wasATSpin(current, coords, rot); - LineClearResult lineClear = stats.processLineClear(board.clearFullLines(), current, coords, spinWasLastMove, tspin); - print("${lineClear.linesCleared} lines, ${lineClear.garbageCleared} garbage"); - if (garbageQueue.isNotEmpty) { - if (lineClear.linesCleared > 0){ - int garbageToDelete = lineClear.attackProduced; - for (IncomingGarbage garbage in garbageQueue){ - if (garbage.data.amt! >= garbageToDelete) { - garbageToDelete -= garbage.data.amt!; - lineClear.attackProduced = garbageToDelete; - garbage.data.amt = 0; - }else{ - garbage.data.amt = garbage.data.amt! - garbageToDelete; - lineClear.attackProduced = 0; - break; - } - } - }else{ - int needToTake = settings!.garbageCap!; - for (IncomingGarbage garbage in garbageQueue){ - if ((garbage.frameOfThreat??99999999) > currentFrame) break; - if (garbage.data.amt! > needToTake) { - board.writeGarbage(garbage.data, needToTake); - garbage.data.amt = garbage.data.amt! - needToTake; - break; - } else { - board.writeGarbage(garbage.data); - needToTake -= garbage.data.amt!; - garbage.data.amt = 0; - } - } - } - garbageQueue.removeWhere((element) => element.data.amt == 0); - } - current = getNewOne(); - coords = Coords(3, 21) + spawnPositionFixes[current.index]; - } +// void handleHardDrop(){ +// board.writeToBoard(current, coords, rot); +// bool tspin = board.wasATSpin(current, coords, rot); +// LineClearResult lineClear = stats.processLineClear(board.clearFullLines(), current, coords, spinWasLastMove, tspin); +// print("${lineClear.linesCleared} lines, ${lineClear.garbageCleared} garbage"); +// if (garbageQueue.isNotEmpty) { +// if (lineClear.linesCleared > 0){ +// int garbageToDelete = lineClear.attackProduced; +// for (IncomingGarbage garbage in garbageQueue){ +// if (garbage.data.amt! >= garbageToDelete) { +// garbageToDelete -= garbage.data.amt!; +// lineClear.attackProduced = garbageToDelete; +// garbage.data.amt = 0; +// }else{ +// garbage.data.amt = garbage.data.amt! - garbageToDelete; +// lineClear.attackProduced = 0; +// break; +// } +// } +// }else{ +// int needToTake = settings!.garbageCap!; +// for (IncomingGarbage garbage in garbageQueue){ +// if ((garbage.frameOfThreat??99999999) > currentFrame) break; +// if (garbage.data.amt! > needToTake) { +// board.writeGarbage(garbage.data, needToTake); +// garbage.data.amt = garbage.data.amt! - needToTake; +// break; +// } else { +// board.writeGarbage(garbage.data); +// needToTake -= garbage.data.amt!; +// garbage.data.amt = 0; +// } +// } +// } +// garbageQueue.removeWhere((element) => element.data.amt == 0); +// } +// current = getNewOne(); +// coords = Coords(3, 21) + spawnPositionFixes[current.index]; +// } - void handleGravity(double frames){ - if (frames == 0) return; - gravityBucket += settings != null ? (handling!.sdfActive ? max(settings.g! * settings.handling!.sdf, 0.05 * settings.handling!.sdf) : settings.g!) * frames : 0; - int gravityImpact = 0; - if (gravityBucket >= 1.0){ - gravityImpact = gravityBucket.truncate(); - gravityBucket -= gravityBucket.truncate(); - } - while (gravityImpact > 0){ - if (board.positionIsValid(current, Coords(coords.x, coords.y-1), rot)) {coords.y -= 1; floored = false;} - else floored = true; - gravityImpact--; - } - if (floored) lockDelay -= frames; - if (lockDelay <= 0 && floored){ - handleHardDrop(); - } - } +// void handleGravity(double frames){ +// if (frames == 0) return; +// gravityBucket += settings != null ? (handling!.sdfActive ? max(settings.g! * settings.handling!.sdf, 0.05 * settings.handling!.sdf) : settings.g!) * frames : 0; +// int gravityImpact = 0; +// if (gravityBucket >= 1.0){ +// gravityImpact = gravityBucket.truncate(); +// gravityBucket -= gravityBucket.truncate(); +// } +// while (gravityImpact > 0){ +// if (board.positionIsValid(current, Coords(coords.x, coords.y-1), rot)) {coords.y -= 1; floored = false;} +// else floored = true; +// gravityImpact--; +// } +// if (floored) lockDelay -= frames; +// if (lockDelay <= 0 && floored){ +// handleHardDrop(); +// } +// } - void handleMovement(double frames){ - if (frames == 0 || handling == null) return; - int movement = handling.processMovenent(frames); - while (movement.abs() > 0){ - if (board.positionIsValid(current, Coords(movement.isNegative ? coords.x-1 : coords.x+1, coords.y), rot)) movement.isNegative ? coords.x-- : coords.x++; - movement.isNegative ? movement++ : movement--; - } - } +// void handleMovement(double frames){ +// if (frames == 0 || handling == null) return; +// int movement = handling.processMovenent(frames); +// while (movement.abs() > 0){ +// if (board.positionIsValid(current, Coords(movement.isNegative ? coords.x-1 : coords.x+1, coords.y), rot)) movement.isNegative ? coords.x-- : coords.x++; +// movement.isNegative ? movement++ : movement--; +// } +// } - coords += spawnPositionFixes[current.index]; - for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ - handleMovement(1-subframesWent); - handleGravity(1-subframesWent); - subframesWent = 0; +// coords += spawnPositionFixes[current.index]; +// for (currentFrame; currentFrame <= replay.roundLengths[0]; currentFrame++){ +// handleMovement(1-subframesWent); +// handleGravity(1-subframesWent); +// subframesWent = 0; - if (settings?.handling?.sdf == 41) coords.y = sonicDrop(); - print("$currentFrame: $current at $coords\n$board"); - //print(stats.combo); - if (currentFrame == nextEvent.frame){ - while (currentFrame == nextEvent.frame){ - print("Processing $nextEvent"); - switch (nextEvent.type){ - case EventType.start: - developer.log("go"); - break; - case EventType.full: - settings = (nextEvent as EventFull).data.options; - handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); - lockDelay = settings.locktime!.toDouble(); - lockResets = settings.lockresets!; - break; - case EventType.keydown: - nextEvent as EventKeyPress; - double subframesDiff = nextEvent.data.subframe - subframesWent; - subframesWent += subframesDiff; - handleMovement(subframesDiff); - handleGravity(subframesDiff); - //activeKeypresses[nextEvent.data.key] = nextEvent; - switch (nextEvent.data.key){ - case KeyType.rotateCCW: - handleRotation(-1); - break; - case KeyType.rotateCW: - handleRotation(1); - break; - case KeyType.rotate180: - handleRotation(2); - break; - case KeyType.moveLeft: - case KeyType.moveRight: - int pontencialMovement = handling!.movementKeyPressed(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); - if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; - break; - case KeyType.softDrop: - handling!.sdfActive = true; - break; - case KeyType.hardDrop: - coords.y = sonicDrop(); - handleHardDrop(); - case KeyType.hold: - switch (hold){ - case null: - hold = current; - current = getNewOne(); - break; - case _: - Tetromino temp; - temp = hold; - hold = current; - current = temp; - rot = 0; - lockResets = 15; - lockDelay = 30; - gravityBucket = 1.0; - floored = false; - coords = Coords(3, 21) + spawnPositionFixes[current.index]; - break; - } - break; - case KeyType.chat: - // TODO: Handle this case. - case KeyType.exit: - // TODO: Handle this case. - case KeyType.retry: - // TODO: Handle this case. - default: - developer.log(nextEvent.data.key.name); - } - if (nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW){ - spinWasLastMove = true; - }else{ - spinWasLastMove = false; - } - break; - case EventType.keyup: - nextEvent as EventKeyPress; - double subframesDiff = nextEvent.data.subframe - subframesWent; - subframesWent += subframesDiff; - handleMovement(subframesDiff); - handleGravity(subframesDiff); - switch (nextEvent.data.key){ - case KeyType.moveLeft: - case KeyType.moveRight: - handling!.movementKeyReleased(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); - break; - case KeyType.softDrop: - handling?.sdfActive = false; - break; - case KeyType.rotateCCW: - // TODO: Handle this case. - case KeyType.rotateCW: - // TODO: Handle this case. - case KeyType.rotate180: - // TODO: Handle this case. - case KeyType.hardDrop: - // TODO: Handle this case. - case KeyType.hold: - // TODO: Handle this case. - case KeyType.chat: - // TODO: Handle this case. - case KeyType.exit: - // TODO: Handle this case. - case KeyType.retry: - // TODO: Handle this case. - } - activeKeypresses.remove(nextEvent.data.key); - break; - case EventType.end: - currentFrame = replay.roundLengths[0]+1; - break; - case EventType.ige: - nextEvent as EventIGE; - switch (nextEvent.data.data.type){ - case "interaction": - garbageQueue.add(IncomingGarbage((nextEvent.data.data as IGEdataInteraction).data)); - case "interaction_confirm": - GarbageData data = (nextEvent.data.data as IGEdataInteraction).data; - if(data.type != "targeted") garbageQueue.firstWhere((element) => element.data.iid == data.iid).confirm(currentFrame, settings!.garbageSpeed!); - case "allow_targeting": - case "target": - default: - developer.log("Unknown IGE type: ${nextEvent.data.type}", level: 900); - break; - } - // garbage speed counts from interaction comfirm - break; - default: - developer.log("Event wasn't processed: ${nextEvent}", level: 900); - } - try{ - nextEvent = events.removeAt(0); - } - catch (e){ - developer.log(e.toString()); - } - } - //developer.log("Next is: $nextEvent"); - } - } - exit(0); -} \ No newline at end of file +// if (settings?.handling?.sdf == 41) coords.y = sonicDrop(); +// print("$currentFrame: $current at $coords\n$board"); +// //print(stats.combo); +// if (currentFrame == nextEvent.frame){ +// while (currentFrame == nextEvent.frame){ +// print("Processing $nextEvent"); +// switch (nextEvent.type){ +// case EventType.start: +// developer.log("go"); +// break; +// case EventType.full: +// settings = (nextEvent as EventFull).data.options; +// handling = HandlingHandler(settings!.handling!.das.toDouble(), settings.handling!.arr.toDouble()); +// lockDelay = settings.locktime!.toDouble(); +// lockResets = settings.lockresets!; +// break; +// case EventType.keydown: +// nextEvent as EventKeyPress; +// double subframesDiff = nextEvent.data.subframe - subframesWent; +// subframesWent += subframesDiff; +// handleMovement(subframesDiff); +// handleGravity(subframesDiff); +// //activeKeypresses[nextEvent.data.key] = nextEvent; +// switch (nextEvent.data.key){ +// case KeyType.rotateCCW: +// handleRotation(-1); +// break; +// case KeyType.rotateCW: +// handleRotation(1); +// break; +// case KeyType.rotate180: +// handleRotation(2); +// break; +// case KeyType.moveLeft: +// case KeyType.moveRight: +// int pontencialMovement = handling!.movementKeyPressed(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); +// if (board.positionIsValid(current, Coords(coords.x+pontencialMovement, coords.y), rot)) coords.x += pontencialMovement; +// break; +// case KeyType.softDrop: +// handling!.sdfActive = true; +// break; +// case KeyType.hardDrop: +// coords.y = sonicDrop(); +// handleHardDrop(); +// case KeyType.hold: +// switch (hold){ +// case null: +// hold = current; +// current = getNewOne(); +// break; +// case _: +// Tetromino temp; +// temp = hold; +// hold = current; +// current = temp; +// rot = 0; +// lockResets = 15; +// lockDelay = 30; +// gravityBucket = 1.0; +// floored = false; +// coords = Coords(3, 21) + spawnPositionFixes[current.index]; +// break; +// } +// break; +// case KeyType.chat: +// // TODO: Handle this case. +// case KeyType.exit: +// // TODO: Handle this case. +// case KeyType.retry: +// // TODO: Handle this case. +// default: +// developer.log(nextEvent.data.key.name); +// } +// if (nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW && nextEvent.data.key == KeyType.rotateCW){ +// spinWasLastMove = true; +// }else{ +// spinWasLastMove = false; +// } +// break; +// case EventType.keyup: +// nextEvent as EventKeyPress; +// double subframesDiff = nextEvent.data.subframe - subframesWent; +// subframesWent += subframesDiff; +// handleMovement(subframesDiff); +// handleGravity(subframesDiff); +// switch (nextEvent.data.key){ +// case KeyType.moveLeft: +// case KeyType.moveRight: +// handling!.movementKeyReleased(nextEvent.data.key == KeyType.moveLeft, nextEvent.data.key == KeyType.moveRight, nextEvent.data.subframe); +// break; +// case KeyType.softDrop: +// handling?.sdfActive = false; +// break; +// case KeyType.rotateCCW: +// // TODO: Handle this case. +// case KeyType.rotateCW: +// // TODO: Handle this case. +// case KeyType.rotate180: +// // TODO: Handle this case. +// case KeyType.hardDrop: +// // TODO: Handle this case. +// case KeyType.hold: +// // TODO: Handle this case. +// case KeyType.chat: +// // TODO: Handle this case. +// case KeyType.exit: +// // TODO: Handle this case. +// case KeyType.retry: +// // TODO: Handle this case. +// } +// activeKeypresses.remove(nextEvent.data.key); +// break; +// case EventType.end: +// currentFrame = replay.roundLengths[0]+1; +// break; +// case EventType.ige: +// nextEvent as EventIGE; +// switch (nextEvent.data.data.type){ +// case "interaction": +// garbageQueue.add(IncomingGarbage((nextEvent.data.data as IGEdataInteraction).data)); +// case "interaction_confirm": +// GarbageData data = (nextEvent.data.data as IGEdataInteraction).data; +// if(data.type != "targeted") garbageQueue.firstWhere((element) => element.data.iid == data.iid).confirm(currentFrame, settings!.garbageSpeed!); +// case "allow_targeting": +// case "target": +// default: +// developer.log("Unknown IGE type: ${nextEvent.data.type}", level: 900); +// break; +// } +// // garbage speed counts from interaction comfirm +// break; +// default: +// developer.log("Event wasn't processed: ${nextEvent}", level: 900); +// } +// try{ +// nextEvent = events.removeAt(0); +// } +// catch (e){ +// developer.log(e.toString()); +// } +// } +// //developer.log("Next is: $nextEvent"); +// } +// } +// exit(0); +// } \ No newline at end of file diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart index e89b2cf..eeff63b 100644 --- a/lib/data_objects/tetrio.dart +++ b/lib/data_objects/tetrio.dart @@ -897,9 +897,9 @@ class TetraLeagueAlphaRecord{ TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext, required this.replayAvalable}); TetraLeagueAlphaRecord.fromJson(Map json) { - ownId = json['_id']; endContext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])]; replayId = json['replayid']; + ownId = json['_id']??replayId; timestamp = DateTime.parse(json['ts']); replayAvalable = true; } @@ -973,19 +973,19 @@ class EndContextMulti { EndContextMulti.fromJson(Map json) { userId = json['id'] ?? json['user']['_id']; username = json['username'] ?? json['user']['username']; - handling = Handling.fromJson(json['handling']); + 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']; - piecesPlaced = json['piecesplaced']; + 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'].map((e) => e.toDouble()).toList(); - tertiaryTracking = json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList(); + 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']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList(); + 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); diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index 7f1a7a8..9b521ad 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -269,633 +269,633 @@ class ReplayData{ // can't belive i have to implement that difficult shit -List readEventList(Map json){ - List events = []; - int id = 0; - for (var event in json['data'][0]['replays'][0]['events']){ - int frame = event["frame"]; - EventType type = EventType.values.byName(event['type']); - switch (type) { - case EventType.start: - events.add(Event(id, frame, type)); - break; - case EventType.full: - events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); - break; - case EventType.targets: - events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); - break; - case EventType.keydown: - events.add(EventKeyPress(id, frame, type, - Keypress( - KeyType.values.byName(event['data']['key']), - event['data']['subframe'], - false) - )); - break; - case EventType.keyup: - events.add(EventKeyPress(id, frame, type, - Keypress( - KeyType.values.byName(event['data']['key']), - event['data']['subframe'], - true) - )); - break; - case EventType.end: - events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); - break; - case EventType.ige: - events.add(EventIGE(id, frame, type, IGE( - event['data']['id'], - event['data']['frame'], - event['data']['type'], - event['data']['data'] - )) - ); - break; - case EventType.exit: - events.add(Event(id, frame, type)); - break; - } - id++; - } - return events; -} +// List readEventList(Map json){ +// List events = []; +// int id = 0; +// for (var event in json['data'][0]['replays'][0]['events']){ +// int frame = event["frame"]; +// EventType type = EventType.values.byName(event['type']); +// switch (type) { +// case EventType.start: +// events.add(Event(id, frame, type)); +// break; +// case EventType.full: +// events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); +// break; +// case EventType.targets: +// events.add(EventTargets(id, frame, type, Targets.fromJson(event["data"]))); +// break; +// case EventType.keydown: +// events.add(EventKeyPress(id, frame, type, +// Keypress( +// KeyType.values.byName(event['data']['key']), +// event['data']['subframe'], +// false) +// )); +// break; +// case EventType.keyup: +// events.add(EventKeyPress(id, frame, type, +// Keypress( +// KeyType.values.byName(event['data']['key']), +// event['data']['subframe'], +// true) +// )); +// break; +// case EventType.end: +// events.add(EventEnd(id, frame, type, EndData(event['data']['reason'], DataFull.fromJson(event['data']['export'])))); +// break; +// case EventType.ige: +// events.add(EventIGE(id, frame, type, IGE( +// event['data']['id'], +// event['data']['frame'], +// event['data']['type'], +// event['data']['data'] +// )) +// ); +// break; +// case EventType.exit: +// events.add(Event(id, frame, type)); +// break; +// } +// id++; +// } +// return events; +// } -enum EventType -{ - start, - end, - full, - keydown, - keyup, - targets, - ige, - exit -} +// enum EventType +// { +// start, +// end, +// full, +// keydown, +// keyup, +// targets, +// ige, +// exit +// } -enum KeyType -{ - moveLeft, - moveRight, - softDrop, - rotateCCW, - rotateCW, - rotate180, - hardDrop, - hold, - chat, - exit, - retry -} +// enum KeyType +// { +// moveLeft, +// moveRight, +// softDrop, +// rotateCCW, +// rotateCW, +// rotate180, +// hardDrop, +// hold, +// chat, +// exit, +// retry +// } -class Event{ - int id; - int frame; - EventType type; - //dynamic data; +// class Event{ +// int id; +// int frame; +// EventType type; +// //dynamic data; - Event(this.id, this.frame, this.type); +// Event(this.id, this.frame, this.type); - @override - String toString(){ - return "E#$id f#$frame: $type"; - } -} +// @override +// String toString(){ +// return "E#$id f#$frame: $type"; +// } +// } -class Keypress{ - KeyType key; - late double subframe; - bool released; +// class Keypress{ +// KeyType key; +// late double subframe; +// bool released; - Keypress(this.key, num sframe, this.released){ - subframe = sframe.toDouble(); - } -} +// Keypress(this.key, num sframe, this.released){ +// subframe = sframe.toDouble(); +// } +// } -class EventKeyPress extends Event{ - Keypress data; +// class EventKeyPress extends Event{ +// Keypress data; - EventKeyPress(super.id, super.frame, super.type, this.data); -} +// EventKeyPress(super.id, super.frame, super.type, this.data); +// } -class Targets{ - String? id; - int? frame; - String? type; - List? data; +// class Targets{ +// String? id; +// int? frame; +// String? type; +// List? data; - Targets(this.id, this.frame, this.type, this.data); +// Targets(this.id, this.frame, this.type, this.data); - Targets.fromJson(Map json){ - id = json["id"]; - frame = json["frame"]; - type = json["type"]; - data = json["data"]; - } -} +// Targets.fromJson(Map json){ +// id = json["id"]; +// frame = json["frame"]; +// type = json["type"]; +// data = json["data"]; +// } +// } -class EventTargets extends Event{ - Targets data; +// class EventTargets extends Event{ +// Targets data; - EventTargets(super.id, super.frame, super.type, this.data); -} +// EventTargets(super.id, super.frame, super.type, this.data); +// } -class IGEdata{ - late String type; - late String? gameid; - late int? frame; +// class IGEdata{ +// late String type; +// late String? gameid; +// late int? frame; - IGEdata.fromJson(Map d){ - type = d['type']; - gameid = d['gameid']; - frame = d['frame']; - } -} +// IGEdata.fromJson(Map d){ +// type = d['type']; +// gameid = d['gameid']; +// frame = d['frame']; +// } +// } -enum GarbageStatus -{ - sleeping, - caution, - spawn, - danger -} +// enum GarbageStatus +// { +// sleeping, +// caution, +// spawn, +// danger +// } -class GarbageData{ - int? id; - int? iid; - int? ackiid; - String? username; - late String type; - bool? active; - GarbageStatus? status; - int? delay; - bool? queued; - int? amt; - int? x; - int? y; - int? size; - int? column; - int? cid; - bool? firstcycle; - int? gid; - bool? value; +// class GarbageData{ +// int? id; +// int? iid; +// int? ackiid; +// String? username; +// late String type; +// bool? active; +// GarbageStatus? status; +// int? delay; +// bool? queued; +// int? amt; +// int? x; +// int? y; +// int? size; +// int? column; +// int? cid; +// bool? firstcycle; +// int? gid; +// bool? value; - GarbageData.fromJson(Map data){ - id = data['id']; - iid = data['iid']; - ackiid = data['ackiid']; - username = data['username']; - type = data['type']; - active = data['active']; - status = data['status'] != null ? GarbageStatus.values[data['status']] : null; - delay = data['delay']; - queued = data['queued']; - amt = data['amt']; - x = data['x']; - y = data['y']; - size = data['size']; - column = data['column']; - cid = data['cid']; - firstcycle = data['firstcycle']; - gid = data['gid']; - value = data['value']; - } -} +// GarbageData.fromJson(Map data){ +// id = data['id']; +// iid = data['iid']; +// ackiid = data['ackiid']; +// username = data['username']; +// type = data['type']; +// active = data['active']; +// status = data['status'] != null ? GarbageStatus.values[data['status']] : null; +// delay = data['delay']; +// queued = data['queued']; +// amt = data['amt']; +// x = data['x']; +// y = data['y']; +// size = data['size']; +// column = data['column']; +// cid = data['cid']; +// firstcycle = data['firstcycle']; +// gid = data['gid']; +// value = data['value']; +// } +// } -class IGEdataTarget extends IGEdata{ - late List targets; +// class IGEdataTarget extends IGEdata{ +// late List targets; - GarbageData? data; - //compatibility for v15 targets event - String? sender_id; +// GarbageData? data; +// //compatibility for v15 targets event +// String? sender_id; - IGEdataTarget.fromJson(Map d) : super.fromJson(d){ - targets = d['targets']; - data = d['data'] != null ? GarbageData.fromJson(d['data']) : null; - } -} +// IGEdataTarget.fromJson(Map d) : super.fromJson(d){ +// targets = d['targets']; +// data = d['data'] != null ? GarbageData.fromJson(d['data']) : null; +// } +// } -class IGEdataAllowTargeting extends IGEdata{ - late bool value; +// class IGEdataAllowTargeting extends IGEdata{ +// late bool value; - IGEdataAllowTargeting.fromJson(Map d) : super.fromJson(d){ - value = d['value']; - frame = d['frame']; - } -} +// IGEdataAllowTargeting.fromJson(Map d) : super.fromJson(d){ +// value = d['value']; +// frame = d['frame']; +// } +// } -class IGEdataInteraction extends IGEdata{ - late GarbageData data; - String? sender; - String? senderID; - int? sentFrame; - bool confirm = false; +// class IGEdataInteraction extends IGEdata{ +// late GarbageData data; +// String? sender; +// String? senderID; +// int? sentFrame; +// bool confirm = false; - IGEdataInteraction.fromJson(Map d) : super.fromJson(d){ - //data = Targeted(d['data']['targeted'], d['data']['value']); - data = GarbageData.fromJson(d['data']); - sender = d['sender']; - senderID = d['sender_id']; - confirm = type == "interaction_confirm"; - } -} +// IGEdataInteraction.fromJson(Map d) : super.fromJson(d){ +// //data = Targeted(d['data']['targeted'], d['data']['value']); +// data = GarbageData.fromJson(d['data']); +// sender = d['sender']; +// senderID = d['sender_id']; +// confirm = type == "interaction_confirm"; +// } +// } -class IGE{ - int id; - int frame; - String type; - late IGEdata data; +// class IGE{ +// int id; +// int frame; +// String type; +// late IGEdata data; - IGE(this.id, this.frame, this.type, Map d){ - data = switch (d["type"] as String) { - "interaction" => IGEdataInteraction.fromJson(d), - "interaction_confirm" => IGEdataInteraction.fromJson(d), - "target" => IGEdataTarget.fromJson(d), - "allow_targeting" => IGEdataAllowTargeting.fromJson(d), - _ => IGEdata.fromJson(d), - }; - } -} +// IGE(this.id, this.frame, this.type, Map d){ +// data = switch (d["type"] as String) { +// "interaction" => IGEdataInteraction.fromJson(d), +// "interaction_confirm" => IGEdataInteraction.fromJson(d), +// "target" => IGEdataTarget.fromJson(d), +// "allow_targeting" => IGEdataAllowTargeting.fromJson(d), +// _ => IGEdata.fromJson(d), +// }; +// } +// } -class EventIGE extends Event{ - IGE data; +// class EventIGE extends Event{ +// IGE data; - EventIGE(super.id, super.frame, super.type, this.data); -} +// EventIGE(super.id, super.frame, super.type, this.data); +// } -class EndData { - String reason; - DataFull export; +// class EndData { +// String reason; +// DataFull export; - EndData(this.reason, this.export); -} +// EndData(this.reason, this.export); +// } -class EventEnd extends Event{ - EndData data; +// class EventEnd extends Event{ +// EndData data; - EventEnd(super.id, super.frame, super.type, this.data); -} +// EventEnd(super.id, super.frame, super.type, this.data); +// } -class Hold -{ - String? piece; - bool locked; +// class Hold +// { +// String? piece; +// bool locked; - Hold(this.piece, this.locked); -} +// Hold(this.piece, this.locked); +// } -class DataFullOptions{ - int? version; - bool? seedRandom; - int? seed; - double? g; - int? stock; - int? gMargin; - double? gIncrease; - double? garbageMultiplier; - int? garbageMargin; - double? garbageIncrease; - int? garbageCap; - double? garbageCapIncrease; - int? garbageCapMax; - int? garbageHoleSize; - String? garbageBlocking; // TODO: enum - bool? hasGarbage; - int? locktime; - int? garbageSpeed; - int? forfeitTime; - int? are; - int? areLineclear; - bool? infiniteMovement; - int? lockresets; - bool? allow180; - bool? btbChaining; - bool? allclears; - bool? clutch; - bool? noLockout; - String? passthrough; - int? boardwidth; - int? boardheight; - Handling? handling; - int? boardbuffer; +// class DataFullOptions{ +// int? version; +// bool? seedRandom; +// int? seed; +// double? g; +// int? stock; +// int? gMargin; +// double? gIncrease; +// double? garbageMultiplier; +// int? garbageMargin; +// double? garbageIncrease; +// int? garbageCap; +// double? garbageCapIncrease; +// int? garbageCapMax; +// int? garbageHoleSize; +// String? garbageBlocking; // TODO: enum +// bool? hasGarbage; +// int? locktime; +// int? garbageSpeed; +// int? forfeitTime; +// int? are; +// int? areLineclear; +// bool? infiniteMovement; +// int? lockresets; +// bool? allow180; +// bool? btbChaining; +// bool? allclears; +// bool? clutch; +// bool? noLockout; +// String? passthrough; +// int? boardwidth; +// int? boardheight; +// Handling? handling; +// int? boardbuffer; - DataFullOptions.fromJson(Map json){ - version = json["version"]; - seedRandom = json["seed_random"]; - seed = json["seed"]; - g = json["g"]; - stock = json["stock"]; - gMargin = json["gmargin"]; - gIncrease = json["gincrease"]; - garbageMultiplier = json["garbagemultiplier"].toDouble(); - garbageCap = json["garbagecap"]; - garbageCapIncrease = json["garbagecapincrease"].toDouble(); - garbageCapMax = json["garbagecapmax"]; - garbageHoleSize = json["garbageholesize"]; - garbageBlocking = json["garbageblocking"]; - hasGarbage = json["hasgarbage"]; - locktime = json["locktime"]; - garbageSpeed = json["garbagespeed"]; - forfeitTime = json["forfeit_time"]; - are = json["are"]; - areLineclear = json["lineclear_are"]; - infiniteMovement = json["infinitemovement"]; - lockresets = json["lockresets"]; - allow180 = json["allow180"]; - btbChaining = json["b2bchaining"]; - allclears = json["allclears"]; - clutch = json["clutch"]; - noLockout = json["nolockout"]; - passthrough = json["passthrough"]; - boardwidth = json["boardwidth"]; - boardheight = json["boardheight"]; - handling = Handling.fromJson(json["handling"]); - boardbuffer = json["boardbuffer"]; - } -} +// DataFullOptions.fromJson(Map json){ +// version = json["version"]; +// seedRandom = json["seed_random"]; +// seed = json["seed"]; +// g = json["g"]; +// stock = json["stock"]; +// gMargin = json["gmargin"]; +// gIncrease = json["gincrease"]; +// garbageMultiplier = json["garbagemultiplier"].toDouble(); +// garbageCap = json["garbagecap"]; +// garbageCapIncrease = json["garbagecapincrease"].toDouble(); +// garbageCapMax = json["garbagecapmax"]; +// garbageHoleSize = json["garbageholesize"]; +// garbageBlocking = json["garbageblocking"]; +// hasGarbage = json["hasgarbage"]; +// locktime = json["locktime"]; +// garbageSpeed = json["garbagespeed"]; +// forfeitTime = json["forfeit_time"]; +// are = json["are"]; +// areLineclear = json["lineclear_are"]; +// infiniteMovement = json["infinitemovement"]; +// lockresets = json["lockresets"]; +// allow180 = json["allow180"]; +// btbChaining = json["b2bchaining"]; +// allclears = json["allclears"]; +// clutch = json["clutch"]; +// noLockout = json["nolockout"]; +// passthrough = json["passthrough"]; +// boardwidth = json["boardwidth"]; +// boardheight = json["boardheight"]; +// handling = Handling.fromJson(json["handling"]); +// boardbuffer = json["boardbuffer"]; +// } +// } -class DataFullStats - { - int? seed; - int? lines; - int? levelLines; - int? levelLinesNeeded; - int? inputs; - int? holds; - int? score; - int? zenLevel; - int? zenProgress; - int? level; - int? combo; - int? currentComboPower; - int? topCombo; - int? btb; - int? topbtb; - int? tspins; - int? piecesPlaced; - Clears? clears; - Garbage? garbage; - int? kills; - Finesse? finesse; +// class DataFullStats +// { +// int? seed; +// int? lines; +// int? levelLines; +// int? levelLinesNeeded; +// int? inputs; +// int? holds; +// int? score; +// int? zenLevel; +// int? zenProgress; +// int? level; +// int? combo; +// int? currentComboPower; +// int? topCombo; +// int? btb; +// int? topbtb; +// int? tspins; +// int? piecesPlaced; +// Clears? clears; +// Garbage? garbage; +// int? kills; +// Finesse? finesse; - DataFullStats.fromJson(Map json){ - seed = json["seed"]; - lines = json["lines"]; - levelLines = json["level_lines"]; - levelLinesNeeded = json["level_lines_needed"]; - inputs = json["inputs"]; - holds = json["holds"]; - score = json["score"]; - zenLevel = json["zenlevel"]; - zenProgress = json["zenprogress"]; - level = json["level"]; - combo = json["combo"]; - currentComboPower = json["currentcombopower"]; - topCombo = json["topcombo"]; - btb = json["btb"]; - topbtb = json["topbtb"]; - tspins = json["tspins"]; - piecesPlaced = json["piecesplaced"]; - clears = Clears.fromJson(json["clears"]); - garbage = Garbage.fromJson(json["garbage"]); - kills = json["kills"]; - finesse = Finesse.fromJson(json["finesse"]); - } - } +// DataFullStats.fromJson(Map json){ +// seed = json["seed"]; +// lines = json["lines"]; +// levelLines = json["level_lines"]; +// levelLinesNeeded = json["level_lines_needed"]; +// inputs = json["inputs"]; +// holds = json["holds"]; +// score = json["score"]; +// zenLevel = json["zenlevel"]; +// zenProgress = json["zenprogress"]; +// level = json["level"]; +// combo = json["combo"]; +// currentComboPower = json["currentcombopower"]; +// topCombo = json["topcombo"]; +// btb = json["btb"]; +// topbtb = json["topbtb"]; +// tspins = json["tspins"]; +// piecesPlaced = json["piecesplaced"]; +// clears = Clears.fromJson(json["clears"]); +// garbage = Garbage.fromJson(json["garbage"]); +// kills = json["kills"]; +// finesse = Finesse.fromJson(json["finesse"]); +// } +// } -class DataFullGame - { - List? board; - List? bag; - double? g; - bool? playing; - Hold? hold; - String? piece; - Handling? handling; +// class DataFullGame +// { +// List? board; +// List? bag; +// double? g; +// bool? playing; +// Hold? hold; +// String? piece; +// Handling? handling; - DataFullGame.fromJson(Map json){ - board = json["board"]; - bag = json["bag"]; - hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); - g = json["g"]; - handling = Handling.fromJson(json["handling"]); - } - } +// DataFullGame.fromJson(Map json){ +// board = json["board"]; +// bag = json["bag"]; +// hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); +// g = json["g"]; +// handling = Handling.fromJson(json["handling"]); +// } +// } -class DataFull{ - bool? successful; - String? gameOverReason; - int? fire; - DataFullOptions? options; - DataFullStats? stats; - DataFullGame? game; +// class DataFull{ +// bool? successful; +// String? gameOverReason; +// int? fire; +// DataFullOptions? options; +// DataFullStats? stats; +// DataFullGame? game; - DataFull.fromJson(Map json){ - successful = json["successful"]; - gameOverReason = json["gameoverreason"]; - fire = json["fire"]; - options = DataFullOptions.fromJson(json["options"]); - stats = DataFullStats.fromJson(json["stats"]); - game = DataFullGame.fromJson(json["game"]); - } -} +// DataFull.fromJson(Map json){ +// successful = json["successful"]; +// gameOverReason = json["gameoverreason"]; +// fire = json["fire"]; +// options = DataFullOptions.fromJson(json["options"]); +// stats = DataFullStats.fromJson(json["stats"]); +// game = DataFullGame.fromJson(json["game"]); +// } +// } -class EventFull extends Event{ - DataFull data; +// class EventFull extends Event{ +// DataFull data; - EventFull(super.id, super.frame, super.type, this.data); -} +// EventFull(super.id, super.frame, super.type, this.data); +// } -class TetrioRNG{ - late double _t; +// class TetrioRNG{ +// late double _t; - TetrioRNG(int seed){ - _t = seed % 2147483647; - if (_t <= 0) _t += 2147483646; - } +// TetrioRNG(int seed){ +// _t = seed % 2147483647; +// if (_t <= 0) _t += 2147483646; +// } - int next(){ - _t = 16807 * _t % 2147483647; - return _t.toInt(); - } +// int next(){ +// _t = 16807 * _t % 2147483647; +// return _t.toInt(); +// } - double nextFloat(){ - return (next() - 1) / 2147483646; - } +// double nextFloat(){ +// return (next() - 1) / 2147483646; +// } - List shuffleList(List array){ - int length = array.length; - if (length == 0) return []; +// List shuffleList(List array){ +// int length = array.length; +// if (length == 0) return []; - for (; --length > 0;){ - int swapIndex = ((nextFloat()) * (length + 1)).toInt(); - Tetromino tmp = array[length]; - array[length] = array[swapIndex]; - array[swapIndex] = tmp; - } - return array; - } -} +// for (; --length > 0;){ +// int swapIndex = ((nextFloat()) * (length + 1)).toInt(); +// Tetromino tmp = array[length]; +// array[length] = array[swapIndex]; +// array[swapIndex] = tmp; +// } +// return array; +// } +// } -enum Tetromino{ - Z, - L, - O, - S, - I, - J, - T, - garbage, - empty -} +// enum Tetromino{ +// Z, +// L, +// O, +// S, +// I, +// J, +// T, +// garbage, +// empty +// } -class Coords{ - int x; - int y; +// class Coords{ +// int x; +// int y; - Coords(this.x, this.y); +// Coords(this.x, this.y); - @override - String toString() { - return "($x; $y)"; - } +// @override +// String toString() { +// return "($x; $y)"; +// } - Coords operator+(Coords other){ - return Coords(x+other.x, y+other.y); - } +// Coords operator+(Coords other){ +// return Coords(x+other.x, y+other.y); +// } - Coords operator-(Coords other){ - return Coords(x-other.x, y-other.y); - } -} +// Coords operator-(Coords other){ +// return Coords(x-other.x, y-other.y); +// } +// } -List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; -List>> shapes = [ - [ // Z - [Coords(0, 2), Coords(1, 2), Coords(1, 1), Coords(2, 1)], - [Coords(2, 2), Coords(2, 1), Coords(1, 1), Coords(1, 0)], - [Coords(2, 0), Coords(1, 0), Coords(1, 1), Coords(0, 1)], - [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] - ], - [ // L - [Coords(2, 2), Coords(2, 1), Coords(1, 1), Coords(0, 1)], - [Coords(2, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)], - [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], - [Coords(0, 2), Coords(1, 2), Coords(1, 1), Coords(1, 0)] - ], - [ // O - [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], - [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], - [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], - [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)] - ], - [ // S - [Coords(2, 2), Coords(1, 2), Coords(1, 1), Coords(0, 1)], - [Coords(2, 0), Coords(2, 1), Coords(1, 1), Coords(1, 2)], - [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(2, 1)], - [Coords(0, 2), Coords(0, 1), Coords(1, 1), Coords(1, 0)] - ], - [ // I - [Coords(0, 2), Coords(1, 2), Coords(2, 2), Coords(3, 2)], - [Coords(2, 3), Coords(2, 2), Coords(2, 1), Coords(2, 0)], - [Coords(3, 1), Coords(2, 1), Coords(1, 1), Coords(0, 1)], - [Coords(1, 0), Coords(1, 1), Coords(1, 2), Coords(1, 3)] - ], - [ // J - [Coords(0, 2), Coords(0, 1), Coords(1, 1), Coords(2, 1)], - [Coords(2, 2), Coords(1, 2), Coords(1, 1), Coords(1, 0)], - [Coords(2, 0), Coords(2, 1), Coords(1, 1), Coords(0, 1)], - [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)] - ], - [ // T - [Coords(1, 2), Coords(0, 1), Coords(1, 1), Coords(2, 1)], - [Coords(2, 1), Coords(1, 2), Coords(1, 1), Coords(1, 0)], - [Coords(1, 0), Coords(2, 1), Coords(1, 1), Coords(0, 1)], - [Coords(0, 1), Coords(1, 0), Coords(1, 1), Coords(1, 2)] - ] -]; -List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(1, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; +// List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; +// List>> shapes = [ +// [ // Z +// [Coords(0, 2), Coords(1, 2), Coords(1, 1), Coords(2, 1)], +// [Coords(2, 2), Coords(2, 1), Coords(1, 1), Coords(1, 0)], +// [Coords(2, 0), Coords(1, 0), Coords(1, 1), Coords(0, 1)], +// [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(1, 2)] +// ], +// [ // L +// [Coords(2, 2), Coords(2, 1), Coords(1, 1), Coords(0, 1)], +// [Coords(2, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)], +// [Coords(0, 0), Coords(0, 1), Coords(1, 1), Coords(2, 1)], +// [Coords(0, 2), Coords(1, 2), Coords(1, 1), Coords(1, 0)] +// ], +// [ // O +// [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], +// [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], +// [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)], +// [Coords(0, 0), Coords(1, 0), Coords(0, 1), Coords(1, 1)] +// ], +// [ // S +// [Coords(2, 2), Coords(1, 2), Coords(1, 1), Coords(0, 1)], +// [Coords(2, 0), Coords(2, 1), Coords(1, 1), Coords(1, 2)], +// [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(2, 1)], +// [Coords(0, 2), Coords(0, 1), Coords(1, 1), Coords(1, 0)] +// ], +// [ // I +// [Coords(0, 2), Coords(1, 2), Coords(2, 2), Coords(3, 2)], +// [Coords(2, 3), Coords(2, 2), Coords(2, 1), Coords(2, 0)], +// [Coords(3, 1), Coords(2, 1), Coords(1, 1), Coords(0, 1)], +// [Coords(1, 0), Coords(1, 1), Coords(1, 2), Coords(1, 3)] +// ], +// [ // J +// [Coords(0, 2), Coords(0, 1), Coords(1, 1), Coords(2, 1)], +// [Coords(2, 2), Coords(1, 2), Coords(1, 1), Coords(1, 0)], +// [Coords(2, 0), Coords(2, 1), Coords(1, 1), Coords(0, 1)], +// [Coords(0, 0), Coords(1, 0), Coords(1, 1), Coords(1, 2)] +// ], +// [ // T +// [Coords(1, 2), Coords(0, 1), Coords(1, 1), Coords(2, 1)], +// [Coords(2, 1), Coords(1, 2), Coords(1, 1), Coords(1, 0)], +// [Coords(1, 0), Coords(2, 1), Coords(1, 1), Coords(0, 1)], +// [Coords(0, 1), Coords(1, 0), Coords(1, 1), Coords(1, 2)] +// ] +// ]; +// List spawnPositionFixes = [Coords(0, 0), Coords(0, 0), Coords(1, 1), Coords(0, 0), Coords(0, -1), Coords(0, 0), Coords(0, 0)]; -const Map garbage = { - "single": 0, - "double": 1, - "triple": 2, - "quad": 4, - "penta": 5, - "t-spin": 0, - "t-spin single": 2, - "t-spin double": 4, - "t-spin triple": 6, - "t-spin quad": 10, - "t-spin penta": 12, - "t-spin mini": 0, - "t-spin mini single": 0, - "t-spin mini double": 1, - "allclear": 10 -}; -int btbBonus = 1; -double btbLog = 0.8; -double comboBonus = 0.25; -int comboMinifier = 1; -double comboMinifierLog = 1.25; -List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; +// const Map garbage = { +// "single": 0, +// "double": 1, +// "triple": 2, +// "quad": 4, +// "penta": 5, +// "t-spin": 0, +// "t-spin single": 2, +// "t-spin double": 4, +// "t-spin triple": 6, +// "t-spin quad": 10, +// "t-spin penta": 12, +// "t-spin mini": 0, +// "t-spin mini single": 0, +// "t-spin mini double": 1, +// "allclear": 10 +// }; +// int btbBonus = 1; +// double btbLog = 0.8; +// double comboBonus = 0.25; +// int comboMinifier = 1; +// double comboMinifierLog = 1.25; +// List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; -class KicksetBase { - List? additionalOffsets; - late List additionalOffsetEmpty; - List? spawnRotation; - late List>> kickTable; //kickTable[initRot][rotDirection-1][kick] - late List>> kickTableI; -} +// class KicksetBase { +// List? additionalOffsets; +// late List additionalOffsetEmpty; +// List? spawnRotation; +// late List>> kickTable; //kickTable[initRot][rotDirection-1][kick] +// late List>> kickTableI; +// } -class SRSPlus extends KicksetBase{ - SRSPlus(){ - kickTable = [ - [ - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 270 - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 90 - [Coords( 0, 0), Coords( 0, 1), Coords( 1, 1), Coords(-1, 1), Coords( 1, 0), Coords(-1, 0)], // 0 -> 180 - ], - [ - [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 0 - [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 180 - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 2), Coords( 1, 1), Coords( 0, 2), Coords( 0, 1)], // 90 -> 270 - ], - [ - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 90 - [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 270 - [Coords( 0, 0), Coords( 0,-1), Coords(-1,-1), Coords( 1,-1), Coords(-1, 0), Coords( 1, 0)], // 180 -> 0 - ], - [ - [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 180 - [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 0 - [Coords( 0, 0), Coords(-1, 0), Coords(-1, 2), Coords(-1, 1), Coords( 0, 2), Coords( 0, 1)], // 270 -> 90 - ] - ]; - kickTableI = [ - [ - [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords( 2,-1), Coords(-1, 2)], // 0 -> 270 - [Coords( 0, 0), Coords( 1, 0), Coords( 2, 0), Coords(-1,-1), Coords( 1, 2)], // 0 -> 90 - [Coords( 0, 0), Coords( 0, 1)], // 0 -> 180 - ], - [ - [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords(-1,-2), Coords( 2,-1)], // 90 -> 0 - [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords(-1, 2), Coords( 2, 1)], // 90 -> 180 - [Coords( 0, 0), Coords( 1, 0)], // 90 -> 270 - ], - [ - [Coords( 0, 0), Coords(-2, 0), Coords( 1, 0), Coords(-2, 1), Coords( 1,-2)], // 180 -> 90 - [Coords( 0, 0), Coords(-2, 0), Coords(-1, 0), Coords( 2, 1), Coords(-1,-2)], // 180 -> 270 - [Coords( 0, 0), Coords( 0,-1)], // 180 -> 0 - ], - [ - [Coords( 0, 0), Coords( 1, 0), Coords(-2, 0), Coords( 1, 2), Coords(-2,-1)], // 270 -> 180 - [Coords( 0, 0), Coords( 1, 0), Coords(-2, 0), Coords( 1,-2), Coords(-2, 1)], // 270 -> 0 - [Coords( 0, 0), Coords(-1, 0)], // 270 -> 90 - ] - ]; - additionalOffsetEmpty = [Coords( 0, 0),Coords( 0, 0),Coords( 0, 0),Coords( 0, 0)]; - } -} +// class SRSPlus extends KicksetBase{ +// SRSPlus(){ +// kickTable = [ +// [ +// [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 0 -> 270 +// [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 0 -> 90 +// [Coords( 0, 0), Coords( 0, 1), Coords( 1, 1), Coords(-1, 1), Coords( 1, 0), Coords(-1, 0)], // 0 -> 180 +// ], +// [ +// [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 0 +// [Coords( 0, 0), Coords( 1, 0), Coords( 1,-1), Coords( 0, 2), Coords( 1, 2)], // 90 -> 180 +// [Coords( 0, 0), Coords( 1, 0), Coords( 1, 2), Coords( 1, 1), Coords( 0, 2), Coords( 0, 1)], // 90 -> 270 +// ], +// [ +// [Coords( 0, 0), Coords(-1, 0), Coords(-1, 1), Coords( 0,-2), Coords(-1,-2)], // 180 -> 90 +// [Coords( 0, 0), Coords( 1, 0), Coords( 1, 1), Coords( 0,-2), Coords( 1,-2)], // 180 -> 270 +// [Coords( 0, 0), Coords( 0,-1), Coords(-1,-1), Coords( 1,-1), Coords(-1, 0), Coords( 1, 0)], // 180 -> 0 +// ], +// [ +// [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 180 +// [Coords( 0, 0), Coords(-1, 0), Coords(-1,-1), Coords( 0, 2), Coords(-1, 2)], // 270 -> 0 +// [Coords( 0, 0), Coords(-1, 0), Coords(-1, 2), Coords(-1, 1), Coords( 0, 2), Coords( 0, 1)], // 270 -> 90 +// ] +// ]; +// kickTableI = [ +// [ +// [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords( 2,-1), Coords(-1, 2)], // 0 -> 270 +// [Coords( 0, 0), Coords( 1, 0), Coords( 2, 0), Coords(-1,-1), Coords( 1, 2)], // 0 -> 90 +// [Coords( 0, 0), Coords( 0, 1)], // 0 -> 180 +// ], +// [ +// [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords(-1,-2), Coords( 2,-1)], // 90 -> 0 +// [Coords( 0, 0), Coords(-1, 0), Coords( 2, 0), Coords(-1, 2), Coords( 2, 1)], // 90 -> 180 +// [Coords( 0, 0), Coords( 1, 0)], // 90 -> 270 +// ], +// [ +// [Coords( 0, 0), Coords(-2, 0), Coords( 1, 0), Coords(-2, 1), Coords( 1,-2)], // 180 -> 90 +// [Coords( 0, 0), Coords(-2, 0), Coords(-1, 0), Coords( 2, 1), Coords(-1,-2)], // 180 -> 270 +// [Coords( 0, 0), Coords( 0,-1)], // 180 -> 0 +// ], +// [ +// [Coords( 0, 0), Coords( 1, 0), Coords(-2, 0), Coords( 1, 2), Coords(-2,-1)], // 270 -> 180 +// [Coords( 0, 0), Coords( 1, 0), Coords(-2, 0), Coords( 1,-2), Coords(-2, 1)], // 270 -> 0 +// [Coords( 0, 0), Coords(-1, 0)], // 270 -> 90 +// ] +// ]; +// additionalOffsetEmpty = [Coords( 0, 0),Coords( 0, 0),Coords( 0, 0),Coords( 0, 0)]; +// } +// } diff --git a/lib/gen/strings.g.dart b/lib/gen/strings.g.dart index 6b05e47..42e4e73 100644 --- a/lib/gen/strings.g.dart +++ b/lib/gen/strings.g.dart @@ -6,7 +6,7 @@ /// Locales: 2 /// Strings: 1182 (591 per locale) /// -/// Built on 2024-06-16 at 21:03 UTC +/// Built on 2024-07-10 at 15:23 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -321,7 +321,7 @@ class Translations implements BaseTranslations { String get fromBeginning => 'From beginning'; String get calc => 'Calc'; String get calcViewNoValues => 'Enter values to calculate the stats'; - String get rankAveragesViewTitle => 'Ranks cutoff and average stats'; + String get rankAveragesViewTitle => 'Ranks cutoffs'; String get sprintAndBlitsViewTitle => '40 lines and Blitz averages'; String sprintAndBlitsRelevance({required Object date}) => 'Relevance: ${date}'; String get rank => 'Rank'; @@ -1016,7 +1016,7 @@ class _StringsRu implements Translations { @override String get fromBeginning => 'С начала'; @override String get calc => 'Считать'; @override String get calcViewNoValues => 'Введите значения, чтобы посчитать статистику'; - @override String get rankAveragesViewTitle => 'Требования рангов и средние значения'; + @override String get rankAveragesViewTitle => 'Требования рангов'; @override String get sprintAndBlitsViewTitle => 'Средние результаты 40 линий и блица'; @override String sprintAndBlitsRelevance({required Object date}) => 'Актуальность: ${date}'; @override String get rank => 'Ранг'; @@ -1703,7 +1703,7 @@ extension on Translations { case 'fromBeginning': return 'From beginning'; case 'calc': return 'Calc'; case 'calcViewNoValues': return 'Enter values to calculate the stats'; - case 'rankAveragesViewTitle': return 'Ranks cutoff and average stats'; + case 'rankAveragesViewTitle': return 'Ranks cutoffs'; case 'sprintAndBlitsViewTitle': return '40 lines and Blitz averages'; case 'sprintAndBlitsRelevance': return ({required Object date}) => 'Relevance: ${date}'; case 'rank': return 'Rank'; @@ -2314,7 +2314,7 @@ extension on _StringsRu { case 'fromBeginning': return 'С начала'; case 'calc': return 'Считать'; case 'calcViewNoValues': return 'Введите значения, чтобы посчитать статистику'; - case 'rankAveragesViewTitle': return 'Требования рангов и средние значения'; + case 'rankAveragesViewTitle': return 'Требования рангов'; case 'sprintAndBlitsViewTitle': return 'Средние результаты 40 линий и блица'; case 'sprintAndBlitsRelevance': return ({required Object date}) => 'Актуальность: ${date}'; case 'rank': return 'Ранг'; diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index df67f3d..d949867 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -606,7 +606,7 @@ class TetrioService extends DB { if (kIsWeb) { url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLMatches", "user": userID}); } else { - url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID'); + url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID', {"before": "66749c93ffcbce61b2a1d912"}); } try{ @@ -614,62 +614,9 @@ class TetrioService extends DB { switch (response.statusCode) { case 200: - // that one api returns csv instead of json - List> csv = const CsvToListConverter().convert(response.body)..removeAt(0); - List matches = []; - - // parsing data into TetraLeagueAlphaRecord objects - for (var entry in csv){ - TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord( - replayId: entry[0].toString(), - ownId: entry[0].toString(), // i gonna disting p1nkl0bst3r entries with it - timestamp: DateTime.parse(entry[1]), - endContext: [ - EndContextMulti( - userId: entry[2].toString(), - username: entry[3].toString(), - naturalOrder: 0, - inputs: -1, - piecesPlaced: -1, - handling: Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true), - points: entry[4], - wins: entry[4], - secondary: entry[6], - secondaryTracking: [], - tertiary: entry[5], - tertiaryTracking: [], - extra: entry[7], - extraTracking: [], - success: true - ), - EndContextMulti( - userId: entry[8].toString(), - username: entry[9].toString(), - naturalOrder: 1, - inputs: -1, - piecesPlaced: -1, - handling: Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true), - points: entry[10], - wins: entry[10], - secondary: entry[12], - secondaryTracking: [], - tertiary: entry[11], - tertiaryTracking: [], - extra: entry[13], - extraTracking: [], - success: false - ) - ], - replayAvalable: false - ); - matches.add(match); - } - - // trying to dump it to local DB - TetraLeagueAlphaStream fakeStream = TetraLeagueAlphaStream(userId: userID, records: matches); - saveTLMatchesFromStream(fakeStream); - - return matches; + TetraLeagueAlphaStream stream = TetraLeagueAlphaStream.fromJson(jsonDecode(response.body)['data']['records'], userID); + saveTLMatchesFromStream(stream); + return stream.records; case 404: developer.log("fetchAndSaveOldTLmatches: Probably, history doesn't exist", name: "services/tetrio_crud", error: response.statusCode); throw TetrioHistoryNotExist(); diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index b3a845f..a95ff9b 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -306,7 +306,7 @@ class _MainState extends State with TickerProviderStateMixin { }); } - return [me, records, states, tlMatches, compareWith, isTracking, news, topTR, recent, sprint, blitz]; + return [me, records, states, tlMatches, compareWith, isTracking, news, topTR, recent, sprint, blitz, tlMatches.elementAtOrNull(0)?.timestamp]; } /// Triggers widgets rebuild @@ -459,6 +459,7 @@ class _MainState extends State with TickerProviderStateMixin { userID: snapshot.data![0].userId, states: snapshot.data![2], topTR: snapshot.data![7]?.tr, + lastMatchPlayed: snapshot.data![11], bot: snapshot.data![0].role == "bot", guest: snapshot.data![0].role == "anon", thatRankCutoff: thatRankCutoff, diff --git a/lib/views/ranks_averages_view.dart b/lib/views/ranks_averages_view.dart index 5b481b3..dbfa0e9 100644 --- a/lib/views/ranks_averages_view.dart +++ b/lib/views/ranks_averages_view.dart @@ -49,14 +49,13 @@ class RanksAverages extends State { child: averages.isEmpty ? const Center(child: Text('Fetching...')) : ListView.builder( itemCount: averages.length, itemBuilder: (context, index){ - bool bigScreen = MediaQuery.of(context).size.width > 768; List keys = averages.keys.toList(); return ListTile( leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48), title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")), subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM", - style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)), - trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), + style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey, fontSize: 13)), + trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: const TextStyle(fontSize: 28, fontFamily: "Eurostile Round")), onTap: (){ if (averages[keys[index]]?[1]["players"] > 0) { Navigator.push( diff --git a/lib/views/tl_leaderboard_view.dart b/lib/views/tl_leaderboard_view.dart index d69bff8..8b16a28 100644 --- a/lib/views/tl_leaderboard_view.dart +++ b/lib/views/tl_leaderboard_view.dart @@ -58,7 +58,7 @@ class TLLeaderboardState extends State { ); }, icon: const Icon(Icons.compress), - tooltip: t.averages, + tooltip: t.rankAveragesViewTitle, ), ], ), @@ -102,11 +102,11 @@ class TLLeaderboardState extends State { ), TextButton(onPressed: (){ Navigator.push( - context, - MaterialPageRoute( - builder: (context) => RankView(rank: snapshot.data!.getAverageOfRank("")), - ), - ); + context, + MaterialPageRoute( + builder: (context) => RankView(rank: snapshot.data!.getAverageOfRank("")), + ), + ); }, child: Text(t.everyoneAverages, style: const TextStyle(fontSize: 25))) ],) @@ -184,12 +184,12 @@ class TLLeaderboardState extends State { style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9) ), title: Text(allPlayers[index].username, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)), - subtitle: Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}", - style: TextStyle(fontFamily: "Eurostile Round Condensed", fontSize: bigScreen ? null : 12, color: _sortBy == Stats.tr ? Colors.grey : null)), + subtitle: (bigScreen || _sortBy != Stats.tr) ? Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}", + style: TextStyle(fontFamily: "Eurostile Round Condensed", fontSize: bigScreen ? null : 13, color: _sortBy == Stats.tr ? Colors.grey : null)) : null, trailing: Row( mainAxisSize: MainAxisSize.min, children: [ - Text("${f2.format(allPlayers[index].rating)} TR", style: TextStyle(fontSize: bigScreen ? 28 : 22)), + Text("${f2.format(allPlayers[index].rating)} TR", style: const TextStyle(fontSize: 28)), Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 36), ], ), diff --git a/lib/views/tl_match_view.dart b/lib/views/tl_match_view.dart index 96d23ae..7d001ae 100644 --- a/lib/views/tl_match_view.dart +++ b/lib/views/tl_match_view.dart @@ -269,7 +269,7 @@ class TlMatchResultState extends State { label: "Sent", higherIsBetter: true), CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.recived, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.recived, - label: "Recived", higherIsBetter: true), + label: "Received", higherIsBetter: true), CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.attack, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.attack, label: "Attack", higherIsBetter: true), diff --git a/lib/widgets/tl_rating_thingy.dart b/lib/widgets/tl_rating_thingy.dart index 735b06c..f5c3e7e 100644 --- a/lib/widgets/tl_rating_thingy.dart +++ b/lib/widgets/tl_rating_thingy.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; @@ -6,14 +8,16 @@ import 'package:tetra_stats/main.dart' show prefs; import 'package:tetra_stats/utils/numers_formats.dart'; var fDiff = NumberFormat("+#,###.####;-#,###.####"); +DateTime seasonEnd = DateTime.utc(2024, 07, 26); class TLRatingThingy extends StatelessWidget{ final String userID; final TetraLeagueAlpha tlData; final TetraLeagueAlpha? oldTl; final double? topTR; + final DateTime? lastMatchPlayed; - const TLRatingThingy({super.key, required this.userID, required this.tlData, this.oldTl, this.topTR}); + const TLRatingThingy({super.key, required this.userID, required this.tlData, this.oldTl, this.topTR, this.lastMatchPlayed}); @override Widget build(BuildContext context) { @@ -23,6 +27,11 @@ class TLRatingThingy extends StatelessWidget{ List formatedTR = f4.format(tlData.rating).split(decimalSeparator); List formatedGlicko = f4.format(tlData.glicko).split(decimalSeparator); List formatedPercentile = f4.format(tlData.percentile * 100).split(decimalSeparator); + DateTime now = DateTime.now(); + bool beforeS1end = now.isBefore(seasonEnd); + int daysLeft = seasonEnd.difference(now).inDays; + print(max(0, 7 - (lastMatchPlayed != null ? now.difference(lastMatchPlayed!).inDays : 7))); + int safeRD = min(100, (100 + ((tlData.rd! >= 100 && tlData.decaying) ? 7 : max(0, 7 - (lastMatchPlayed != null ? now.difference(lastMatchPlayed!).inDays : 7))) - daysLeft).toInt()); return Wrap( direction: Axis.horizontal, alignment: WrapAlignment.spaceAround, @@ -83,7 +92,8 @@ class TLRatingThingy extends StatelessWidget{ if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"), TextSpan(text: " • ${prefs.getInt("ratingMode") == 1 ? "${f2.format(tlData.rating)} TR • RD: " : "Glicko: ${f2.format(tlData.glicko!)}±"}"), TextSpan(text: f2.format(tlData.rd!), style: tlData.decaying ? TextStyle(color: tlData.rd! > 98 ? Colors.red : Colors.yellow) : null), - if (tlData.decaying) WidgetSpan(child: Icon(Icons.trending_up, color: tlData.rd! > 98 ? Colors.red : Colors.yellow,), alignment: PlaceholderAlignment.middle, baseline: TextBaseline.alphabetic) + if (tlData.decaying) WidgetSpan(child: Icon(Icons.trending_up, color: tlData.rd! > 98 ? Colors.red : Colors.yellow,), alignment: PlaceholderAlignment.middle, baseline: TextBaseline.alphabetic), + if (beforeS1end) tlData.rd! <= safeRD ? TextSpan(text: " (Safe)", style: TextStyle(color: Colors.greenAccent)) : TextSpan(text: " (> ${safeRD} RD !!!)", style: TextStyle(color: Colors.redAccent)) ], ), ), diff --git a/lib/widgets/tl_thingy.dart b/lib/widgets/tl_thingy.dart index 71f674e..95ffe97 100644 --- a/lib/widgets/tl_thingy.dart +++ b/lib/widgets/tl_thingy.dart @@ -31,7 +31,8 @@ class TLThingy extends StatefulWidget { final double? nextRankCutoff; final double? nextRankCutoffGlicko; final double? nextRankTarget; - const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff, this.thatRankCutoff, this.thatRankCutoffGlicko, this.nextRankCutoffGlicko, this.nextRankTarget, this.thatRankTarget}); + final DateTime? lastMatchPlayed; + const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff, this.thatRankCutoff, this.thatRankCutoffGlicko, this.nextRankCutoffGlicko, this.nextRankTarget, this.thatRankTarget, this.lastMatchPlayed}); @override State createState() => _TLThingyState(); @@ -92,7 +93,7 @@ class _TLThingyState extends State { }); }, ), - if (currentTl.gamesPlayed >= 10) TLRatingThingy(userID: widget.userID, tlData: currentTl, oldTl: oldTl, topTR: widget.topTR), + if (currentTl.gamesPlayed > 9) TLRatingThingy(userID: widget.userID, tlData: currentTl, oldTl: oldTl, topTR: widget.topTR, lastMatchPlayed: widget.lastMatchPlayed), if (currentTl.gamesPlayed > 9) TLProgress( tlData: currentTl, previousRankTRcutoff: widget.thatRankCutoff, diff --git a/pubspec.yaml b/pubspec.yaml index 24111e6..2007d63 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: tetra_stats description: Track your and other player stats in TETR.IO publish_to: 'none' -version: 1.6.0+20 +version: 1.6.1+21 environment: sdk: '>=3.0.0' diff --git a/res/i18n/strings.i18n.json b/res/i18n/strings.i18n.json index 3136a87..8dd3631 100644 --- a/res/i18n/strings.i18n.json +++ b/res/i18n/strings.i18n.json @@ -186,7 +186,7 @@ "fromBeginning": "From beginning", "calc": "Calc", "calcViewNoValues": "Enter values to calculate the stats", - "rankAveragesViewTitle": "Ranks cutoff and average stats", + "rankAveragesViewTitle": "Ranks cutoffs", "sprintAndBlitsViewTitle": "40 lines and Blitz averages", "sprintAndBlitsRelevance": "Relevance: ${date}", "rank": "Rank", diff --git a/res/i18n/strings_ru.i18n.json b/res/i18n/strings_ru.i18n.json index 00dbc00..63c49d5 100644 --- a/res/i18n/strings_ru.i18n.json +++ b/res/i18n/strings_ru.i18n.json @@ -186,7 +186,7 @@ "fromBeginning": "С начала", "calc": "Считать", "calcViewNoValues": "Введите значения, чтобы посчитать статистику", - "rankAveragesViewTitle": "Требования рангов и средние значения", + "rankAveragesViewTitle": "Требования рангов", "sprintAndBlitsViewTitle": "Средние результаты 40 линий и блица", "sprintAndBlitsRelevance": "Актуальность: ${date}", "rank": "Ранг", diff --git a/web/index.html b/web/index.html index ad7b67e..5626d5d 100644 --- a/web/index.html +++ b/web/index.html @@ -150,7 +150,7 @@ let tip = document.querySelector("#tip"); const tips = [ // Promoting Tetra Stats "native" - "Want a better perfomance?
Try out Tetra Stats Native", + "Want a better perfomance?
Try out Tetra Stats \"Native\"", "Imagine a world, where Tetra Stats was written in JS", "Welcome to fullscreen canvas", @@ -172,6 +172,7 @@ let appRunner = await engineInitializer.initializeEngine(); await appRunner.runApp(); preloader.classList.add("hidden"); + tip.classList.add("hidden"); } }); } catch (e){ From 29ac38c034997990b47feb63ec9382222cdc0445 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Wed, 10 Jul 2024 18:50:25 +0300 Subject: [PATCH 13/14] Oops i forgor to remove something useless --- lib/views/settings_view.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index fb373b9..1eb96c5 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -288,13 +288,13 @@ class SettingsState extends State { subtitle: Text(t.aboutAppText(appName: packageInfo.appName, packageName: packageInfo.packageName, version: packageInfo.version, buildNumber: packageInfo.buildNumber)), trailing: const Icon(Icons.arrow_right) ), - Wrap( - alignment: WrapAlignment.center, - spacing: 8, - children: [ - TextButton(child: Text("Donate to me"), onPressed: (){},),TextButton(child: Text("Donate to NOT me"), onPressed: (){},),TextButton(child: Text("Donate to someone else"), onPressed: (){},), - ], - ), + // Wrap( + // alignment: WrapAlignment.center, + // spacing: 8, + // children: [ + // TextButton(child: Text("Donate to me"), onPressed: (){},),TextButton(child: Text("Donate to NOT me"), onPressed: (){},),TextButton(child: Text("Donate to someone else"), onPressed: (){},), + // ], + // ), ], )), ); From 54a5cc683ce9b8869663c18999854ed8151931bf Mon Sep 17 00:00:00 2001 From: dan63047 Date: Wed, 10 Jul 2024 19:21:03 +0300 Subject: [PATCH 14/14] and i forgot about something again --- lib/data_objects/tetrio.dart | 2 +- lib/services/tetrio_crud.dart | 2 +- lib/views/main_view.dart | 4 ++-- lib/widgets/singleplayer_record.dart | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart index eeff63b..8ff586c 100644 --- a/lib/data_objects/tetrio.dart +++ b/lib/data_objects/tetrio.dart @@ -901,7 +901,7 @@ class TetraLeagueAlphaRecord{ replayId = json['replayid']; ownId = json['_id']??replayId; timestamp = DateTime.parse(json['ts']); - replayAvalable = true; + replayAvalable = ownId != replayId; } Map toJson() { diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index d949867..f821c73 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -606,7 +606,7 @@ class TetrioService extends DB { if (kIsWeb) { url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLMatches", "user": userID}); } else { - url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID', {"before": "66749c93ffcbce61b2a1d912"}); + url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID', {"before": "0", "count": "9000"}); } try{ diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index a95ff9b..14ab269 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -1085,7 +1085,7 @@ class _TwoRecordsThingy extends StatelessWidget { if (sprint != null) FinesseThingy(sprint?.endContext.finesse, sprint?.endContext.finessePercentage), if (sprint != null) LineclearsThingy(sprint!.endContext.clears, sprint!.endContext.lines, sprint!.endContext.holds, sprint!.endContext.tSpins), if (sprint != null) Text("${sprint!.endContext.inputs} KP • ${f2.format(sprint!.endContext.kps)} KPS"), - Wrap( + if (sprint != null) Wrap( alignment: WrapAlignment.spaceBetween, crossAxisAlignment: WrapCrossAlignment.start, spacing: 20, @@ -1171,7 +1171,7 @@ class _TwoRecordsThingy extends StatelessWidget { if (blitz != null) FinesseThingy(blitz?.endContext.finesse, blitz?.endContext.finessePercentage), if (blitz != null) LineclearsThingy(blitz!.endContext.clears, blitz!.endContext.lines, blitz!.endContext.holds, blitz!.endContext.tSpins), if (blitz != null) Text("${blitz!.endContext.piecesPlaced} P • ${blitz!.endContext.inputs} KP • ${f2.format(blitz!.endContext.kpp)} KPP • ${f2.format(blitz!.endContext.kps)} KPS"), - Wrap( + if (blitz != null) Wrap( alignment: WrapAlignment.spaceBetween, crossAxisAlignment: WrapCrossAlignment.start, spacing: 20, diff --git a/lib/widgets/singleplayer_record.dart b/lib/widgets/singleplayer_record.dart index 3dd9209..5d19c94 100644 --- a/lib/widgets/singleplayer_record.dart +++ b/lib/widgets/singleplayer_record.dart @@ -126,7 +126,7 @@ class SingleplayerRecord extends StatelessWidget { LineclearsThingy(record!.endContext.clears, record!.endContext.lines, record!.endContext.holds, record!.endContext.tSpins), if (record!.endContext.gameType == "40l") Text("${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kps)} KPS"), if (record!.endContext.gameType == "blitz") Text("${record!.endContext.piecesPlaced} P • ${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kpp)} KPP • ${f2.format(record!.endContext.kps)} KPS"), - Wrap( + if (record != null) Wrap( alignment: WrapAlignment.spaceBetween, crossAxisAlignment: WrapCrossAlignment.start, spacing: 20,