#include "MySQLDatabase.h" void MySQLDatabase::InsertPositionSamples(const std::vector& samples) { if (samples.empty()) return; const auto prevCommit = GetAutoCommit(); SetAutoCommit(false); for (const auto& sample : samples) { ExecuteInsert("REPLACE INTO player_positions (character_id, time, zone_id, instance_id, clone_id, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?);", sample.characterId, sample.time, sample.zoneId, sample.instanceId, sample.cloneId, sample.x, sample.y, sample.z); } Commit(); SetAutoCommit(prevCommit); } std::vector MySQLDatabase::GetPositionSamples(uint32_t zoneId, uint32_t instanceId, int64_t from, int64_t to, int64_t bucketSeconds, uint32_t limit) { const std::string instance = instanceId ? " AND instance_id = ?" : ""; const std::string query = bucketSeconds > 1 ? "SELECT character_id, instance_id, MAX(clone_id) AS clone_id, MIN(time) AS t, AVG(x) AS x, AVG(y) AS y, AVG(z) AS z FROM player_positions " "WHERE zone_id = ? AND time BETWEEN ? AND ?" + instance + " GROUP BY character_id, instance_id, FLOOR(time / ?) ORDER BY character_id, t LIMIT ?;" : "SELECT character_id, instance_id, clone_id, time AS t, x, y, z FROM player_positions WHERE zone_id = ? AND time BETWEEN ? AND ?" + instance + " ORDER BY character_id, t LIMIT ?;"; auto result = bucketSeconds > 1 ? (instanceId ? ExecuteSelect(query, zoneId, from, to, instanceId, bucketSeconds, limit) : ExecuteSelect(query, zoneId, from, to, bucketSeconds, limit)) : (instanceId ? ExecuteSelect(query, zoneId, from, to, instanceId, limit) : ExecuteSelect(query, zoneId, from, to, limit)); std::vector samples; while (result->next()) { samples.push_back({ result->getInt64("t"), result->getInt64("character_id"), zoneId, result->getUInt("instance_id"), result->getUInt("clone_id"), static_cast(result->getDouble("x")), static_cast(result->getDouble("y")), static_cast(result->getDouble("z")) }); } return samples; } std::vector MySQLDatabase::GetPositionInstances(uint32_t zoneId, int64_t from, int64_t to) { const std::string query = "SELECT zone_id, instance_id, MAX(clone_id) AS clone_id, MIN(time) AS first, MAX(time) AS last, COUNT(DISTINCT character_id) AS players " "FROM player_positions WHERE time BETWEEN ? AND ?" + std::string(zoneId ? " AND zone_id = ?" : "") + " GROUP BY zone_id, instance_id ORDER BY last DESC LIMIT 500;"; auto result = zoneId ? ExecuteSelect(query, from, to, zoneId) : ExecuteSelect(query, from, to); std::vector instances; while (result->next()) { instances.push_back({ result->getUInt("zone_id"), result->getUInt("instance_id"), result->getUInt("clone_id"), result->getInt64("first"), result->getInt64("last"), result->getUInt("players") }); } return instances; } uint32_t MySQLDatabase::PrunePositionSamples(int64_t beforeTime) { return static_cast(ExecuteUpdate("DELETE FROM player_positions WHERE time < ?;", beforeTime)); } nlohmann::json MySQLDatabase::GetMapCellsPerDay(uint32_t zoneId, std::optional cloneId, uint8_t kind, uint32_t fromDay, uint32_t toDay, uint32_t limit) { const std::string clone = cloneId ? " AND clone_id = " + std::to_string(*cloneId) : ""; auto result = ExecuteSelect("SELECT day, cell_x, cell_z, SUM(events) AS events FROM map_events_daily WHERE zone = ? AND kind = ? AND day BETWEEN ? AND ?" + clone + " GROUP BY day, cell_x, cell_z ORDER BY day, cell_x, cell_z LIMIT ?;", zoneId, static_cast(kind), fromDay, toDay, limit); nlohmann::json rows = nlohmann::json::array(); while (result->next()) { rows.push_back({ {"day", result->getInt("day")}, {"x", result->getInt("cell_x")}, {"z", result->getInt("cell_z")}, {"events", result->getInt64("events")} }); } return rows; } nlohmann::json MySQLDatabase::GetCloneVisitors(uint32_t zoneId, uint32_t cloneId, int64_t from, int64_t to, uint32_t limit) { auto result = ExecuteSelect("SELECT p.character_id, COALESCE(c.name, '') AS name, MIN(p.time) AS first, MAX(p.time) AS last FROM player_positions p " "LEFT JOIN charinfo c ON c.id = p.character_id WHERE p.zone_id = ? AND p.clone_id = ? AND p.time BETWEEN ? AND ? " "GROUP BY p.character_id, c.name ORDER BY last DESC, p.character_id LIMIT ?;", zoneId, cloneId, from, to, limit); nlohmann::json rows = nlohmann::json::array(); while (result->next()) { rows.push_back({ {"character_id", std::to_string(result->getInt64("character_id"))}, {"name", std::string(result->getString("name").c_str())}, {"first", result->getInt64("first")}, {"last", result->getInt64("last")} }); } return rows; }