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
2021-11-13 02:28:43 +01:00
const entriesPerPage = process . env . ENTRIES _PER _PAGE ? ? 50
2021-11-04 15:40:12 +01:00
/ * *
* 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 )
}
/ * *
* This function returns all data pertaining to all maps
* @ returns { array } An array contaning all map objects
* /
export function allMaps ( ) {
2021-11-13 02:28:43 +01:00
// This is kinda dumb
return searchMap (
"" ,
[ "Novice" , "Moderate" , "Brutal" , "Insane" , "Dummy" , "DDmaX" , "Oldschool" , "Solo" , "Race" , "Fun" ] ,
[ 0 , 1 , 2 , 3 , 4 , 5 ] , "release" , "desc" , 1 )
2021-11-04 15:40:12 +01:00
}
/ * *
* 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 ) {
2021-11-13 02:28:43 +01:00
let flag = skinDB . prepare ( ` SELECT COUNT(flag) as a, flag FROM skindata WHERE player = ? GROUP BY flag ORDER BY a DESC ` ) . get ( entry . player ) ? . flag ? ? "default"
2021-11-07 20:10:21 +01:00
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-13 02:28:43 +01:00
export function graphMap ( map , player ) {
let finishes
if ( player )
finishes = sqlite . prepare ( ` SELECT * FROM race WHERE map = ? AND player = ? ORDER BY date ` ) . all ( map , player )
else
finishes = sqlite . prepare ( ` SELECT * FROM graphRecordCache WHERE map = ? ORDER BY date ` ) . all ( map )
2021-11-05 09:36:43 +01:00
2021-11-05 11:56:31 +01:00
if ( ! finishes )
return undefined
2021-11-05 09:36:43 +01:00
let array = [ ]
2021-11-13 02:28:43 +01:00
let currentFinish
let currentBest = 0
2021-11-05 09:36:43 +01:00
2021-11-13 02:28:43 +01:00
for ( const record of finishes ) {
currentFinish = record . time
if ( currentFinish <= currentBest || currentBest == 0 ) {
currentBest = currentFinish
array . push ( { t : record . date , y : record . time , player : record . player } )
}
}
2021-11-05 09:36:43 +01:00
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"
2021-11-13 02:34:52 +01:00
* @ param { number } page Which page ?
2021-11-05 19:38:22 +01:00
*
* @ returns { array } Returns an array of all maps found
* /
2021-11-13 02:28:43 +01:00
export function searchMap ( query , categories , stars , sortBy , order , page ) {
2021-11-05 19:38:22 +01:00
const categoriesJoined = categories . join ( ',' )
const starsJoined = stars . join ( ',' )
let output = [ ]
2021-11-13 02:28:43 +01:00
// TODO: Would it be possible to NOT duplicate this?
const mapCount = sqlite . prepare ( `
SELECT COUNT ( * ) as a FROM maps WHERE map LIKE '%${query}%'
AND ',' || ? || ',' LIKE '%,' || category || ',%'
AND ',' || ? || ',' LIKE '%,' || stars || ',%' ` )
. get ( categoriesJoined , starsJoined ) . a
2021-11-05 19:38:22 +01:00
const maps = sqlite . prepare ( `
SELECT * FROM maps WHERE map LIKE '%${query}%'
AND ',' || ? || ',' LIKE '%,' || category || ',%'
AND ',' || ? || ',' LIKE '%,' || stars || ',%'
2021-11-13 02:28:43 +01:00
ORDER BY $ { simpleSanitize ( sortBy ) } $ { simpleSanitize ( order ) } LIMIT $ { entriesPerPage * ( page - 1 ) } , $ { entriesPerPage } ` )
. all ( categoriesJoined , starsJoined )
const totalPages = Math . ceil ( mapCount / 50 )
const pageInfo = { page , mapCount : mapCount , totalPages }
2021-11-05 19:38:22 +01:00
for ( const map of maps ) {
output . push ( prettyifyMap ( map ) )
}
2021-11-06 16:55:37 +01:00
2021-11-13 02:28:43 +01:00
return { "pageInfo" : pageInfo , "maps" : output }
2021-11-05 19:38:22 +01:00
}
2021-11-08 06:37:41 +01:00
2021-11-07 20:10:21 +01:00
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 {
2021-11-08 06:37:41 +01:00
player ,
2021-11-04 15:40:12 +01:00
finishedMaps ,
unfinishedMaps ,
2021-11-08 06:37:41 +01:00
2021-11-07 12:04:53 +01:00
leaderboardPoints ,
2021-11-08 06:37:41 +01:00
leaderboardRace ,
leaderboardTeamrace ,
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
allMaps ,
2021-11-05 19:38:22 +01:00
searchMap ,
2021-11-07 20:10:21 +01:00
mapToRegion ,
playerServer ,
2021-11-04 15:40:12 +01:00
}