battlerite-api a javascript wrapper for the battlerite API
A modular API wrapper for the Battlerite Developer API. Currently there is a module that provides a simple endpoint querystring
=> json object
function. (lib/node-api.js
) I plan to write a function that provides the same interface for the browser. A second module (lib/lib.js
) consumes the first and provides an fully featured JavaScript API interface. An entrypoint for inclusion in node.js programs is provided in index.js
Last known to be compatible with
Battlerite API v1.5.0
Gamelocker API v7.6.0
My approach is decidedly more minimal than either of those, using much less code and no dependencies. I don't think this is better, just different.
This is a tool which provides a wrapper around the internal API as used by the game itself, unfortunately that API is about a thousand times more useful than the official one, though to Stunlock's credit, they're updating quick.
You're going to want to have a recent node.
npm i -s battlerite-dev
Initiialize the API like so
const Battlerite_Dev = require('battlerite-dev')
const api = new Battlerite_Dev({key: "your_very_long_api_key"})
a function exists corresponding to each API endpoint, consuming an options
object and returning a promise that resolves to the requested JSON, for example:
api.status().then(r => console.log(r))
or
let options = {
filter: {
gameMode: ['ranked','casual']
}
}
api.matches(options).then(r => console.log(r))
or
api.match('id_hash_as_string').then(r => console.log(r))
the options object is a simple JSON representation of the possibly filter queries for the API
interface Options {
sort: "createdAt" | "-createdAt"
page: {
offset: number //number of matches to offset start of return data
limit: number //max number of matches to report
},
filter: {
createdAt: {
start: //TODO look up what this is supposed to be
end:
},
teamNames: any // no idea, anything i've tried returns a 404
playerIds: string | string[] //returns matches that include ALL playersIds
gameMode: number //only works with 1733162751, maybe there's anotherone for the battleground mode
}
}
returns a promise that resolves to the API response
returns a promise that resolves to the API response
returns a promise detailing the API status, you don't need an API key for this one
takes a single playerid as a string or an array of up to 6 playerid strings returns a promise that resolves to the API response for the players endpoint
same as matches
same as matches
returns a promise that resolves to an array of telemetry objects be aware that this consumes a call to the battlerite API to fetch the telemetry URL
interface TelemetryOptions {
url: boolean //if true returns just the URL
}
returns a promise that resolves to an array of telemetry objects using the full url this is useful when you've already got match data retrieved somewhere as calls to the telemetry api are not rate-limited and do not require an API key
The matches endpoint doesn't quite behave as the docs state.
Not only that, but there's currently no way of getting a playerId <=> playerName relationship using the official api, if you hit the unofficial API though you can get the data
filter[gameMode]
returns a 404 if you use ranked
or casual
as the filterstring, but it does work if you use 1733162751
, which is sent as the data.attributes.gameMode
with every(?) match right now
filter[teamName]
returns a 404 regardless of query? i've tried the team name as a string, and also the long id hash that is provided in roster objects
when retrieving a match, you can only count on some of the data to be present in player.stats, things like the meaningless "attachment" or "emote" numbers are always there, damage is not :(
type TelemetryType =
| 'Structures.UserRoundSpell'
| 'Structures.RoundEvent'
| 'Structures.DeathEvent'
| 'Structures.MatchReservedUser'
| 'Structures.RoundFinishedEvent'
| 'Structures.MatchFinishedEvent'
| 'Structures.MatchStart'
| 'Structures.ServerShutdown'
| 'com.stunlock.battlerite.team.TeamUpdateEvent'
| 'com.stunlock.service.matchmaking.avro.QueueEven'
interface TelemetryObject {
cursor: number //not sure
type: TelemetryType
dataObject : TelemetryData
}
interface TelemetryData {
matchID: string
time: number
[prop: string]: any
}
type Telemetry = TememetryObject[]
interface MatchStart extends TelemetryData {
gameMode: number
mapID: string
matchID: string
region: string
teamSize: number
type: string //same as servertype in reserveduser
version: string //"1.0"
}
interface MatchFinishedEvent extends TelemetryData {
region: string // "us_southwest", "us_southeast", "us_west"
matchLength: number
teamOneScore: number
teamTwoScore: number
leavers: array
}
the most interesting data end up here, mostly per-round score for the players
interface RoundFinishedEvent extends TelemetryData {
winningTeam: number //one indexed because fuck you
round: number //zero indexed because zero consistency
roundLength: number //in seconds, as an int
playerStats: PlayerStats[]
}
interface PlayerStats {
userID: string
abilityUses: number
damageDone: number
damageReceived: number
disablesDone: number
disablesReceived: number
healingDone: number
healingReceived: number
energyGained: number
energyUsed: number
kills: number // this may be some sort of binary encoding? it's not the # of player kills for sure
deaths: number
score: number
timeAlive: number
}
interface RoundEvent extends TelemetryData {
character: number
round: number
timeIntoRound: number //as far as I can tell this is always zero
type: string //"MOUNT_DURATION", "ENERGY_ABILITY_USED", "ENERGY_SHARD_PICKUP", "HEALTH_SHARD_PICKUP", "ULTIMATE_USED", "MOUNTS_AFTER_ELEVATOR", "RUNE_LASTHIT", "ALLY_DEATH_ENERGY_PICKUP"
value: number
}
some data about each user, there's one of these for every user in a match
interface MatchReservedUser extends TelemetryData {
accountId: string //same as userID except with inconsistent caps
attachment: number
character: number //character id same as actor?
characterLevel: number
characterTimePlayed: number
division: number
divisionRating: number
emote: number
league: number
mount: number
outfit: number
rankingType: string //"RANKED" | "UNRANKED" | "NONE" maybe one more?
seasonId: number
serverType: string // "QUICK2V2" | "PRIVATE" | "QUICK3V3" there may also be additional ones
team: number
teamId: string
totalTimePlayed: number
}
gives the death times of users, curiously it doesn't mention in which round the death occured
interface DeathEvent extends TelemetryData {
userID: string
}
interface ServerShutdown extends TelemetryData {
matchTime: number //a different number of seconds than matchLength, i think this is greater in all cases
reason: string // only seen "EMPTY_SERVER" | "MATCH_COMPLETED" so far
}
this one appears to be missing entries, there's on average ~60 of these per match which is way fewer than the actions I expect to happen, also the damage/healing totals don't add up to the ones in the other sources I can't really figure out what the selection criteria for these is, at some point I may screencap a private match where we test some things out, and then try and correlate the data
interface UserRoundSpell extends TelemetryData {
scoreType: string //"USES", "DAMAGE_RECEIVED", "CONTROL_DONE", "CONTROL_RECEIVED", "DAMAGE_DONE", "ENERGY_RECEIVED", "HEALING_DONE", "HEALING_RECEIVED", "ENERGY_USED"
scoreTypeId: number //presumably the id of the spell
value: number
round: number //zero indexed
character: number
sourceTypeId: number
}
this has how much MMR you won or lost
interface TeamUpdateEvent extends TelemetryData {
}
this is the matchmaker data, some of it overkaps with reserved user
interface TeamUpdateEvent extends TelemetryData {
}
- Rate Limiting
- Proper code documentation (JSDoc?)
- Rewrite the whole thing in typescript/purescript
- Tests?
MIT