2021-11-07 20:10:21 +01:00
|
|
|
import { sqlite, skinDB } from './init.js'
|
2021-11-05 19:38:22 +01:00
|
|
|
import { simpleSanitize } from './searcher.js'
|
2021-11-04 15:40:12 +01:00
|
|
|
/**
|
|
|
|
* This function checks if a player exists
|
|
|
|
*
|
|
|
|
* @param {string} player The player to check
|
|
|
|
|
|
|
|
* @returns {boolean} Returns a boolean
|
|
|
|
*/
|
|
|
|
export function playerExists(player) {
|
|
|
|
const exists = sqlite.prepare(`SELECT * FROM points WHERE player = ? LIMIT 1`).get(player)
|
|
|
|
|
|
|
|
if(exists)
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function checks if a map exists
|
|
|
|
*
|
|
|
|
* @param {string} player The map to check
|
|
|
|
|
|
|
|
* @returns {boolean} Returns a boolean
|
|
|
|
*/
|
|
|
|
export function mapExists(map) {
|
|
|
|
const exists = sqlite.prepare(`SELECT * FROM maps WHERE map = ? LIMIT 1`).get(map)
|
|
|
|
|
|
|
|
if(exists)
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function checks if a map category exists
|
|
|
|
*
|
|
|
|
* @param {string} player The category to check
|
|
|
|
|
|
|
|
* @returns {boolean} Returns a boolean
|
|
|
|
*/
|
|
|
|
export function categoryExists(category) {
|
|
|
|
const exists = sqlite.prepare(`SELECT category FROM maps WHERE category = ? LIMIT 1`).get(category)
|
|
|
|
|
|
|
|
if(exists)
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns all data pertaining a certain player
|
|
|
|
*
|
|
|
|
* @param {string} player The player to fetch
|
|
|
|
|
|
|
|
* @returns {object} An object containing the players data
|
|
|
|
*/
|
|
|
|
export function player(player) {
|
|
|
|
/* Misc */
|
|
|
|
const firstFinish = sqlite.prepare(`SELECT map, time, date, server FROM race WHERE player = ? ORDER BY date ASC LIMIT 1`).get(player)
|
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!firstFinish)
|
|
|
|
return undefined
|
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
/* Points */
|
|
|
|
let points = {}
|
|
|
|
let rank = {}
|
|
|
|
|
|
|
|
const pointsData = sqlite.prepare(`SELECT * FROM points WHERE player = ?`)
|
|
|
|
|
|
|
|
for (const pointsType of pointsData.iterate(player)) {
|
|
|
|
rank[pointsType.type] = pointsType.rank
|
|
|
|
}
|
|
|
|
for (const pointsType of pointsData.iterate(player)) {
|
|
|
|
points[pointsType.type] = pointsType.points
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
player,
|
|
|
|
firstFinish,
|
|
|
|
points,
|
|
|
|
rank,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns all data pertaining a certain map
|
|
|
|
*
|
|
|
|
* @param {string} map The map to fetch
|
|
|
|
|
|
|
|
* @returns {object} An object containing map data
|
|
|
|
*/
|
|
|
|
export function map(map) {
|
|
|
|
const a = sqlite.prepare(`
|
|
|
|
SELECT * FROM maps WHERE map = ?
|
|
|
|
`).get(map)
|
|
|
|
|
|
|
|
return prettyifyMap(a)
|
|
|
|
}
|
|
|
|
|
|
|
|
export function mapCategory(category) {
|
|
|
|
let output = []
|
|
|
|
const maps = sqlite.prepare(`
|
|
|
|
SELECT * FROM maps WHERE category = ?`).all(category)
|
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!maps)
|
|
|
|
return undefined
|
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
for(const map of maps) {
|
|
|
|
output.push(prettyifyMap(map))
|
|
|
|
}
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns all data pertaining to all maps
|
|
|
|
|
|
|
|
* @returns {array} An array contaning all map objects
|
|
|
|
*/
|
|
|
|
export function allMaps() {
|
|
|
|
let output = []
|
|
|
|
const maps = sqlite.prepare(`
|
|
|
|
SELECT * FROM maps`).all()
|
|
|
|
|
|
|
|
for(const map of maps) {
|
|
|
|
output.push(prettyifyMap(map))
|
|
|
|
}
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns all data pertaining a certain map
|
|
|
|
*
|
|
|
|
* @param {string} map The map to fetch
|
|
|
|
|
|
|
|
* @returns {object} An object containing map data
|
|
|
|
*/
|
|
|
|
export function prettyifyMap(a) {
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!a)
|
|
|
|
return undefined
|
2021-11-04 15:40:12 +01:00
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
let output = {
|
2021-11-04 15:40:12 +01:00
|
|
|
map: a.map,
|
|
|
|
category: a.category,
|
|
|
|
points: a.points,
|
|
|
|
stars: a.stars,
|
|
|
|
release: a.release,
|
|
|
|
mappers: a.mapper.split(" & "),
|
|
|
|
|
|
|
|
times: {
|
|
|
|
average: a.avgTime,
|
|
|
|
median: a.medianTime,
|
|
|
|
topTime: a.topTime,
|
|
|
|
topTimeTeam: (a.topTeamTime != -1) ? a.topTeamTime : undefined,
|
|
|
|
},
|
|
|
|
finishes: {
|
|
|
|
total: a.finishesTotal,
|
|
|
|
team: a.finishesTeam,
|
|
|
|
unique: a.finishesUnique,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns the race leaderboard for a map
|
|
|
|
*
|
|
|
|
* @param {string} map The map to check
|
|
|
|
* @param {number} start At which rank the leaderboard should begin
|
|
|
|
* @param {number} end At which rank the leaderboard should end
|
|
|
|
|
|
|
|
* @returns {array} An array containing the leaderboard
|
|
|
|
*/
|
|
|
|
export function leaderboardRace(map, start, end) {
|
|
|
|
const leaderboard = sqlite.prepare(`
|
2021-11-05 11:56:31 +01:00
|
|
|
SELECT rank, time, date, player, server FROM rankings WHERE map = ? LIMIT ?, ?`)
|
|
|
|
.all(map, start -1, end)
|
2021-11-04 15:40:12 +01:00
|
|
|
|
|
|
|
return leaderboard
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns the teamrace leaderboard for a map
|
|
|
|
*
|
|
|
|
* @param {string} map The map to check
|
|
|
|
* @param {number} start At which rank the leaderboard should begin
|
|
|
|
* @param {number} end At which rank the leaderboard should end
|
|
|
|
|
|
|
|
* @returns {array} An array containing the leaderboard
|
|
|
|
*/
|
|
|
|
export function leaderboardTeamrace(map, start, end) {
|
|
|
|
// TODO: Optimize array creation of players
|
|
|
|
let leaderboard = []
|
|
|
|
|
|
|
|
const a = sqlite.prepare(`
|
|
|
|
SELECT teamrank, time, date, player, server FROM teamrankings WHERE map = ? AND teamrank >= ? AND teamrank <= ? GROUP BY teamrank`)
|
|
|
|
|
|
|
|
for(const teamrank of a.iterate(map, start, end)) {
|
|
|
|
let players = []
|
|
|
|
const b = sqlite.prepare(`SELECT player FROM teamrankings WHERE map = ? AND teamrank = ?`)
|
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!b)
|
|
|
|
return undefined
|
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
for(const player of b.iterate(map, teamrank.teamrank)) {
|
|
|
|
players.push(player.player)
|
|
|
|
}
|
|
|
|
leaderboard.push({
|
|
|
|
teamrank: teamrank.teamrank,
|
|
|
|
time: teamrank.time,
|
|
|
|
date: teamrank.date,
|
|
|
|
server: teamrank.server,
|
|
|
|
players: players,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return leaderboard
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns the points leaderboard for a specific type
|
|
|
|
* (points, pointsRank, pointsTeam, pointsThisWeek, pointsThisMonth)
|
|
|
|
*
|
|
|
|
* @param {string} type Which type of points to fetch
|
2021-11-07 20:10:21 +01:00
|
|
|
* @param {string} region Which region should be included (Global, Europe, Asia, SA, NA, Africa, ME, OLD, Other)
|
2021-11-04 15:40:12 +01:00
|
|
|
* @param {number} start At which rank the leaderboard should begin
|
|
|
|
* @param {number} end At which rank the leaderboard should end
|
|
|
|
|
|
|
|
* @returns {array} An array containing the leaderboard
|
|
|
|
*/
|
2021-11-07 20:10:21 +01:00
|
|
|
export function leaderboardPoints(type, region, start, end) {
|
|
|
|
let output = []
|
|
|
|
let leaderboard
|
2021-11-04 15:40:12 +01:00
|
|
|
|
2021-11-07 20:10:21 +01:00
|
|
|
if(region == "Global") {
|
|
|
|
leaderboard = sqlite.prepare(`
|
|
|
|
SELECT rank, region, player, points FROM points WHERE type = ? AND rank >= ? AND rank <= ? ORDER BY rank`)
|
|
|
|
.all(type, start, end)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
leaderboard = sqlite.prepare(`
|
|
|
|
SELECT rank, region, player, points FROM points WHERE type = ? AND region = ? ORDER BY rank ASC LIMIT ?, ${end}`)
|
|
|
|
.all(type, region, start - 1)
|
|
|
|
}
|
2021-11-07 21:56:46 +01:00
|
|
|
let rank = 1
|
2021-11-07 20:10:21 +01:00
|
|
|
for (const entry of leaderboard) {
|
|
|
|
let flag = skinDB.prepare(`SELECT flag FROM skindata WHERE player = ?`).get(entry.player)?.flag ?? "default"
|
|
|
|
|
2021-11-07 21:56:46 +01:00
|
|
|
output.push({ rank: rank, global: entry.rank, player: entry.player, points: entry.points, region: entry.region, flag: flag })
|
2021-11-07 21:57:45 +01:00
|
|
|
++rank
|
2021-11-07 20:10:21 +01:00
|
|
|
}
|
|
|
|
return output
|
2021-11-04 15:40:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns all finished maps by a specific player
|
|
|
|
* togheter with their respective rank, teamrank, amount of finishes.
|
|
|
|
* Finishes are grouped by map category (Novice, Brutal)
|
|
|
|
*
|
|
|
|
* @param {string} player The player to check
|
|
|
|
|
|
|
|
* @returns {object} An object containing all finishes grouped by category
|
|
|
|
*/
|
|
|
|
export function finishedMaps(player) {
|
|
|
|
const finishesStmt = sqlite.prepare(
|
|
|
|
`
|
|
|
|
SELECT a.map,
|
|
|
|
a.category,
|
|
|
|
a.points,
|
|
|
|
a.rank,
|
|
|
|
b.teamrank,
|
|
|
|
a.finishes
|
|
|
|
FROM rankings AS a
|
|
|
|
LEFT OUTER JOIN teamrankings AS b
|
|
|
|
ON a.player = b.player
|
|
|
|
AND a.category = b.category
|
|
|
|
AND a.map = b.map
|
|
|
|
WHERE a.player = ?
|
|
|
|
`)
|
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!finishesStmt)
|
|
|
|
return undefined
|
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
let finishes = {
|
|
|
|
Novice: [],
|
|
|
|
Moderate: [],
|
|
|
|
Brutal: [],
|
|
|
|
Insane: [],
|
|
|
|
Dummy: [],
|
|
|
|
DDmaX: [],
|
|
|
|
Oldschool: [],
|
|
|
|
Solo: [],
|
|
|
|
Race: [],
|
|
|
|
Fun: []
|
|
|
|
}
|
|
|
|
for (const finish of finishesStmt.iterate(player)) {
|
|
|
|
finishes[finish.category].push(finish)
|
|
|
|
}
|
|
|
|
|
|
|
|
return finishes
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function returns all unfinished maps by a specific player
|
|
|
|
* togheter with category, points, finishTotal and medianTime.
|
|
|
|
* Maps are grouped by the map category (Novice, Brutal)
|
|
|
|
*
|
|
|
|
* @param {string} player The player to check
|
|
|
|
|
|
|
|
* @returns {object} An object containing all unfinished maps
|
|
|
|
*/
|
|
|
|
export function unfinishedMaps(player) {
|
|
|
|
const maps = sqlite.prepare(
|
|
|
|
`
|
|
|
|
SELECT a.map,
|
|
|
|
a.category,
|
|
|
|
a.points,
|
|
|
|
b.finishesTotal,
|
|
|
|
b.medianTime
|
|
|
|
FROM (SELECT category,
|
|
|
|
map,
|
|
|
|
points
|
|
|
|
FROM maps
|
|
|
|
WHERE map NOT IN (SELECT map
|
|
|
|
FROM rankings
|
|
|
|
WHERE player = ? )) AS a
|
|
|
|
JOIN maps AS b
|
|
|
|
ON a.category = b.category
|
|
|
|
AND a.map = b.map
|
|
|
|
ORDER BY b.category ASC;
|
|
|
|
`)
|
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!maps)
|
|
|
|
return undefined
|
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
let unfinished = {
|
|
|
|
Novice: [],
|
|
|
|
Moderate: [],
|
|
|
|
Brutal: [],
|
|
|
|
Insane: [],
|
|
|
|
Dummy: [],
|
|
|
|
DDmaX: [],
|
|
|
|
Oldschool: [],
|
|
|
|
Solo: [],
|
|
|
|
Race: [],
|
|
|
|
Fun: []
|
|
|
|
}
|
|
|
|
for (const map of maps.iterate(player)) {
|
|
|
|
unfinished[map.category].push(map)
|
|
|
|
}
|
|
|
|
|
|
|
|
return unfinished
|
|
|
|
}
|
|
|
|
|
2021-11-05 09:36:43 +01:00
|
|
|
export function graphMap(map) {
|
|
|
|
const finishes = sqlite.prepare(`SELECT * FROM graphRecordCache WHERE map = ? ORDER BY date`)
|
|
|
|
|
2021-11-05 11:56:31 +01:00
|
|
|
if(!finishes)
|
|
|
|
return undefined
|
|
|
|
|
2021-11-05 09:36:43 +01:00
|
|
|
let array = []
|
|
|
|
for (const record of finishes.iterate(map))
|
|
|
|
array.push({ t: record.date, y: record.time, player: record.player})
|
|
|
|
|
|
|
|
return array
|
|
|
|
}
|
2021-11-05 19:38:22 +01:00
|
|
|
/**
|
|
|
|
* This searches the DB for maps
|
|
|
|
*
|
|
|
|
* @param {string} query The query to search for
|
|
|
|
* @param {array} categories Which categories to be searched ["Novice", "Insane"]
|
|
|
|
* @param {array} stars Only include maps with a specific amount of stars [1, 5]
|
|
|
|
* @param {string} sortBy What to sort after
|
|
|
|
* @param {string} order "ASC" | "DESC"
|
|
|
|
*
|
|
|
|
* @returns {array} Returns an array of all maps found
|
|
|
|
*/
|
|
|
|
export function searchMap(query, categories, stars, sortBy, order) {
|
|
|
|
const categoriesJoined = categories.join(',')
|
|
|
|
const starsJoined = stars.join(',')
|
|
|
|
|
|
|
|
let output = []
|
|
|
|
const maps = sqlite.prepare(`
|
|
|
|
SELECT * FROM maps WHERE map LIKE '%${query}%'
|
|
|
|
AND ',' || ? || ',' LIKE '%,' || category || ',%'
|
|
|
|
AND ',' || ? || ',' LIKE '%,' || stars || ',%'
|
|
|
|
ORDER BY ? ${simpleSanitize(order)}`)
|
|
|
|
.all(categoriesJoined, starsJoined, sortBy)
|
|
|
|
|
|
|
|
for(const map of maps) {
|
|
|
|
output.push(prettyifyMap(map))
|
|
|
|
}
|
2021-11-06 16:55:37 +01:00
|
|
|
|
|
|
|
return output
|
2021-11-05 19:38:22 +01:00
|
|
|
}
|
2021-11-07 20:10:21 +01:00
|
|
|
/*
|
|
|
|
Europe
|
|
|
|
/ RUS - Russia
|
|
|
|
/ GER - Germany
|
|
|
|
/ NLD - Netherlands
|
|
|
|
/ TUR - Turkey
|
|
|
|
/ POL - Poland
|
|
|
|
/ FRA - France
|
|
|
|
|
|
|
|
Asia
|
|
|
|
/ IND - INDIA
|
|
|
|
/ SGP - Singapore
|
|
|
|
/ CHN - China
|
|
|
|
/ JAP - Japan
|
|
|
|
/ KOR - South Korea
|
|
|
|
|
|
|
|
South America
|
|
|
|
/ COL - Columbia
|
|
|
|
/ ARG - Argentina
|
|
|
|
/ CHL - Chile
|
|
|
|
/ BRA - Brazil
|
|
|
|
|
|
|
|
North America
|
|
|
|
/ CAN - Cananda
|
|
|
|
/ USA - USA
|
|
|
|
|
|
|
|
Africa
|
|
|
|
/ ZAF - South Africa
|
|
|
|
|
|
|
|
Middle east
|
|
|
|
/ KSA/UAE/IRN
|
|
|
|
|
|
|
|
Others
|
|
|
|
/ CRI - Costa Rica
|
|
|
|
/ AUS - Australia
|
|
|
|
/ OLD ranks (NA/EU)
|
|
|
|
/ UNK - Some bugged ranks
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function mapToRegion(srv) {
|
|
|
|
if(srv == "RUS" || srv == "GER" || srv == "NLD" || srv == "TUR" || srv == "POL" || srv == "FRA")
|
|
|
|
return "Europe"
|
|
|
|
|
|
|
|
if(srv == "IND" || srv == "SGP" || srv == "CHN" || srv == "JAP" || srv == "KOR")
|
|
|
|
return "Asia"
|
|
|
|
|
|
|
|
if(srv == "COL" || srv == "ARG" || srv == "CHL" || srv == "BRA")
|
|
|
|
return "SA"
|
|
|
|
|
|
|
|
if(srv == "CAN" || srv == "USA")
|
|
|
|
return "NA"
|
|
|
|
|
|
|
|
if(srv == "ZAF")
|
|
|
|
return "Africa"
|
|
|
|
|
|
|
|
/* Middle east */
|
|
|
|
if(srv == "KSA" || srv == "UAE" || srv == "IRN")
|
|
|
|
return "ME"
|
|
|
|
|
|
|
|
if(srv == "")
|
|
|
|
return "OLD"
|
|
|
|
|
|
|
|
return "Other"
|
|
|
|
}
|
|
|
|
|
|
|
|
export function playerServer(player) {
|
|
|
|
/* This can be undefined if a player has changed their name */
|
|
|
|
const server = sqlite.prepare(
|
|
|
|
`SELECT server, COUNT(server) as a FROM rankings WHERE player = ? GROUP BY server ORDER BY a DESC`)
|
|
|
|
.get(player)?.server ?? ""
|
|
|
|
|
|
|
|
return server
|
|
|
|
}
|
|
|
|
|
2021-11-05 19:38:22 +01:00
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
export default {
|
|
|
|
playerExists,
|
|
|
|
finishedMaps,
|
|
|
|
unfinishedMaps,
|
|
|
|
player,
|
2021-11-07 12:04:53 +01:00
|
|
|
leaderboardPoints,
|
2021-11-07 12:20:31 +01:00
|
|
|
|
2021-11-04 15:40:12 +01:00
|
|
|
map,
|
2021-11-05 09:36:43 +01:00
|
|
|
graphMap,
|
2021-11-04 15:40:12 +01:00
|
|
|
mapCategory,
|
|
|
|
allMaps,
|
|
|
|
mapExists,
|
2021-11-05 19:38:22 +01:00
|
|
|
searchMap,
|
2021-11-04 15:40:12 +01:00
|
|
|
leaderboardRace,
|
|
|
|
leaderboardTeamrace,
|
|
|
|
categoryExists,
|
2021-11-07 20:10:21 +01:00
|
|
|
|
|
|
|
mapToRegion,
|
|
|
|
playerServer,
|
2021-11-04 15:40:12 +01:00
|
|
|
}
|