Read player data endpoints (#48)

* player info and pdata endpoints
* add loadout and stats
* ratelimit category + name
This commit is contained in:
Barnaby 2022-04-05 22:46:56 +01:00 committed by GitHub
parent 23f6cf87ce
commit 78942467a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 219 additions and 2 deletions

View File

@ -26,7 +26,7 @@
"error",
"allman"
],
"no-mixed-spaces-and-tabs": "error",
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"eol-last": "error",
"linebreak-style": [
"error",

175
client/playerinfo.js Normal file
View File

@ -0,0 +1,175 @@
const path = require( "path" )
const { PLAYER_NOT_FOUND } = require( "../shared/errorcodes.js" )
const { ParseDefinition, PdataToJsonUntyped } = require( "../shared/pjson.js" )
const { getRatelimit } = require( "../shared/ratelimit.js" )
const accounts = require( path.join( __dirname, "../shared/accounts.js" ) )
const fs = require( "fs" )
const PLAYER_DATA_PDEF_231 = ParseDefinition( fs.readFileSync( "./persistent_player_data_version_231.pdef", "utf8" ) )
module.exports = ( fastify, opts, done ) =>
{
// exported routes
// GET /player/pdata
// show pdata for a given player as json
fastify.get( "/player/pdata",
{
config: { rateLimit: getRatelimit( "REQ_PER_MINUTE__PLAYER_DATA" ) }, // ratelimit
schema: {
querystring: {
id: { type: "string" }, // the id of the player to get stats of
}
}
},
async ( request ) =>
{
let account = await accounts.AsyncGetPlayerByID( request.query.id )
if( !account )
{
return { success: false, error: PLAYER_NOT_FOUND }
}
let pdata = PdataToJsonUntyped( account.persistentDataBaseline, PLAYER_DATA_PDEF_231 )
return pdata
} )
// GET /player/info
// show info for a given player as json
fastify.get( "/player/info",
{
config: { rateLimit: getRatelimit( "REQ_PER_MINUTE__PLAYER_DATA" ) }, // ratelimit
schema: {
querystring: {
id: { type: "string" }, // the id of the player to get stats of
}
}
},
async ( request ) =>
{
let account = await accounts.AsyncGetPlayerByID( request.query.id )
if( !account )
{
return { success: false, error: PLAYER_NOT_FOUND }
}
let pdata = PdataToJsonUntyped( account.persistentDataBaseline, PLAYER_DATA_PDEF_231 )
// define a filter for which properties are copied from the pdata
let filter = ["gen", "xp", "activeCallingCardIndex", "activeCallsignIconIndex", "activeCallsignIconStyleIndex", "netWorth"]
let pdataFiltered = Object.fromEntries(
filter
.map( key => [key, pdata[key]] )
)
let ret = {
name: account.username,
id: account.id
}
Object.assign( ret, pdataFiltered )
return ret
} )
// GET /player/stats
// show stats for a given player as json
fastify.get( "/player/stats",
{
config: { rateLimit: getRatelimit( "REQ_PER_MINUTE__PLAYER_DATA" ) }, // ratelimit
schema: {
querystring: {
id: { type: "string" }, // the id of the player to get stats of
}
}
},
async ( request ) =>
{
let account = await accounts.AsyncGetPlayerByID( request.query.id )
if( !account )
{
return { success: false, error: PLAYER_NOT_FOUND }
}
let pdata = PdataToJsonUntyped( account.persistentDataBaseline, PLAYER_DATA_PDEF_231 )
// define a filter for which properties are copied from the pdata
let filter = ["gen", "xp", "credits", "netWorth", "factionXP", "titanXP", "fdTitanXP", "gameStats", "mapStats", "timeStats",
"distanceStats", "weaponStats", "weaponKillStats", "killStats", "deathStats", "miscStats", "fdStats", "titanStats",
"kdratio_lifetime", "kdratio_lifetime_pvp", "winStreak", "highestWinStreakEver", ]
let pdataFiltered = Object.fromEntries(
filter
.map( key => [key, pdata[key]] )
)
let ret = {
id: account.id
}
Object.assign( ret, pdataFiltered )
return ret
} )
// GET /player/loadout
// show louadout data for a given player as json
fastify.get( "/player/loadout",
{
config: { rateLimit: getRatelimit( "REQ_PER_MINUTE__PLAYER_DATA" ) }, // ratelimit
schema: {
querystring: {
id: { type: "string" }, // the id of the player to get stats of
}
}
},
async ( request ) =>
{
let account = await accounts.AsyncGetPlayerByID( request.query.id )
if( !account )
{
return { success: false, error: PLAYER_NOT_FOUND }
}
let pdata = PdataToJsonUntyped( account.persistentDataBaseline, PLAYER_DATA_PDEF_231 )
// define a filter for which properties are copied from the pdata
let filter = ["factionChoice", "activePilotLoadout", "activeTitanLoadout", "pilotLoadouts", "titanLoadouts"]
let pdataFiltered = Object.fromEntries(
filter
.map( key => [key, pdata[key]] )
)
let ret = {
id: account.id
}
Object.assign( ret, pdataFiltered )
return ret
} )
done()
}
// might be useful at some point
// function StripPdataTypes( pdata )
// {
// if( typeof pdata != "object" ) return pdata
// let stripped = {}
// for( const [k, v] of Object.entries( pdata ) )
// {
// if( typeof v.value == "object" )
// {
// if( Array.isArray( v.value ) )
// {
// stripped[k] = v.value.map( val => StripPdataTypes( val ) )
// }
// else
// {
// stripped[k] = StripPdataTypes( v.value )
// }
// }
// else
// {
// stripped[k] = v.value
// }
// }
// return stripped
// }

View File

@ -28,9 +28,10 @@ REQ_PER_MINUTE__SERVER_HEARTBEAT=60
REQ_PER_MINUTE__SERVER_UPDATEVALUES=20
REQ_PER_MINUTE__SERVER_REMOVESERVER=5
REQ_PER_MINUTE__ACCOUNT_WRITEPERSISTENCE=50
REQ_PER_MINUTE__PLAYER_DATA=50
# origin
ORIGIN_ENABLE=1
ORIGIN_PERSIST_SID=1
ORIGIN_EMAIL=
ORIGIN_PASSWORD=
ORIGIN_PASSWORD=

View File

@ -332,6 +332,46 @@ function PdataToJson( pdata, pdef )
return ret
}
function PdataToJsonUntyped( pdata, pdef )
{
let ret = {}
let i = 0
function recursiveReadPdata( struct, base )
{
for ( let member of struct )
{
let arraySize = member.arraySize || 1
if ( typeof( arraySize ) == "string" )
arraySize = pdef.enums[ member.arraySize ].length
let retArray = []
for ( let j = 0; j < arraySize; j++ )
{
if ( member.type in NATIVE_TYPES )
{
retArray.push( NATIVE_TYPES[ member.type ].read( pdata, i, member.nativeArraySize ) )
i += NATIVE_TYPES[ member.type ].size * ( member.nativeArraySize || 1 )
}
else if ( member.type in pdef.enums )
retArray.push( pdef.enums[ member.type ][ pdata.readUInt8( i++ ) ] ) // enums are uint8s
else if ( member.type in pdef.structs )
{
let newStruct = {}
recursiveReadPdata( pdef.structs[ member.type ], newStruct )
retArray.push( newStruct )
}
}
base[ member.name ] = member.arraySize ? retArray : retArray[ 0 ]
}
}
recursiveReadPdata( pdef.members, ret )
return ret
}
//function PdataJsonToBuffer( json, pdef )
//{
@ -431,5 +471,6 @@ module.exports = {
ParseDefinitionDiff: ParseDefinitionDiff,
GetMemberSize: GetMemberSize,
PdataToJson: PdataToJson,
PdataToJsonUntyped: PdataToJsonUntyped,
PdataJsonToBuffer: PdataJsonToBuffer,
}