X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=events.cpp;h=3b072ec54d31fddfdc8d6de2e983c81d0b04d513;hb=60dc34deda46a19db619517a332bf37523ec1086;hp=e6ed5796340ff3521ab051512f25920d1d04c022;hpb=0c2456af6161a3e5b0accdcd7bdfca59a75a446e;p=pkanalytics diff --git a/events.cpp b/events.cpp index e6ed579..3b072ec 100644 --- a/events.cpp +++ b/events.cpp @@ -24,7 +24,7 @@ QVariant EventsModel::headerData(int section, Qt::Orientation orientation, int r if (section == 0) { return "Time"; } else if (section == 1) { - return "Player"; + return "Who/what"; } else { return "Type"; } @@ -42,10 +42,15 @@ QVariant EventsModel::data(const QModelIndex &index, int role) const return QString::fromUtf8(format_timestamp(events[index.row()].t)); } else if (index.column() == 1) { optional player_id = events[index.row()].player_id; + optional formation_id = events[index.row()].formation_id; if (player_id) { auto p_it = players.find(*player_id); const Player &p = p_it->second; return QString::fromUtf8(p.name + " (" + p.number + ")"); + } else if (formation_id) { + auto f_it = formations.find(*formation_id); + const Formation &f = f_it->second; + return QString::fromUtf8(f.name); } else { return QVariant(); } @@ -90,8 +95,34 @@ void EventsModel::load_data() abort(); } + // Read the formations. + ret = sqlite3_prepare_v2(db, "SELECT formation, name FROM formation", -1, &stmt, 0); + if (ret != SQLITE_OK) { + fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); + abort(); + } + for ( ;; ) { + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) { + Formation f; + f.formation_id = sqlite3_column_int(stmt, 0); + f.name = (const char *) sqlite3_column_text(stmt, 1); + formations[f.formation_id] = std::move(f); + } else if (ret == SQLITE_DONE) { + break; + } else { + fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); + abort(); + } + } + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) { + fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); + abort(); + } + // Read the events. - ret = sqlite3_prepare_v2(db, "SELECT event, t, player, type FROM event WHERE match=? ORDER BY t", -1, &stmt, 0); + ret = sqlite3_prepare_v2(db, "SELECT event, t, player, formation, type FROM event WHERE match=? ORDER BY t", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); abort(); @@ -106,7 +137,10 @@ void EventsModel::load_data() if (sqlite3_column_type(stmt, 2) == SQLITE_INTEGER) { // Non-NULL. e.player_id = sqlite3_column_int(stmt, 2); } - e.type = (const char *)sqlite3_column_text(stmt, 3); + if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) { // Non-NULL. + e.formation_id = sqlite3_column_int(stmt, 3); + } + e.type = (const char *)sqlite3_column_text(stmt, 4); events.push_back(std::move(e)); } else if (ret == SQLITE_DONE) { break; @@ -122,7 +156,7 @@ void EventsModel::load_data() } } -unsigned EventsModel::insert_event(uint64_t t, optional player_id, const string &type) +unsigned EventsModel::insert_event(uint64_t t, optional player_id, optional formation_id, const string &type) { auto it = lower_bound(events.begin(), events.end(), t, [](const Event &e, uint64_t t) { return e.t < t; }); @@ -139,7 +173,7 @@ unsigned EventsModel::insert_event(uint64_t t, optional player_id, const st // Insert the new row into the database. sqlite3_stmt *stmt; - int ret = sqlite3_prepare_v2(db, "INSERT INTO event (match, t, player, type) VALUES (?, ?, ?, ?)", -1, &stmt, 0); + int ret = sqlite3_prepare_v2(db, "INSERT INTO event (match, t, player, formation, type) VALUES (?, ?, ?, ?, ?)", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db)); abort(); @@ -152,7 +186,12 @@ unsigned EventsModel::insert_event(uint64_t t, optional player_id, const st } else { sqlite3_bind_null(stmt, 3); } - sqlite3_bind_text(stmt, 4, type.data(), type.size(), SQLITE_STATIC); + if (formation_id) { + sqlite3_bind_int64(stmt, 4, *formation_id); + } else { + sqlite3_bind_null(stmt, 4); + } + sqlite3_bind_text(stmt, 5, type.data(), type.size(), SQLITE_STATIC); ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { @@ -385,16 +424,44 @@ void EventsModel::set_team_at(uint64_t t, const set &new_team) set old_team = get_team_at(backdate_point); for (int player_id : old_team) { if (!new_team.count(player_id)) { - insert_event(backdate_point, player_id, "out"); + insert_event(backdate_point, player_id, nullopt, "out"); } } for (int player_id : new_team) { if (!old_team.count(player_id)) { - insert_event(backdate_point, player_id, "in"); + insert_event(backdate_point, player_id, nullopt, "in"); } } } +void EventsModel::set_formation_at(uint64_t t, bool offense, unsigned formation) +{ + // If there's another goal/stoppage no more than 20 seconds ago, + // we assume that the formation started at that point (it just took + // the operator a bit of time to see it). If not, we assume we + // changed in the middle of a point. + uint64_t backdate_point = 0; + for (const Event &e : events) { + if (e.t > t) { + break; + } + if (e.type == "goal" || e.type == "their_goal" || e.type == "stoppage" || e.type == "reset" || e.type == "set_offense" || e.type == "set_defense" || e.type == "in" || e.type == "out" || e.type == "pull" || e.type == "their_pull") { + backdate_point = e.t + 1; + } + if (e.type == "formation_offense" || e.type == "formation_defense") { + backdate_point = 0; + } + } + if (backdate_point != 0 && t - backdate_point < 20000) { + t = backdate_point; + } + if (offense) { + insert_event(t, nullopt, formation, "formation_offense"); + } else { + insert_event(t, nullopt, formation, "formation_defense"); + } +} + vector EventsModel::sort_team(const set &team) const { vector ret(team.begin(), team.end());