├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── api │ ├── base.ts │ ├── index.ts │ ├── matches.ts │ ├── players.ts │ ├── samples.ts │ ├── seasons.ts │ ├── status.ts │ └── telemetry.ts ├── entities │ ├── asset.ts │ ├── gameModeStats.ts │ ├── index.ts │ ├── match.spec.ts │ ├── match.ts │ ├── participant.ts │ ├── player.spec.ts │ ├── player.ts │ ├── playerSeason.spec.ts │ ├── playerSeason.ts │ ├── roster.ts │ ├── sample.spec.ts │ ├── sample.ts │ ├── season.spec.ts │ ├── season.ts │ ├── status.spec.ts │ ├── status.ts │ └── telemetry │ │ ├── events │ │ ├── armorDestroy.ts │ │ ├── carePackageLand.ts │ │ ├── carePackageSpawn.ts │ │ ├── gameStatePeriodic.ts │ │ ├── index.ts │ │ ├── itemAttach.ts │ │ ├── itemDetach.ts │ │ ├── itemDrop.ts │ │ ├── itemEquip.ts │ │ ├── itemPickup.ts │ │ ├── itemUnequip.ts │ │ ├── itemUse.ts │ │ ├── matchDefinition.ts │ │ ├── matchEnd.ts │ │ ├── matchStart.ts │ │ ├── playerAttack.ts │ │ ├── playerCreate.ts │ │ ├── playerKill.ts │ │ ├── playerLogin.ts │ │ ├── playerLogout.ts │ │ ├── playerMakeGroggy.ts │ │ ├── playerPosition.ts │ │ ├── playerRevive.ts │ │ ├── playerTakeDamage.ts │ │ ├── swimEnd.ts │ │ ├── swimStart.ts │ │ ├── telemetryEvent.ts │ │ ├── vehicleDestroy.ts │ │ ├── vehicleLeave.ts │ │ ├── vehicleRide.ts │ │ └── wheelDestroy.ts │ │ ├── objects │ │ ├── character.ts │ │ ├── gameState.ts │ │ ├── index.ts │ │ ├── item.ts │ │ ├── itemPackage.ts │ │ ├── location.ts │ │ └── vehicle.ts │ │ ├── telemetry.spec.ts │ │ └── telemetry.ts ├── index.ts ├── interfaces │ ├── common.ts │ ├── index.ts │ ├── match.ts │ ├── player.ts │ ├── sample.ts │ ├── season.ts │ ├── status.ts │ └── telemetry.ts └── shared │ ├── constants.ts │ └── index.ts ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .vscode 4 | .idea 5 | .nyc_output 6 | coverage 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Martin Sileno 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # PUBG TypeScript API 3 | 4 | [![Join the chat at https://gitter.im/pubg-typescript-api/Lobby](https://badges.gitter.im/pubg-typescript-api/Lobby.svg)](https://gitter.im/pubg-typescript-api/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | [![npm version](https://badge.fury.io/js/pubg-typescript-api.svg)](https://www.npmjs.com/package/pubg-typescript-api) 6 | 7 | 8 | ## Table of contents 9 | * [About](#about) 10 | * [Changelog](#changelog) 11 | * [Getting started](#getting-started) 12 | * [Usage example: player last match](#usage-example-player-last-match) 13 | * [Usage example: player aggregate stats](#usage-example-player-aggregate-stats) 14 | * [Usage example: telemetry](#usage-example-telemetry) 15 | * [Download telemetry data](#download-telemetry-data) 16 | * [List of kills in a match](#list-of-kills-in-a-match) 17 | * [Care package landings](#care-package-landings) 18 | * [Player positions in a match](#player-positions-in-a-match) 19 | * [License](#license) 20 | 21 | 22 | ## About 23 | Unofficial TypeScript wrapper on the official PUBG API. 24 | 25 | **Main features**: 26 | 27 | - Simple to use 28 | - Maps API resources to *easier-to-use* "Models" (i.e. `Player`, `Match`, `Participant`, etc.) 29 | - Telemetry parsing 30 | - OOP design 31 | - Fully typed 32 | - ~~Helps you win chicken dinners~~ 33 | 34 | ## Changelog 35 | 36 | See [releases](https://github.com/martinsileno/pubg-typescript-api/releases) tab on github. 37 | 38 | ## Getting started 39 | 40 | First, obtain an API key from [PUBG Official API](https://developer.playbattlegrounds.com/). 41 | 42 | Then install the package with NPM: 43 | ``` 44 | npm install --save pubg-typescript-api 45 | ``` 46 | 47 | ## Usage example: player last match 48 | 49 | As an example, let's make a command line utility to display some quick **stats on a player's last match**. 50 | 51 | Import the module and define `API_KEY` with your own API key obtained from the official website. 52 | Obviously the required classes depend on what you're doing, but in this case we need these 53 | 54 | ```typescript 55 | import { Match, PlatformRegion, Player, PubgAPI } from 'pubg-typescript-api'; 56 | 57 | const API_KEY = 'YOUR_API_KEY_HERE'; 58 | ``` 59 | 60 | First, instantiate the `PubgAPI` object, responsible for making requests to the API authenticated with your API key 61 | 62 | ```typescript 63 | const api = new PubgAPI(API_KEY, PlatformRegion.PC_EU); 64 | ``` 65 | 66 | here we used the Platform and Region `PC_EU`, but you're obviously free to change it to whatever you need. The possible values can be found in the `PlatformRegion` enum. 67 | 68 | This object must be given to all methods that retrieve data from the API. For example, let's find the player corresponding to the username "martinsileno" 69 | 70 | ```typescript 71 | const players = await Player.filterByName(api, ['martinsileno']); 72 | const player = players[0]; 73 | console.log(`Found player "${player.name}" with ID: ${player.id}`); 74 | ``` 75 | 76 | here we're *awaiting* on the Promise returned by `filterByName`, a function that returns a (promise of a) list of Players with the given names. 77 | 78 | Now that we have our player's data, let's find stats on his/her last played match 79 | 80 | ```typescript 81 | const lastMatchId = player.matchIds[0]; 82 | const match = await Match.get(api, lastMatchId); 83 | console.log(`Last played match on ${match.dateCreated} and lasted ${Math.round(match.duration / 60)} minutes, with ID: ${match.id}`); 84 | ``` 85 | 86 | here we extract the latest match ID from `player.matchIds` (it's sorted from newest to oldest) and then using it as argument for `Match.get`, a function that returns a promise of a `Match` object. So by *awaiting* on that, we get our match data. 87 | 88 | The last step before running our simple example is to get the player's stats in this Match. 89 | 90 | ```typescript 91 | const participant = match.getParticipantByName('martinsileno'); 92 | if (!participant) { 93 | console.error('Player not found in participants'); 94 | return; 95 | } 96 | console.log(`${participant.name} placed #${participant.winPlace} out of ${match.participants.length} on ${match.map}`); 97 | console.log('his stats: '); 98 | console.log(`kills ${participant.kills}`); 99 | console.log(`damage ${participant.damageDealt}`); 100 | console.log(`assists ${participant.assists}`); 101 | console.log(`headshot kills ${participant.headshotKills}`); 102 | console.log(`total distance ${participant.totalDistance}m`); 103 | ``` 104 | 105 | to get a player's stats in a `Match` we use the method `getParticipantByName`, which returns the corresponding `Participant` object. 106 | 107 | The `Participant` instances contain details on players in a `Match`, see the public getters in the class to find more. 108 | 109 | And we're done, we can run our example to see if it works, the output should look like 110 | 111 | ``` 112 | $ node dist/main.js 113 | Found player "martinsileno" with ID: account.a540a32a49784025939a975b45e86bfe 114 | Last played match on Sun Apr 22 2018 00:33:20 GMT+0200 (W. Europe Daylight Time) and lasted 32 minutes, with ID: a6d8d8f7-a3c4-4b1c-9947-8df40c144283 115 | martinsileno placed #1 out of 92 on Desert_Main 116 | his stats: 117 | kills 2 118 | damage 376.501 119 | assists 3 120 | headshot kills 1 121 | total distance 3915.62m 122 | ``` 123 | 124 | ## Usage example: player aggregate stats 125 | 126 | Since May 1st and [version 1.3](https://github.com/martinsileno/pubg-typescript-api/releases/tag/v1.3.0) of this wrapper we finally have aggregate data on a player for each season. 127 | 128 | Getting this data is very easy, 129 | 130 | ```typescript 131 | const api = new PubgAPI(API_KEY, PlatformRegion.PC_NA); 132 | const result = await Player.filterByName(api, ['shroud']); 133 | const shroud = result[0]; 134 | const seasonData = await PlayerSeason.get(api, shroud.id, 'division.bro.official.2018-04'); 135 | const soloStats = seasonData.squadFPPStats; 136 | console.log(`Player [${shroud.name}] stats for season [${seasonData.seasonId}]:`); 137 | console.log(`Kills ${soloStats.kills} / Assists ${soloStats.assists} / Knock-outs ${soloStats.dBNOs}`); 138 | console.log(`Played ${soloStats.roundsPlayed} matches`); 139 | console.log(`Won ${soloStats.wins} (${(100 * soloStats.wins / soloStats.roundsPlayed).toFixed(2)}%)`); 140 | console.log(`top10s ${soloStats.top10s} (${(100 * soloStats.top10s / soloStats.roundsPlayed).toFixed(2)}%)`); 141 | ``` 142 | 143 | This results in 144 | 145 | ``` 146 | Player [shroud] stats for season [division.bro.official.2018-04]: 147 | Kills 268 / Assists 50 / Knock-outs 200 148 | Played 50 matches 149 | Won 13 (26.00%) 150 | top10s 20 (40.00%) 151 | ``` 152 | 153 | You can get the season names using the `Season.list` method, 154 | 155 | ```typescript 156 | const seasonsList = await Season.list(api); 157 | seasonsList.forEach(s => console.log(s.id)); 158 | ``` 159 | 160 | *(I suggest you cache the result as it's not likely to change often)* 161 | 162 | ## Usage example: telemetry 163 | 164 | This package includes an easy-to-use and complete telemetry parsing utility. 165 | 166 | As an usage example we will get a list of player kills, care package landings and a list of player positions for a player. 167 | 168 | You can do **much** more with telemetry data, please read the documentation in the wiki for more details. 169 | 170 | ### Download telemetry data 171 | 172 | The first thing to do when working with telemetry is to download the corresponding object 173 | 174 | ```typescript 175 | const api = new PubgAPI(API_KEY, PlatformRegion.PC_EU); 176 | const telemetry = await match.getTelemetry(api); 177 | ``` 178 | 179 | ### List of kills in a match 180 | 181 | ```typescript 182 | telemetry.playerKillEvents.forEach(e => { 183 | console.log(`[${e.dateTime.toLocaleDateString()} ${e.dateTime.toLocaleTimeString()} kill] ${e.killer.name} -> ${e.victim.name} | ${e.damageCauserName} ${e.damageTypeCategory} @ ${e.distance / 100}m`); 184 | }); 185 | ``` 186 | 187 | example output: 188 | 189 | ``` 190 | ... 191 | [2018-4-28 19:16:28 kill] Ludosh -> martinsileno | PlayerMale_A_C Damage_Groggy @ 63.1690576171875m 192 | [2018-4-28 19:16:28 kill] siperdekizurafa -> zaku6652 | PlayerMale_A_C Damage_Groggy @ 36.4665966796875m 193 | [2018-4-28 19:16:28 kill] Ludosh -> Novanta | WeapHK416_C Damage_Gun @ 54.971845703125m 194 | [2018-4-28 19:17:54 kill] Razzmatazzzzz -> WilliamTanz | WeapSCAR-L_C Damage_Gun @ 143.47111328125m 195 | [2018-4-28 19:17:55 kill] Haspex -> LMNTRIXs | WeapAK47_C Damage_Gun @ 126.266767578125m 196 | ... 197 | ``` 198 | 199 | *"damage groggy" means bleed out damage* 200 | 201 | ### Care package landings 202 | 203 | ```typescript 204 | telemetry.carePackageLandEvents.forEach(e => { 205 | const itemsString = e.itemPackage.items.map(item => item.itemId).join(', '); 206 | console.log(`[${e.dateTime.toLocaleDateString()} ${e.dateTime.toLocaleTimeString()} carePackage land] with ${itemsString}`); 207 | }); 208 | ``` 209 | 210 | example output: 211 | 212 | ``` 213 | [2018-4-28 19:04:55 carePackage land] with Item_Weapon_M24_C, Item_Ammo_762mm_C, Item_Ammo_762mm_C, Item_Attach_Weapon_Upper_CQBSS_C, Item_Attach_Weapon_Upper_PM2_01_C, Item_Back_C_01_Lv3_C, Item_Heal_MedKit_C 214 | [2018-4-28 19:11:27 carePackage land] with Item_Weapon_M24_C, Item_Ammo_762mm_C, Item_Ammo_762mm_C, Item_Attach_Weapon_Upper_CQBSS_C, Item_Head_G_01_Lv3_C, Item_Heal_FirstAid_C 215 | [2018-4-28 19:15:11 carePackage land] with Item_Weapon_Groza_C, Item_Ammo_762mm_C, Item_Ammo_762mm_C, Item_Ammo_762mm_C, Item_Attach_Weapon_Upper_CQBSS_C, Item_Armor_C_01_Lv3_C, Item_Heal_MedKit_C 216 | [2018-4-28 19:24:19 carePackage land] with Item_Weapon_M249_C, Item_Ammo_556mm_C, Item_Ammo_556mm_C, Item_Head_G_01_Lv3_C, Item_Heal_MedKit_C, Item_Ghillie_02_C 217 | ``` 218 | 219 | ### Player positions in a match 220 | 221 | ```typescript 222 | const martinPositions = telemetry.playerPositionEvents.filter(e => e.character.name === 'martinsileno'); 223 | martinPositions.forEach(e => { 224 | const loc = e.character.location; 225 | console.log(`[${e.dateTime.toLocaleDateString()} ${e.dateTime.toLocaleTimeString()} position] (${loc.x}, ${loc.y}, ${loc.z})`); 226 | }); 227 | ``` 228 | 229 | example output: 230 | 231 | ``` 232 | ... 233 | [2018-4-28 19:12:44 position] (432451, 63057.02734375, 5437.40966796875) 234 | [2018-4-28 19:12:54 position] (429667.1875, 61954.94921875, 4977.5) 235 | [2018-4-28 19:13:04 position] (425153.90625, 65993.546875, 4900.1298828125) 236 | [2018-4-28 19:13:14 position] (422108.46875, 71026.3671875, 5496.9599609375) 237 | [2018-4-28 19:13:24 position] (419111.8125, 75035.40625, 5401.53759765625) 238 | ... 239 | ``` 240 | 241 | ## License 242 | 243 | MIT 244 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pubg-typescript-api", 3 | "version": "1.6.0", 4 | "description": "TypeScript wrapper on the official PUBG API", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "npm run clean && tsc && cp README.md ./dist/README.md && cp package.json ./dist/package.json", 9 | "clean": "rimraf dist", 10 | "lint": "tslint --project tsconfig.json", 11 | "test": "nyc mocha -r ts-node/register --require source-map-support/register --full-trace --bail src/**/*.spec.ts" 12 | }, 13 | "engines": { 14 | "node": ">=8" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/martinsileno/pubg-typescript-api.git" 19 | }, 20 | "keywords": [ 21 | "pubg" 22 | ], 23 | "author": "Martin Sileno", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/martinsileno/pubg-typescript-api/issues" 27 | }, 28 | "homepage": "https://github.com/martinsileno/pubg-typescript-api#readme", 29 | "devDependencies": { 30 | "@types/chai": "^4.1.6", 31 | "@types/mocha": "^5.2.5", 32 | "chai": "^4.2.0", 33 | "mocha": "^5.2.0", 34 | "nyc": "^13.0.1", 35 | "rimraf": "^2.6.2", 36 | "ts-mockito": "^2.3.1", 37 | "ts-node": "^7.0.1", 38 | "tslint": "^5.11.0", 39 | "tslint-no-unused-expression-chai": "^0.1.3", 40 | "typescript": "^3.1.1" 41 | }, 42 | "dependencies": { 43 | "axios": "^0.18.0" 44 | }, 45 | "nyc": { 46 | "include": [ 47 | "src/**/*.ts", 48 | "src/**/*.tsx" 49 | ], 50 | "extension": [ 51 | ".ts", 52 | ".tsx" 53 | ], 54 | "require": [ 55 | "ts-node/register" 56 | ], 57 | "reporter": [ 58 | "text-summary", 59 | "html" 60 | ], 61 | "sourceMap": true, 62 | "instrument": true 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/api/base.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance } from 'axios'; 2 | 3 | import { PlatformRegion } from '../shared/constants'; 4 | 5 | 6 | /** 7 | * Instances of this class will be used to make authenticated requests to the PUBG API. 8 | * 9 | * Instantiate this by providing your API key and the PlatformRegion. 10 | * 11 | * It accepts an optional `useGzip` option which, if set to true, requests that the server 12 | * compress its response using gzip. This can improve performance for large responses such as 13 | * matches. 14 | * The `useGzip` option must NOT be set to true if using a browser to send requests as it handles 15 | * the `Accept-Encoding` header by itself. 16 | */ 17 | export class PubgAPI { 18 | private _axios: AxiosInstance; 19 | private _apiKey: string; 20 | private _platformRegion: PlatformRegion; 21 | 22 | constructor(apiKey: string, platformRegion: PlatformRegion, useGzip = false) { 23 | this._apiKey = apiKey; 24 | this._platformRegion = platformRegion; 25 | const headers: {[p: string]: string} = { 26 | 'Authorization': `Bearer ${this._apiKey}`, 27 | 'Accept': 'application/json', 28 | }; 29 | if (useGzip) { 30 | headers['Accept-Encoding'] = 'gzip'; 31 | } 32 | this._axios = axios.create({ 33 | baseURL: `https://api.playbattlegrounds.com/shards/${this._platformRegion}/`, 34 | headers: headers, 35 | }); 36 | } 37 | 38 | /** 39 | * The AxiosInstance used to make authenticated API requests. 40 | */ 41 | get axios() { 42 | return this._axios; 43 | } 44 | 45 | /** 46 | * Platform and Region associated with this API instance. 47 | */ 48 | get platformRegion() { 49 | return this._platformRegion; 50 | } 51 | } 52 | 53 | 54 | export abstract class PubgAPIEndpoint { 55 | private _api: PubgAPI; 56 | constructor(api: PubgAPI) { 57 | this._api = api; 58 | } 59 | 60 | get api() { 61 | return this._api; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | export { PubgAPI } from './base'; 2 | export { MatchesPubgAPI } from './matches'; 3 | export { PlayersPubgAPI } from './players'; 4 | export { SamplesPubgAPI } from './samples'; 5 | export { SeasonsPubgAPI } from './seasons'; 6 | export { StatusPubgAPI } from './status'; 7 | export { TelemetryPubgAPI } from './telemetry'; 8 | -------------------------------------------------------------------------------- /src/api/matches.ts: -------------------------------------------------------------------------------- 1 | import { AxiosPromise } from 'axios'; 2 | 3 | import { IMatch } from '..'; 4 | 5 | import { PubgAPIEndpoint } from './base'; 6 | 7 | 8 | export class MatchesPubgAPI extends PubgAPIEndpoint { 9 | 10 | get(id: string): AxiosPromise { 11 | return this.api.axios.get(`/matches/${id}`); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/api/players.ts: -------------------------------------------------------------------------------- 1 | import { AxiosPromise } from 'axios'; 2 | 3 | import { IPlayer, IPlayerList, IPlayerSeason } from '..'; 4 | 5 | import { PubgAPIEndpoint } from './base'; 6 | 7 | 8 | export class PlayersPubgAPI extends PubgAPIEndpoint { 9 | 10 | get(id: string): AxiosPromise { 11 | return this.api.axios.get(`/players/${id}`); 12 | } 13 | 14 | getSeasonStats(playerId: string, seasonId: string): AxiosPromise { 15 | return this.api.axios.get(`/players/${playerId}/seasons/${seasonId}`); 16 | } 17 | 18 | listByID(playerIDs: string[]): AxiosPromise { 19 | return this.api.axios.get('/players', {params: {'filter[playerIds]': playerIDs.join(',')}}); 20 | } 21 | 22 | listByName(playerNames: string[]): AxiosPromise { 23 | return this.api.axios.get('/players', {params: {'filter[playerNames]': playerNames.join(',')}}); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/api/samples.ts: -------------------------------------------------------------------------------- 1 | import { AxiosPromise } from 'axios'; 2 | 3 | import { ISample } from '..'; 4 | 5 | import { PubgAPIEndpoint } from './base'; 6 | 7 | 8 | export class SamplesPubgAPI extends PubgAPIEndpoint { 9 | 10 | get(dateStart?: Date): AxiosPromise { 11 | if (dateStart) { 12 | return this.api.axios.get( 13 | '/samples', {params: {'filter[createdAt-start]': dateStart.toISOString()}}); 14 | } else { 15 | return this.api.axios.get('/samples'); 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/api/seasons.ts: -------------------------------------------------------------------------------- 1 | import { AxiosPromise } from 'axios'; 2 | 3 | import { ISeasonList } from '..'; 4 | 5 | import { PubgAPIEndpoint } from './base'; 6 | 7 | 8 | export class SeasonsPubgAPI extends PubgAPIEndpoint { 9 | list(): AxiosPromise { 10 | return this.api.axios.get(`/seasons`); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/api/status.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance, AxiosPromise } from 'axios'; 2 | 3 | import { IStatus } from '..'; 4 | 5 | export class StatusPubgAPI { 6 | private _axios: AxiosInstance; 7 | 8 | constructor() { 9 | this._axios = axios.create({ 10 | baseURL: `https://api.playbattlegrounds.com/`, 11 | }); 12 | } 13 | 14 | get(): AxiosPromise { 15 | return this._axios.get(`/status`); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/api/telemetry.ts: -------------------------------------------------------------------------------- 1 | import { AxiosPromise } from 'axios'; 2 | 3 | import { Asset, ITelemetry } from '..'; 4 | 5 | import { PubgAPIEndpoint } from './base'; 6 | 7 | 8 | export class TelemetryPubgAPI extends PubgAPIEndpoint { 9 | 10 | get(arg: Asset | string): AxiosPromise { 11 | let url: string; 12 | if (typeof arg === 'string') { 13 | url = arg; 14 | } else { 15 | url = arg.url; 16 | } 17 | 18 | return this.api.axios.get(url); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/entities/asset.ts: -------------------------------------------------------------------------------- 1 | import { IAsset } from '..'; 2 | 3 | export class Asset { 4 | private _id: string; 5 | private _url: string; 6 | private _dateCreated: Date; 7 | 8 | constructor(asset: IAsset) { 9 | this._id = asset.id; 10 | this._url = asset.attributes.URL; 11 | this._dateCreated = new Date(asset.attributes.createdAt); 12 | } 13 | 14 | /** 15 | * Asset ID 16 | */ 17 | get id() { 18 | return this._id; 19 | } 20 | 21 | /** 22 | * Link to the telemetry.json file 23 | */ 24 | get url() { 25 | return this._url; 26 | } 27 | 28 | /** 29 | * Time of telemetry creation 30 | */ 31 | get dateCreated() { 32 | return this._dateCreated; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/entities/gameModeStats.ts: -------------------------------------------------------------------------------- 1 | import { IGameModeStats } from '..'; 2 | 3 | 4 | /** 5 | * Statistics for a player in a game mode (solo, solo fpp etc.) in given season. 6 | */ 7 | export class GameModeStats { 8 | private _assists: number; 9 | private _bestRankPoint: number; 10 | private _boosts: number; 11 | private _dBNOs: number; 12 | private _dailyKills: number; 13 | private _dailyWins: number; 14 | private _damageDealt: number; 15 | private _days: number; 16 | private _headshotKills: number; 17 | private _heals: number; 18 | private _killPoints: number; // undocumented? 19 | private _kills: number; 20 | private _longestKill: number; 21 | private _longestTimeSurvived: number; 22 | private _losses: number; 23 | private _maxKillStreaks: number; 24 | private _mostSurvivalTime: number; 25 | private _rankPoints: number; 26 | private _revives: number; 27 | private _rideDistance: number; 28 | private _roadKills: number; 29 | private _roundMostKills: number; 30 | private _roundsPlayed: number; 31 | private _suicides: number; 32 | private _swimDistance: number; 33 | private _teamKills: number; 34 | private _timeSurvived: number; 35 | private _top10s: number; 36 | private _vehicleDestroys: number; 37 | private _walkDistance: number; 38 | private _weaponsAcquired: number; 39 | private _weeklyKills: number; 40 | private _weeklyWins: number; 41 | private _winPoints: number; 42 | // private _winRatio: number; 43 | private _wins: number; 44 | 45 | constructor(playerSeason: IGameModeStats) { 46 | this._assists = playerSeason.assists; 47 | this._bestRankPoint = playerSeason.bestRankPoint; 48 | this._boosts = playerSeason.boosts; 49 | this._dBNOs = playerSeason.dBNOs; 50 | this._dailyKills = playerSeason.dailyKills; 51 | this._dailyWins = playerSeason.dailyWins; 52 | this._damageDealt = playerSeason.damageDealt; 53 | this._days = playerSeason.days; 54 | this._headshotKills = playerSeason.headshotKills; 55 | this._heals = playerSeason.heals; 56 | this._killPoints = playerSeason.killPoints; 57 | this._kills = playerSeason.kills; 58 | this._longestKill = playerSeason.longestKill; 59 | this._longestTimeSurvived = playerSeason.longestTimeSurvived; 60 | this._losses = playerSeason.losses; 61 | this._maxKillStreaks = playerSeason.maxKillStreaks; 62 | this._mostSurvivalTime = playerSeason.mostSurvivalTime; 63 | this._rankPoints = playerSeason.rankPoints; 64 | this._revives = playerSeason.revives; 65 | this._rideDistance = playerSeason.rideDistance; 66 | this._roadKills = playerSeason.roadKills; 67 | this._roundMostKills = playerSeason.roundMostKills; 68 | this._roundsPlayed = playerSeason.roundsPlayed; 69 | this._suicides = playerSeason.suicides; 70 | this._swimDistance = playerSeason.swimDistance; 71 | this._teamKills = playerSeason.teamKills; 72 | this._timeSurvived = playerSeason.timeSurvived; 73 | this._top10s = playerSeason.top10s; 74 | this._vehicleDestroys = playerSeason.vehicleDestroys; 75 | this._walkDistance = playerSeason.walkDistance; 76 | this._weaponsAcquired = playerSeason.weaponsAcquired; 77 | this._weeklyKills = playerSeason.weeklyKills; 78 | this._weeklyWins = playerSeason.weeklyWins; 79 | this._winPoints = playerSeason.winPoints; 80 | this._wins = playerSeason.wins; 81 | } 82 | 83 | get assists(): number { 84 | return this._assists; 85 | } 86 | 87 | get bestRankPoint(): number { 88 | return this._bestRankPoint; 89 | } 90 | 91 | get boosts(): number { 92 | return this._boosts; 93 | } 94 | 95 | get dBNOs(): number { 96 | return this._dBNOs; 97 | } 98 | 99 | get dailyKills(): number { 100 | return this._dailyKills; 101 | } 102 | 103 | get dailyWins(): number { 104 | return this._dailyWins; 105 | } 106 | 107 | get damageDealt(): number { 108 | return this._damageDealt; 109 | } 110 | 111 | get days(): number { 112 | return this._days; 113 | } 114 | 115 | get headshotKills(): number { 116 | return this._headshotKills; 117 | } 118 | 119 | get heals(): number { 120 | return this._heals; 121 | } 122 | 123 | get killPoints(): number { 124 | return this._killPoints; 125 | } 126 | 127 | get kills(): number { 128 | return this._kills; 129 | } 130 | 131 | get longestKill(): number { 132 | return this._longestKill; 133 | } 134 | 135 | get longestTimeSurvived(): number { 136 | return this._longestTimeSurvived; 137 | } 138 | 139 | get losses(): number { 140 | return this._losses; 141 | } 142 | 143 | get maxKillStreaks(): number { 144 | return this._maxKillStreaks; 145 | } 146 | 147 | get mostSurvivalTime(): number { 148 | return this._mostSurvivalTime; 149 | } 150 | 151 | get rankPoints(): number { 152 | return this._rankPoints; 153 | } 154 | 155 | get revives(): number { 156 | return this._revives; 157 | } 158 | 159 | get rideDistance(): number { 160 | return this._rideDistance; 161 | } 162 | 163 | get roadKills(): number { 164 | return this._roadKills; 165 | } 166 | 167 | get roundMostKills(): number { 168 | return this._roundMostKills; 169 | } 170 | 171 | get roundsPlayed(): number { 172 | return this._roundsPlayed; 173 | } 174 | 175 | get suicides(): number { 176 | return this._suicides; 177 | } 178 | 179 | get swimDistance(): number { 180 | return this._swimDistance; 181 | } 182 | 183 | get teamKills(): number { 184 | return this._teamKills; 185 | } 186 | 187 | get timeSurvived(): number { 188 | return this._timeSurvived; 189 | } 190 | 191 | get top10s(): number { 192 | return this._top10s; 193 | } 194 | 195 | get vehicleDestroys(): number { 196 | return this._vehicleDestroys; 197 | } 198 | 199 | get walkDistance(): number { 200 | return this._walkDistance; 201 | } 202 | 203 | get weaponsAcquired(): number { 204 | return this._weaponsAcquired; 205 | } 206 | 207 | get weeklyKills(): number { 208 | return this._weeklyKills; 209 | } 210 | 211 | get weeklyWins(): number { 212 | return this._weeklyWins; 213 | } 214 | 215 | get winPoints(): number { 216 | return this._winPoints; 217 | } 218 | 219 | get wins(): number { 220 | return this._wins; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/entities/index.ts: -------------------------------------------------------------------------------- 1 | export { Asset } from './asset'; 2 | export { GameModeStats } from './gameModeStats'; 3 | export { Match } from './match'; 4 | export { Participant } from './participant'; 5 | export { Player } from './player'; 6 | export { PlayerSeason } from './playerSeason'; 7 | export { Roster } from './roster'; 8 | export { Sample } from './sample'; 9 | export { Season } from './season'; 10 | export { Status } from './status'; 11 | export { Telemetry } from './telemetry/telemetry'; 12 | export * from './telemetry/events'; 13 | export * from './telemetry/objects'; 14 | -------------------------------------------------------------------------------- /src/entities/match.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import 'mocha'; 3 | 4 | import { DeathType, GameMode, IMatch, MapName, PlatformRegion, SeasonState } from '..'; 5 | 6 | import { Asset } from './asset'; 7 | import { Match } from './match'; 8 | import { Participant } from './participant'; 9 | 10 | 11 | //#region SETUP STUFF 12 | /* tslint:disable */ 13 | const API_RESPONSE: IMatch = { 14 | "data": { 15 | "type": "match", 16 | "id": "a6d8d8f7-a3c4-4b1c-9947-8df40c144283", 17 | "attributes": { 18 | "createdAt": "2018-04-21T22:33:20Z", 19 | "duration": 1892, 20 | "gameMode": "duo-fpp", 21 | "isCustomMatch": false, 22 | "mapName": "Desert_Main", 23 | "seasonState": "progress", 24 | "shardId": "pc-eu", 25 | "stats": null, 26 | "tags": null, 27 | "titleId": "bluehole-pubg" 28 | }, 29 | "relationships": { 30 | "assets": { 31 | "data": [ 32 | { 33 | "type": "asset", 34 | "id": "a63b97bd-45b8-11e8-8433-0a58646e130b" 35 | } 36 | ] 37 | }, 38 | "rosters": { 39 | "data": [ 40 | { 41 | "type": "roster", 42 | "id": "38461e8d-379a-41ff-8fda-1efbf84847ed" 43 | }, 44 | { 45 | "type": "roster", 46 | "id": "2b551a10-2256-4c98-9f82-82e115dbffec" 47 | }, 48 | { 49 | "type": "roster", 50 | "id": "cd1be289-0bd8-4e9a-89a0-2217d1153c74" 51 | } 52 | ] 53 | } 54 | }, 55 | "links": { 56 | "schema": "", 57 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/matches/a6d8d8f7-a3c4-4b1c-9947-8df40c144283" 58 | } 59 | }, 60 | "included": [ 61 | { 62 | "type": "participant", 63 | "id": "3ff014d0-6e81-446f-93c2-1dda7333297f", 64 | "attributes": { 65 | "actor": "", 66 | "shardId": "pc-eu", 67 | "stats": { 68 | "DBNOs": 0, 69 | "assists": 0, 70 | "boosts": 2, 71 | "damageDealt": 0, 72 | "deathType": "byplayer", 73 | "headshotKills": 0, 74 | "heals": 6, 75 | "killPlace": 39, 76 | "killStreaks": 0, 77 | "kills": 0, 78 | "lastKillPoints": 0, 79 | "lastWinPoints": 0, 80 | "longestKill": 0, 81 | "mostDamage": 0, 82 | "name": "NixdaDieHard", 83 | "playerId": "account.0125807c8de4461198c0de300092ca34", 84 | "revives": 0, 85 | "rideDistance": 304.687073, 86 | "roadKills": 0, 87 | "swimDistance": 87.17336, 88 | "teamKills": 0, 89 | "timeSurvived": 1881, 90 | "vehicleDestroys": 0, 91 | "walkDistance": 4652.759, 92 | "weaponsAcquired": 0, 93 | "winPlace": 2 94 | } 95 | } 96 | }, 97 | { 98 | "type": "roster", 99 | "id": "38461e8d-379a-41ff-8fda-1efbf84847ed", 100 | "attributes": { 101 | "shardId": "pc-eu", 102 | "stats": { 103 | "rank": 2, 104 | "teamId": 30 105 | }, 106 | "won": "false" 107 | }, 108 | "relationships": { 109 | "participants": { 110 | "data": [ 111 | { 112 | "type": "participant", 113 | "id": "3ff014d0-6e81-446f-93c2-1dda7333297f" 114 | }, 115 | { 116 | "type": "participant", 117 | "id": "ab84ed56-da51-4f9e-b649-f8a7f37604e4" 118 | } 119 | ] 120 | }, 121 | "team": { 122 | "data": null 123 | } 124 | } 125 | }, 126 | { 127 | "type": "asset", 128 | "id": "a63b97bd-45b8-11e8-8433-0a58646e130b", 129 | "attributes": { 130 | "URL": "https://telemetry-cdn.playbattlegrounds.com/bluehole-pubg/pc-eu/2018/04/21/23/06/a63b97bd-45b8-11e8-8433-0a58646e130b-telemetry.json", 131 | "createdAt": "2018-04-21T23:06:40Z", 132 | "description": "", 133 | "name": "telemetry" 134 | } 135 | }, 136 | { 137 | "type": "participant", 138 | "id": "99f81c8b-edbd-452c-b8bb-666270b370d3", 139 | "attributes": { 140 | "actor": "", 141 | "shardId": "pc-eu", 142 | "stats": { 143 | "DBNOs": 0, 144 | "assists": 0, 145 | "boosts": 3, 146 | "damageDealt": 98.22, 147 | "deathType": "alive", 148 | "headshotKills": 0, 149 | "heals": 3, 150 | "killPlace": 15, 151 | "killPoints": 1039, 152 | "killPointsDelta": 36.707058, 153 | "killStreaks": 0, 154 | "kills": 2, 155 | "lastKillPoints": 0, 156 | "lastWinPoints": 0, 157 | "longestKill": 46, 158 | "mostDamage": 0, 159 | "name": "zaku6652", 160 | "playerId": "account.cda9cb29e8ce4146a9ad46d5a0da508b", 161 | "revives": 0, 162 | "rideDistance": 0, 163 | "roadKills": 0, 164 | "swimDistance": 0, 165 | "teamKills": 0, 166 | "timeSurvived": 1892, 167 | "vehicleDestroys": 0, 168 | "walkDistance": 3566.60132, 169 | "weaponsAcquired": 0, 170 | "winPlace": 1, 171 | "winPoints": 1121, 172 | "winPointsDelta": 140.555817 173 | } 174 | } 175 | }, 176 | { 177 | "type": "participant", 178 | "id": "ab84ed56-da51-4f9e-b649-f8a7f37604e4", 179 | "attributes": { 180 | "actor": "", 181 | "shardId": "pc-eu", 182 | "stats": { 183 | "DBNOs": 1, 184 | "assists": 0, 185 | "boosts": 3, 186 | "damageDealt": 99.99999, 187 | "deathType": "byplayer", 188 | "headshotKills": 0, 189 | "heals": 4, 190 | "killPlace": 38, 191 | "killPoints": 1232, 192 | "killPointsDelta": 6.263594, 193 | "killStreaks": 0, 194 | "kills": 0, 195 | "lastKillPoints": 0, 196 | "lastWinPoints": 0, 197 | "longestKill": 0, 198 | "mostDamage": 0, 199 | "name": "Hartensteiner", 200 | "playerId": "account.0ad732bf9c344743baae060ca139df03", 201 | "revives": 0, 202 | "rideDistance": 306.4264, 203 | "roadKills": 0, 204 | "swimDistance": 0, 205 | "teamKills": 0, 206 | "timeSurvived": 1892, 207 | "vehicleDestroys": 0, 208 | "walkDistance": 4455.29053, 209 | "weaponsAcquired": 0, 210 | "winPlace": 2, 211 | "winPoints": 1383, 212 | "winPointsDelta": 36.43944 213 | } 214 | } 215 | }, 216 | { 217 | "type": "participant", 218 | "id": "5f470019-5b98-4f8f-9603-eb312c4df5a1", 219 | "attributes": { 220 | "actor": "", 221 | "shardId": "pc-eu", 222 | "stats": { 223 | "DBNOs": 0, 224 | "assists": 0, 225 | "boosts": 3, 226 | "damageDealt": 69.22771, 227 | "deathType": "byplayer", 228 | "headshotKills": 0, 229 | "heals": 2, 230 | "killPlace": 24, 231 | "killPoints": 1314, 232 | "killPointsDelta": 13.5154753, 233 | "killStreaks": 0, 234 | "kills": 1, 235 | "lastKillPoints": 0, 236 | "lastWinPoints": 0, 237 | "longestKill": 20, 238 | "mostDamage": 0, 239 | "name": "saiitek", 240 | "playerId": "account.09293a024365480594d1b745884d8d5c", 241 | "revives": 1, 242 | "rideDistance": 0, 243 | "roadKills": 0, 244 | "swimDistance": 0, 245 | "teamKills": 0, 246 | "timeSurvived": 1831, 247 | "vehicleDestroys": 0, 248 | "walkDistance": 3744.01758, 249 | "weaponsAcquired": 0, 250 | "winPlace": 4, 251 | "winPoints": 1466, 252 | "winPointsDelta": 19.91042 253 | } 254 | } 255 | }, 256 | { 257 | "type": "roster", 258 | "id": "2b551a10-2256-4c98-9f82-82e115dbffec", 259 | "attributes": { 260 | "shardId": "pc-eu", 261 | "stats": { 262 | "rank": 1, 263 | "teamId": 12 264 | }, 265 | "won": "true" 266 | }, 267 | "relationships": { 268 | "participants": { 269 | "data": [ 270 | { 271 | "type": "participant", 272 | "id": "5f1d13e3-a837-498a-b354-ec25976a65f0" 273 | }, 274 | { 275 | "type": "participant", 276 | "id": "99f81c8b-edbd-452c-b8bb-666270b370d3" 277 | } 278 | ] 279 | }, 280 | "team": { 281 | "data": null 282 | } 283 | } 284 | }, 285 | { 286 | "type": "participant", 287 | "id": "2dab6c73-eb40-4658-ade5-0d177adeba66", 288 | "attributes": { 289 | "actor": "", 290 | "shardId": "pc-eu", 291 | "stats": { 292 | "DBNOs": 2, 293 | "assists": 0, 294 | "boosts": 1, 295 | "damageDealt": 213.859985, 296 | "deathType": "byplayer", 297 | "headshotKills": 0, 298 | "heals": 5, 299 | "killPlace": 8, 300 | "killPoints": 1102, 301 | "killPointsDelta": 45.4683075, 302 | "killStreaks": 0, 303 | "kills": 3, 304 | "lastKillPoints": 0, 305 | "lastWinPoints": 0, 306 | "longestKill": 289, 307 | "mostDamage": 0, 308 | "name": "Robination", 309 | "playerId": "account.92c94880c9a146c1b60691ff9492a2fd", 310 | "revives": 0, 311 | "rideDistance": 2138.24683, 312 | "roadKills": 0, 313 | "swimDistance": 0, 314 | "teamKills": 0, 315 | "timeSurvived": 1831, 316 | "vehicleDestroys": 0, 317 | "walkDistance": 3120.68, 318 | "weaponsAcquired": 0, 319 | "winPlace": 4, 320 | "winPoints": 1209, 321 | "winPointsDelta": 34.0894928 322 | } 323 | } 324 | }, 325 | { 326 | "type": "participant", 327 | "id": "5f1d13e3-a837-498a-b354-ec25976a65f0", 328 | "attributes": { 329 | "actor": "", 330 | "shardId": "pc-eu", 331 | "stats": { 332 | "DBNOs": 2, 333 | "assists": 3, 334 | "boosts": 4, 335 | "damageDealt": 376.501, 336 | "deathType": "alive", 337 | "headshotKills": 1, 338 | "heals": 1, 339 | "killPlace": 16, 340 | "killPoints": 1077, 341 | "killPointsDelta": 33.6085434, 342 | "killStreaks": 0, 343 | "kills": 2, 344 | "lastKillPoints": 0, 345 | "lastWinPoints": 0, 346 | "longestKill": 19, 347 | "mostDamage": 0, 348 | "name": "martinsileno", 349 | "playerId": "account.a540a32a49784025939a975b45e86bfe", 350 | "revives": 0, 351 | "rideDistance": 0, 352 | "roadKills": 0, 353 | "swimDistance": 0, 354 | "teamKills": 0, 355 | "timeSurvived": 1892, 356 | "vehicleDestroys": 0, 357 | "walkDistance": 3915.62, 358 | "weaponsAcquired": 0, 359 | "winPlace": 1, 360 | "winPoints": 1114, 361 | "winPointsDelta": 78.83802 362 | } 363 | } 364 | }, 365 | { 366 | "type": "roster", 367 | "id": "cd1be289-0bd8-4e9a-89a0-2217d1153c74", 368 | "attributes": { 369 | "shardId": "pc-eu", 370 | "stats": { 371 | "rank": 4, 372 | "teamId": 5 373 | }, 374 | "won": "false" 375 | }, 376 | "relationships": { 377 | "participants": { 378 | "data": [ 379 | { 380 | "type": "participant", 381 | "id": "2dab6c73-eb40-4658-ade5-0d177adeba66" 382 | }, 383 | { 384 | "type": "participant", 385 | "id": "5f470019-5b98-4f8f-9603-eb312c4df5a1" 386 | } 387 | ] 388 | }, 389 | "team": { 390 | "data": null 391 | } 392 | } 393 | } 394 | ], 395 | "links": { 396 | "self": "https://api.playbattlegrounds.com/shards/pc-na/matches/a6d8d8f7-a3c4-4b1c-9947-8df40c144283" 397 | }, 398 | "meta": {} 399 | } 400 | /* tslint:enable */ 401 | 402 | 403 | interface ExpectedParticipant { 404 | id: string; 405 | DBNOs: number; 406 | assists: number; 407 | boosts: number; 408 | damageDealt: number; 409 | deathType: DeathType; 410 | headshotKills: number; 411 | heals: number; 412 | killPlace: number; 413 | killPoints?: number; 414 | killPointsDelta?: number; 415 | killStreaks: number; 416 | kills: number; 417 | lastKillPoints: number; 418 | lastWinPoints: number; 419 | longestKill: number; 420 | mostDamage: number; 421 | name: string; 422 | playerId: string; 423 | revives: number; 424 | rideDistance: number; 425 | roadKills: number; 426 | swimDistance: number; 427 | teamKills: number; 428 | timeSurvived: number; 429 | vehicleDestroys: number; 430 | walkDistance: number; 431 | weaponsAcquired: number; 432 | winPlace: number; 433 | winPoints?: number; 434 | winPointsDelta?: number; 435 | } 436 | 437 | const participantNix: ExpectedParticipant = { 438 | id: '3ff014d0-6e81-446f-93c2-1dda7333297f', 439 | DBNOs: 0, 440 | assists: 0, 441 | boosts: 2, 442 | damageDealt: 0, 443 | deathType: DeathType.BY_PLAYER, 444 | headshotKills: 0, 445 | heals: 6, 446 | killPlace: 39, 447 | killStreaks: 0, 448 | kills: 0, 449 | lastKillPoints: 0, 450 | lastWinPoints: 0, 451 | longestKill: 0, 452 | mostDamage: 0, 453 | name: 'NixdaDieHard', 454 | playerId: 'account.0125807c8de4461198c0de300092ca34', 455 | revives: 0, 456 | rideDistance: 304.687073, 457 | roadKills: 0, 458 | teamKills: 0, 459 | swimDistance: 87.17336, 460 | timeSurvived: 1881, 461 | vehicleDestroys: 0, 462 | walkDistance: 4652.759, 463 | weaponsAcquired: 0, 464 | winPlace: 2 465 | }; 466 | 467 | const participantZakuro: ExpectedParticipant = { 468 | id: '99f81c8b-edbd-452c-b8bb-666270b370d3', 469 | DBNOs: 0, 470 | assists: 0, 471 | boosts: 3, 472 | damageDealt: 98.22, 473 | deathType: DeathType.ALIVE, 474 | headshotKills: 0, 475 | heals: 3, 476 | killPlace: 15, 477 | killPoints: 1039, 478 | killPointsDelta: 36.707058, 479 | killStreaks: 0, 480 | kills: 2, 481 | lastKillPoints: 0, 482 | lastWinPoints: 0, 483 | longestKill: 46, 484 | mostDamage: 0, 485 | name: 'zaku6652', 486 | playerId: 'account.cda9cb29e8ce4146a9ad46d5a0da508b', 487 | revives: 0, 488 | rideDistance: 0, 489 | roadKills: 0, 490 | swimDistance: 0, 491 | teamKills: 0, 492 | timeSurvived: 1892, 493 | vehicleDestroys: 0, 494 | walkDistance: 3566.60132, 495 | weaponsAcquired: 0, 496 | winPlace: 1, 497 | winPoints: 1121, 498 | winPointsDelta: 140.555817, 499 | }; 500 | 501 | const participantHart: ExpectedParticipant = { 502 | id: 'ab84ed56-da51-4f9e-b649-f8a7f37604e4', 503 | DBNOs: 1, 504 | assists: 0, 505 | boosts: 3, 506 | damageDealt: 99.99999, 507 | deathType: DeathType.BY_PLAYER, 508 | headshotKills: 0, 509 | heals: 4, 510 | killPlace: 38, 511 | killPoints: 1232, 512 | killPointsDelta: 6.263594, 513 | killStreaks: 0, 514 | kills: 0, 515 | lastKillPoints: 0, 516 | lastWinPoints: 0, 517 | longestKill: 0, 518 | mostDamage: 0, 519 | name: 'Hartensteiner', 520 | playerId: 'account.0ad732bf9c344743baae060ca139df03', 521 | revives: 0, 522 | rideDistance: 306.4264, 523 | roadKills: 0, 524 | swimDistance: 0, 525 | teamKills: 0, 526 | timeSurvived: 1892, 527 | vehicleDestroys: 0, 528 | walkDistance: 4455.29053, 529 | weaponsAcquired: 0, 530 | winPlace: 2, 531 | winPoints: 1383, 532 | winPointsDelta: 36.43944, 533 | }; 534 | 535 | const participantSaiitek: ExpectedParticipant = { 536 | id: '5f470019-5b98-4f8f-9603-eb312c4df5a1', 537 | DBNOs: 0, 538 | assists: 0, 539 | boosts: 3, 540 | damageDealt: 69.22771, 541 | deathType: DeathType.BY_PLAYER, 542 | headshotKills: 0, 543 | heals: 2, 544 | killPlace: 24, 545 | killPoints: 1314, 546 | killPointsDelta: 13.5154753, 547 | killStreaks: 0, 548 | kills: 1, 549 | lastKillPoints: 0, 550 | lastWinPoints: 0, 551 | longestKill: 20, 552 | mostDamage: 0, 553 | name: 'saiitek', 554 | playerId: 'account.09293a024365480594d1b745884d8d5c', 555 | revives: 1, 556 | rideDistance: 0, 557 | roadKills: 0, 558 | swimDistance: 0, 559 | teamKills: 0, 560 | timeSurvived: 1831, 561 | vehicleDestroys: 0, 562 | walkDistance: 3744.01758, 563 | weaponsAcquired: 0, 564 | winPlace: 4, 565 | winPoints: 1466, 566 | winPointsDelta: 19.91042, 567 | }; 568 | 569 | const participantRobi: ExpectedParticipant = { 570 | id: '2dab6c73-eb40-4658-ade5-0d177adeba66', 571 | DBNOs: 2, 572 | assists: 0, 573 | boosts: 1, 574 | damageDealt: 213.859985, 575 | deathType: DeathType.BY_PLAYER, 576 | headshotKills: 0, 577 | heals: 5, 578 | killPlace: 8, 579 | killPoints: 1102, 580 | killPointsDelta: 45.4683075, 581 | killStreaks: 0, 582 | kills: 3, 583 | lastKillPoints: 0, 584 | lastWinPoints: 0, 585 | longestKill: 289, 586 | mostDamage: 0, 587 | name: 'Robination', 588 | playerId: 'account.92c94880c9a146c1b60691ff9492a2fd', 589 | revives: 0, 590 | rideDistance: 2138.24683, 591 | roadKills: 0, 592 | swimDistance: 0, 593 | teamKills: 0, 594 | timeSurvived: 1831, 595 | vehicleDestroys: 0, 596 | walkDistance: 3120.68, 597 | weaponsAcquired: 0, 598 | winPlace: 4, 599 | winPoints: 1209, 600 | winPointsDelta: 34.0894928, 601 | }; 602 | 603 | const participantMartin: ExpectedParticipant = { 604 | id: '5f1d13e3-a837-498a-b354-ec25976a65f0', 605 | DBNOs: 2, 606 | assists: 3, 607 | boosts: 4, 608 | damageDealt: 376.501, 609 | deathType: DeathType.ALIVE, 610 | headshotKills: 1, 611 | heals: 1, 612 | killPlace: 16, 613 | killPoints: 1077, 614 | killPointsDelta: 33.6085434, 615 | killStreaks: 0, 616 | kills: 2, 617 | lastKillPoints: 0, 618 | lastWinPoints: 0, 619 | longestKill: 19, 620 | mostDamage: 0, 621 | name: 'martinsileno', 622 | playerId: 'account.a540a32a49784025939a975b45e86bfe', 623 | revives: 0, 624 | rideDistance: 0, 625 | roadKills: 0, 626 | swimDistance: 0, 627 | teamKills: 0, 628 | timeSurvived: 1892, 629 | vehicleDestroys: 0, 630 | walkDistance: 3915.62, 631 | weaponsAcquired: 0, 632 | winPlace: 1, 633 | winPoints: 1114, 634 | winPointsDelta: 78.83802, 635 | }; 636 | //#endregion 637 | 638 | 639 | describe('Match entity', () => { 640 | 641 | function compareParticipant(p: Participant | undefined, expected: ExpectedParticipant): void { 642 | if (!p) { 643 | expect.fail(); 644 | return; 645 | } 646 | expect(p.id).to.equal(expected.id); 647 | expect(p.DBNOs).to.equal(expected.DBNOs); 648 | expect(p.assists).to.equal(expected.assists); 649 | expect(p.boosts).to.equal(expected.boosts); 650 | expect(p.damageDealt).to.equal(expected.damageDealt); 651 | expect(p.deathType).to.equal(expected.deathType); 652 | expect(p.headshotKills).to.equal(expected.headshotKills); 653 | expect(p.heals).to.equal(expected.heals); 654 | expect(p.killPlace).to.equal(expected.killPlace); 655 | expect(p.killPoints).to.equal(expected.killPoints); 656 | expect(p.killPointsDelta).to.equal(expected.killPointsDelta); 657 | expect(p.killStreaks).to.equal(expected.killStreaks); 658 | expect(p.kills).to.equal(expected.kills); 659 | expect(p.lastKillPoints).to.equal(expected.lastKillPoints); 660 | expect(p.lastWinPoints).to.equal(expected.lastWinPoints); 661 | expect(p.longestKill).to.equal(expected.longestKill); 662 | expect(p.mostDamage).to.equal(expected.mostDamage); 663 | expect(p.name).to.equal(expected.name); 664 | expect(p.playerId).to.equal(expected.playerId); 665 | expect(p.revives).to.equal(expected.revives); 666 | expect(p.rideDistance).to.equal(expected.rideDistance); 667 | expect(p.roadKills).to.equal(expected.roadKills); 668 | expect(p.swimDistance).to.equal(expected.swimDistance); 669 | expect(p.teamKills).to.equal(expected.teamKills); 670 | expect(p.timeSurvived).to.equal(expected.timeSurvived); 671 | expect(p.vehicleDestroys).to.equal(expected.vehicleDestroys); 672 | expect(p.walkDistance).to.equal(expected.walkDistance); 673 | expect(p.weaponsAcquired).to.equal(expected.weaponsAcquired); 674 | expect(p.winPlace).to.equal(expected.winPlace); 675 | expect(p.winPoints).to.equal(expected.winPoints); 676 | expect(p.winPointsDelta).to.equal(expected.winPointsDelta); 677 | } 678 | 679 | it('should initialize Match from API response', () => { 680 | const match = Match.fromDetail(API_RESPONSE); 681 | expect(match.id).to.equal('a6d8d8f7-a3c4-4b1c-9947-8df40c144283'); 682 | expect(match.dateCreated).to.deep.equal(new Date('2018-04-21T22:33:20Z')); 683 | expect(match.duration).to.equal(1892); 684 | expect(match.gameMode).to.equal(GameMode.DUO_FPP); 685 | expect(match.isCustomMatch).to.be.false; 686 | expect(match.map).to.equal(MapName.DESERT_MAIN); 687 | expect(match.patchVersion).to.be.an('undefined'); 688 | expect(match.seasonState).to.equal(SeasonState.PROGRESS); 689 | expect(match.shardId).to.equal(PlatformRegion.PC_EU); 690 | }); 691 | 692 | it('should initialize Participant list from API response', () => { 693 | const match = Match.fromDetail(API_RESPONSE); 694 | const participants = match.participants; 695 | expect(participants).to.have.length(6); 696 | const [nix, zakuro, hart, saiitek, robi, martin] = participants; 697 | compareParticipant(nix, participantNix); 698 | compareParticipant(zakuro, participantZakuro); 699 | compareParticipant(hart, participantHart); 700 | compareParticipant(saiitek, participantSaiitek); 701 | compareParticipant(robi, participantRobi); 702 | compareParticipant(martin, participantMartin); 703 | }); 704 | 705 | it('should initialize Roster list from API response', () => { 706 | const match = Match.fromDetail(API_RESPONSE); 707 | const rosters = match.rosters; 708 | expect(rosters).to.have.length(3); 709 | const [r1, r2, r3] = rosters; 710 | expect(r1.id).to.equal('38461e8d-379a-41ff-8fda-1efbf84847ed'); 711 | expect(r1.hasWon).to.be.false; 712 | expect(r1.rank).to.equal(2); 713 | expect(r1.teamId).to.equal(30); 714 | expect(r1.participants).to.have.length(2); 715 | const [nix, hart] = r1.participants; 716 | compareParticipant(nix, participantNix); 717 | compareParticipant(hart, participantHart); 718 | expect(r2.id).to.equal('2b551a10-2256-4c98-9f82-82e115dbffec'); 719 | expect(r2.hasWon).to.be.true; 720 | expect(r2.rank).to.equal(1); 721 | expect(r2.teamId).to.equal(12); 722 | const [martin, zakuro] = r2.participants; 723 | compareParticipant(martin, participantMartin); 724 | compareParticipant(zakuro, participantZakuro); 725 | expect(r3.id).to.equal('cd1be289-0bd8-4e9a-89a0-2217d1153c74'); 726 | expect(r3.hasWon).to.be.false; 727 | expect(r3.rank).to.equal(4); 728 | expect(r3.teamId).to.equal(5); 729 | const [robi, saiitek] = r3.participants; 730 | compareParticipant(robi, participantRobi); 731 | compareParticipant(saiitek, participantSaiitek); 732 | }); 733 | 734 | it('should initialize Asset from API response', () => { 735 | const match = Match.fromDetail(API_RESPONSE); 736 | expect(match.asset).to.not.be.undefined; 737 | const asset = match.asset as Asset; 738 | expect(asset.id).to.equal('a63b97bd-45b8-11e8-8433-0a58646e130b'); 739 | /* tslint:disable-next-line:max-line-length */ 740 | expect(asset.url).to.equal('https://telemetry-cdn.playbattlegrounds.com/bluehole-pubg/pc-eu/2018/04/21/23/06/a63b97bd-45b8-11e8-8433-0a58646e130b-telemetry.json'); 741 | expect(asset.dateCreated).to.deep.equal(new Date('2018-04-21T23:06:40Z')); 742 | }); 743 | 744 | it('should find player by ID', () => { 745 | const match = Match.fromDetail(API_RESPONSE); 746 | const participant = match.getParticipantById('99f81c8b-edbd-452c-b8bb-666270b370d3'); 747 | compareParticipant(participant, participantZakuro); 748 | }); 749 | 750 | it('should find player by name', () => { 751 | const match = Match.fromDetail(API_RESPONSE); 752 | const participant = match.getParticipantByName('martinsileno'); 753 | compareParticipant(participant, participantMartin); 754 | }); 755 | 756 | it('should return undefined if trying to find player by non-existing ID', () => { 757 | const match = Match.fromDetail(API_RESPONSE); 758 | const participant = match.getParticipantById('123456'); 759 | expect(participant).to.be.undefined; 760 | }); 761 | 762 | it('should return undefined if trying to find player by non-existing name', () => { 763 | const match = Match.fromDetail(API_RESPONSE); 764 | const participant = match.getParticipantByName('pippo'); 765 | expect(participant).to.be.undefined; 766 | }); 767 | 768 | it('should find match winner(s)', () => { 769 | const match = Match.fromDetail(API_RESPONSE); 770 | const winners = match.getWinners(); 771 | expect(winners).to.have.length(2); 772 | compareParticipant(winners[0], participantZakuro); 773 | compareParticipant(winners[1], participantMartin); 774 | }); 775 | 776 | }); 777 | -------------------------------------------------------------------------------- /src/entities/match.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Asset, 3 | GameMode, 4 | IAsset, 5 | IMatch, 6 | IParticipant, 7 | IRoster, 8 | MapName, 9 | MatchesPubgAPI, 10 | Participant, 11 | PlatformRegion, 12 | PubgAPI, 13 | Roster, 14 | SeasonState, 15 | Telemetry, 16 | TelemetryPubgAPI, 17 | } from '..'; 18 | 19 | 20 | /** 21 | * A PUBG Match. 22 | * 23 | * Contains information and statistics on a Match, such as date, duration, map, participants 24 | * and teams. 25 | */ 26 | export class Match { 27 | private _id: string; 28 | private _dateCreated: Date; 29 | private _duration: number; 30 | private _gameMode: GameMode; 31 | private _isCustomMatch: boolean; 32 | private _map: MapName; 33 | private _patchVersion: string | undefined; 34 | private _seasonState: SeasonState; 35 | private _shardId: PlatformRegion; 36 | 37 | private _participants: Participant[]; 38 | private _rosters: Roster[]; 39 | private _asset?: Asset; // should never be undefined as an error would be thrown in constructor 40 | 41 | private constructor(matchDetail: IMatch) { 42 | this._id = matchDetail.data.id; 43 | this._dateCreated = new Date(matchDetail.data.attributes.createdAt); 44 | this._duration = matchDetail.data.attributes.duration; 45 | this._gameMode = matchDetail.data.attributes.gameMode as GameMode; 46 | this._isCustomMatch = matchDetail.data.attributes.isCustomMatch; 47 | this._map = matchDetail.data.attributes.mapName as MapName; 48 | this._patchVersion = matchDetail.data.attributes.patchVersion; 49 | this._seasonState = matchDetail.data.attributes.seasonState as SeasonState; 50 | this._shardId = matchDetail.data.attributes.shardId as PlatformRegion; 51 | 52 | const participantsMap = new Map(); // maps participant id to Participant 53 | const rosterContentsMap = new Map(); // maps roster id to participant id list 54 | const participants: Participant[] = []; 55 | const rosters: Roster[] = []; 56 | matchDetail.included.forEach(obj => { 57 | switch (obj.type) { 58 | case 'asset': 59 | if (this._asset) { 60 | throw new Error('Multiple Asset objects found'); 61 | } 62 | this._asset = new Asset(obj as IAsset); 63 | break; 64 | case 'participant': 65 | const participant = new Participant(obj as IParticipant); 66 | participantsMap.set(participant.id, participant); 67 | participants.push(participant); 68 | break; 69 | case 'roster': 70 | const rosterInput = obj as IRoster; 71 | rosterContentsMap.set( 72 | rosterInput.id, rosterInput.relationships!.participants.data.map(pData => pData.id)); 73 | const roster = new Roster(rosterInput); 74 | rosters.push(roster); 75 | break; 76 | default: 77 | throw new Error(`Unexpected object type in match included: ${obj.type}`); 78 | } 79 | }); 80 | 81 | rosters.forEach(r => { 82 | const members = rosterContentsMap.get(r.id)!; 83 | members.forEach(m => { 84 | const p = participantsMap.get(m)!; 85 | r.participants.push(p); 86 | }); 87 | }); 88 | 89 | this._participants = participants; 90 | this._rosters = rosters; 91 | } 92 | 93 | static async get(api: PubgAPI, matchId: string) { 94 | const matchesAPI = new MatchesPubgAPI(api); 95 | const matchData = await matchesAPI.get(matchId); 96 | return Match.fromDetail(matchData.data); 97 | } 98 | 99 | static fromDetail(matchDetail: IMatch): Match { 100 | return new Match(matchDetail); 101 | } 102 | 103 | //#region getters 104 | /** 105 | * Match ID 106 | */ 107 | get id() { 108 | return this._id; 109 | } 110 | 111 | /** 112 | * Time this match object was stored in the API 113 | */ 114 | get dateCreated() { 115 | return this._dateCreated; 116 | } 117 | 118 | /** 119 | * Length of the match 120 | */ 121 | get duration() { 122 | return this._duration; 123 | } 124 | 125 | /** 126 | * Game mode played 127 | */ 128 | get gameMode() { 129 | return this._gameMode; 130 | } 131 | 132 | get isCustomMatch() { 133 | return this._isCustomMatch; 134 | } 135 | 136 | get map() { 137 | return this._map; 138 | } 139 | 140 | get patchVersion() { 141 | return this._patchVersion; 142 | } 143 | 144 | get seasonState() { 145 | return this._seasonState; 146 | } 147 | 148 | get shardId() { 149 | return this._shardId; 150 | } 151 | 152 | /** 153 | * The Asset object linked to this Match. Contains the URL for telemetry data. 154 | */ 155 | get asset(): Asset { 156 | return this._asset!; 157 | } 158 | 159 | /** 160 | * A list of `Participant` objects, one for each player that took part in the Match. 161 | */ 162 | get participants() { 163 | return this._participants; 164 | } 165 | 166 | /** 167 | * A list of `Roster` objects, one for each team that played the Match. 168 | */ 169 | get rosters() { 170 | return this._rosters; 171 | } 172 | //#endregion 173 | 174 | /** 175 | * Return the Participant object with the given ID or undefined if not found. 176 | * @param id ID of the player to search 177 | */ 178 | getParticipantById(id: string) { 179 | return this._participants.find(p => p.id === id); 180 | } 181 | 182 | /** 183 | * Return the Participant object with the given name or undefined if not found. 184 | * @param name name of the player to search 185 | */ 186 | getParticipantByName(name: string) { 187 | return this._participants.find(p => p.name === name); 188 | } 189 | 190 | /** 191 | * Return a list of the Participants that won this match. 192 | */ 193 | getWinners() { 194 | return this._participants.filter(p => p.winPlace === 1); 195 | } 196 | 197 | async getTelemetry(api: PubgAPI) { 198 | const telemetryAPI = new TelemetryPubgAPI(api); 199 | const response = await telemetryAPI.get(this._asset!); 200 | const telemetry = new Telemetry(response.data); 201 | return telemetry; 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /src/entities/participant.ts: -------------------------------------------------------------------------------- 1 | import { DeathType, IParticipant } from '..'; 2 | 3 | export class Participant { 4 | private _id: string; 5 | private _DBNOs: number; 6 | private _assists: number; 7 | private _boosts: number; 8 | private _damageDealt: number; 9 | private _deathType: DeathType; 10 | private _headshotKills: number; 11 | private _heals: number; 12 | private _killPlace: number; 13 | private _killPoints?: number; 14 | private _killPointsDelta?: number; 15 | private _killStreaks: number; 16 | private _kills: number; 17 | private _lastKillPoints: number; 18 | private _lastWinPoints: number; 19 | private _longestKill: number; 20 | private _mostDamage: number; 21 | private _name: string; 22 | private _playerId: string; 23 | private _revives: number; 24 | private _rideDistance: number; 25 | private _roadKills: number; 26 | private _swimDistance: number; 27 | private _teamKills: number; 28 | private _timeSurvived: number; 29 | private _vehicleDestroys: number; 30 | private _walkDistance: number; 31 | private _weaponsAcquired: number; 32 | private _winPlace: number; 33 | private _winPoints?: number; 34 | private _winPointsDelta?: number; 35 | 36 | constructor(participant: IParticipant) { 37 | this._id = participant.id; 38 | const stats = participant.attributes.stats; 39 | this._DBNOs = stats.DBNOs; 40 | this._assists = stats.assists; 41 | this._boosts = stats.boosts; 42 | this._damageDealt = stats.damageDealt; 43 | this._deathType = stats.deathType as DeathType; 44 | this._headshotKills = stats.headshotKills; 45 | this._heals = stats.heals; 46 | this._killPlace = stats.killPlace; 47 | this._killPoints = stats.killPoints; 48 | this._killPointsDelta = stats.killPointsDelta; 49 | this._killStreaks = stats.killStreaks; 50 | this._kills = stats.kills; 51 | this._lastKillPoints = stats.lastKillPoints; 52 | this._lastWinPoints = stats.lastWinPoints; 53 | this._longestKill = stats.longestKill; 54 | this._mostDamage = stats.mostDamage; 55 | this._name = stats.name; 56 | this._playerId = stats.playerId; 57 | this._revives = stats.revives; 58 | this._rideDistance = stats.rideDistance; 59 | this._roadKills = stats.roadKills; 60 | this._swimDistance = stats.swimDistance; 61 | this._teamKills = stats.teamKills; 62 | this._timeSurvived = stats.timeSurvived; 63 | this._vehicleDestroys = stats.vehicleDestroys; 64 | this._walkDistance = stats.walkDistance; 65 | this._weaponsAcquired = stats.weaponsAcquired; 66 | this._winPlace = stats.winPlace; 67 | this._winPoints = stats.winPoints; 68 | this._winPointsDelta = stats.winPointsDelta; 69 | } 70 | 71 | //#region GETTERS 72 | get id() { 73 | return this._id; 74 | } 75 | 76 | /** 77 | * Number of times this participant was downed 78 | */ 79 | get DBNOs() { 80 | return this._DBNOs; 81 | } 82 | 83 | get assists() { 84 | return this._assists; 85 | } 86 | 87 | /** 88 | * Total number of boost items used 89 | */ 90 | get boosts() { 91 | return this._boosts; 92 | } 93 | 94 | get damageDealt() { 95 | return this._damageDealt; 96 | } 97 | 98 | get deathType() { 99 | return this._deathType; 100 | } 101 | 102 | get headshotKills() { 103 | return this._headshotKills; 104 | } 105 | 106 | /** 107 | * Number of healing items used 108 | */ 109 | get heals() { 110 | return this._heals; 111 | } 112 | 113 | get killPlace() { 114 | return this._killPlace; 115 | } 116 | 117 | get killPoints() { 118 | return this._killPoints; 119 | } 120 | 121 | /** 122 | * Change in kill points 123 | */ 124 | get killPointsDelta() { 125 | return this._killPointsDelta; 126 | } 127 | 128 | /** 129 | * Total number of kill streaks 130 | */ 131 | get killStreaks() { 132 | return this._killStreaks; 133 | } 134 | 135 | get kills() { 136 | return this._kills; 137 | } 138 | 139 | get lastKillPoints() { 140 | return this._lastKillPoints; 141 | } 142 | 143 | get lastWinPoints() { 144 | return this._lastWinPoints; 145 | } 146 | 147 | get longestKill() { 148 | return this._longestKill; 149 | } 150 | 151 | /** 152 | * Highest amount of damage dealt with a single attack 153 | */ 154 | get mostDamage() { 155 | return this._mostDamage; 156 | } 157 | 158 | /** 159 | * Username of the player associated with this participant 160 | */ 161 | get name() { 162 | return this._name; 163 | } 164 | 165 | /** 166 | * Account ID of the player associated with this participant 167 | */ 168 | get playerId() { 169 | return this._playerId; 170 | } 171 | 172 | /** 173 | * Number of times this participant revived others 174 | */ 175 | get revives() { 176 | return this._revives; 177 | } 178 | 179 | /** 180 | * Total distance traveled in vehicles 181 | */ 182 | get rideDistance() { 183 | return this._rideDistance; 184 | } 185 | 186 | /** 187 | * Number of kills while in a vehicle 188 | */ 189 | get roadKills() { 190 | return this._roadKills; 191 | } 192 | 193 | /** 194 | * Total distance traveled while swimming measured in meters 195 | */ 196 | get swimDistance() { 197 | return this._swimDistance; 198 | } 199 | 200 | get teamKills() { 201 | return this._teamKills; 202 | } 203 | 204 | get timeSurvived() { 205 | return this._timeSurvived; 206 | } 207 | 208 | get vehicleDestroys() { 209 | return this._vehicleDestroys; 210 | } 211 | 212 | get walkDistance() { 213 | return this._walkDistance; 214 | } 215 | 216 | get weaponsAcquired() { 217 | return this._weaponsAcquired; 218 | } 219 | 220 | get winPlace() { 221 | return this._winPlace; 222 | } 223 | 224 | get winPoints() { 225 | return this._winPoints; 226 | } 227 | 228 | get winPointsDelta() { 229 | return this._winPointsDelta; 230 | } 231 | //#endregion 232 | 233 | // composite getters 234 | get totalDistance() { 235 | return this._rideDistance + this._walkDistance; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/entities/player.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import 'mocha'; 3 | 4 | import { IPlayer } from '../interfaces/player'; 5 | 6 | import { Player } from './player'; 7 | 8 | 9 | /* tslint:disable */ 10 | const API_DETAIL_RESPONSE: IPlayer = { 11 | "data": { 12 | "type": "player", 13 | "id": "account.a540a32a49784025939a975b45e86bfe", 14 | "attributes": { 15 | "createdAt": "2018-04-05T20:06:36Z", 16 | "name": "martinsileno", 17 | "patchVersion": "", 18 | "shardId": "pc-eu", 19 | "stats": null, 20 | "titleId": "bluehole-pubg", 21 | "updatedAt": "2018-04-05T20:06:36Z" 22 | }, 23 | "relationships": { 24 | "assets": { 25 | "data": [] 26 | }, 27 | "matches": { 28 | "data": [ 29 | { 30 | "type": "match", 31 | "id": "a6d8d8f7-a3c4-4b1c-9947-8df40c144283" 32 | }, 33 | { 34 | "type": "match", 35 | "id": "65e16eb9-0c29-495f-97ad-e693faff6135" 36 | }, 37 | { 38 | "type": "match", 39 | "id": "2271eef0-d6cf-44bd-a281-660857844c9e" 40 | } 41 | ] 42 | } 43 | }, 44 | "links": { 45 | "schema": "", 46 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/players/account.a540a32a49784025939a975b45e86bfe" 47 | } 48 | }, 49 | "links": { 50 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/players/account.a540a32a49784025939a975b45e86bfe" 51 | }, 52 | "meta": {} 53 | } 54 | const API_LIST_RESPONSE = { 55 | "data": [ 56 | { 57 | "type": "player", 58 | "id": "account.cda9cb29e8ce4146a9ad46d5a0da508b", 59 | "attributes": { 60 | "createdAt": "2018-04-05T20:06:36Z", 61 | "name": "zaku6652", 62 | "patchVersion": "", 63 | "shardId": "pc-eu", 64 | "stats": null, 65 | "titleId": "bluehole-pubg", 66 | "updatedAt": "2018-04-05T20:06:36Z" 67 | }, 68 | "relationships": { 69 | "assets": { 70 | "data": [] 71 | }, 72 | "matches": { 73 | "data": [ 74 | { 75 | "type": "match", 76 | "id": "a6d8d8f7-a3c4-4b1c-9947-8df40c144283" 77 | }, 78 | { 79 | "type": "match", 80 | "id": "65e16eb9-0c29-495f-97ad-e693faff6135" 81 | }, 82 | { 83 | "type": "match", 84 | "id": "2271eef0-d6cf-44bd-a281-660857844c9e" 85 | } 86 | ] 87 | } 88 | }, 89 | "links": { 90 | "schema": "", 91 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/players/account.cda9cb29e8ce4146a9ad46d5a0da508b" 92 | } 93 | }, 94 | { 95 | "type": "player", 96 | "id": "account.a540a32a49784025939a975b45e86bfe", 97 | "attributes": { 98 | "createdAt": "2018-04-05T20:06:36Z", 99 | "name": "martinsileno", 100 | "patchVersion": "", 101 | "shardId": "pc-eu", 102 | "stats": null, 103 | "titleId": "bluehole-pubg", 104 | "updatedAt": "2018-04-05T20:06:36Z" 105 | }, 106 | "relationships": { 107 | "assets": { 108 | "data": [] 109 | }, 110 | "matches": { 111 | "data": [ 112 | { 113 | "type": "match", 114 | "id": "a6d8d8f7-a3c4-4b1c-9947-8df40c144283" 115 | }, 116 | { 117 | "type": "match", 118 | "id": "65e16eb9-0c29-495f-97ad-e693faff6135" 119 | }, 120 | { 121 | "type": "match", 122 | "id": "2271eef0-d6cf-44bd-a281-660857844c9e" 123 | } 124 | ] 125 | } 126 | }, 127 | "links": { 128 | "schema": "", 129 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/players/account.a540a32a49784025939a975b45e86bfe" 130 | } 131 | } 132 | ], 133 | "links": { 134 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/players?filter[playerNames]=martinsileno,zaku6652" 135 | }, 136 | "meta": {} 137 | } 138 | /* tslint:enable */ 139 | 140 | describe('Player entity', () => { 141 | 142 | it('should initialize a Player from API detail response', () => { 143 | const player = Player.fromDetail(API_DETAIL_RESPONSE); 144 | expect(player.id).to.equal('account.a540a32a49784025939a975b45e86bfe'); 145 | expect(player.name).to.equal('martinsileno'); 146 | expect(player.matchIds).to.eql([ 147 | 'a6d8d8f7-a3c4-4b1c-9947-8df40c144283', 148 | '65e16eb9-0c29-495f-97ad-e693faff6135', 149 | '2271eef0-d6cf-44bd-a281-660857844c9e', 150 | ]); 151 | }); 152 | 153 | it('should initialize a list of Player from API list response', () => { 154 | const players = Player.fromList(API_LIST_RESPONSE); 155 | expect(players).to.be.an('Array'); 156 | expect(players).to.have.length(2); 157 | const [p1, p2] = players; 158 | expect(p1.id).to.equal('account.cda9cb29e8ce4146a9ad46d5a0da508b'); 159 | expect(p1.name).to.equal('zaku6652'); 160 | expect(p1.matchIds).to.eql([ 161 | 'a6d8d8f7-a3c4-4b1c-9947-8df40c144283', 162 | '65e16eb9-0c29-495f-97ad-e693faff6135', 163 | '2271eef0-d6cf-44bd-a281-660857844c9e', 164 | ]); 165 | expect(p2.id).to.equal('account.a540a32a49784025939a975b45e86bfe'); 166 | expect(p2.name).to.equal('martinsileno'); 167 | expect(p2.matchIds).to.eql([ 168 | 'a6d8d8f7-a3c4-4b1c-9947-8df40c144283', 169 | '65e16eb9-0c29-495f-97ad-e693faff6135', 170 | '2271eef0-d6cf-44bd-a281-660857844c9e', 171 | ]); 172 | }); 173 | 174 | }); 175 | -------------------------------------------------------------------------------- /src/entities/player.ts: -------------------------------------------------------------------------------- 1 | import { IPlayer, IPlayerList, IPlayerObject, PlayersPubgAPI, PubgAPI } from '..'; 2 | 3 | 4 | /** 5 | * A PUBG Player. 6 | * 7 | * Contains basic info about a Player, such as ID and name. 8 | * 9 | * To retrieve details on the Matches this player took part in, see `Match` class. 10 | */ 11 | export class Player { 12 | private _id: string; 13 | private _name: string; 14 | private _shardId: string; 15 | private _matchIds: string[]; 16 | 17 | private constructor(player: IPlayerObject) { 18 | this._id = player.id; 19 | this._name = player.attributes.name; 20 | this._shardId = player.attributes.shardId; 21 | this._matchIds = player.relationships!.matches.data.map(m => m.id); 22 | } 23 | 24 | /** 25 | * Fetch a Player from PUBG API. 26 | * 27 | * Returns a `Promise` of the corresponding instance of the `Player` class. 28 | * 29 | * To retrieve a `Player`, **await** on the result of this method. 30 | * 31 | * @param api instance of `PubgAPI` that will be used to make the API request 32 | * @param playerId ID of the player to retrieve 33 | */ 34 | static async get(api: PubgAPI, playerId: string) { 35 | const playersAPI = new PlayersPubgAPI(api); 36 | const playerData = await playersAPI.get(playerId); 37 | return Player.fromDetail(playerData.data); 38 | } 39 | 40 | /** 41 | * Fetch a list of Players from PUBG API given a list of player IDs as input. 42 | * 43 | * Returns a `Promise` of a list of `Player` instances of players with the given IDs. 44 | * 45 | * To retrieve a list of `Player`s, **await** on the result of this method. 46 | * 47 | * @param api instance of `PubgAPI` that will be used to make the API request 48 | * @param playerIds list of player IDs 49 | */ 50 | static async filterById(api: PubgAPI, playerIds: string[]) { 51 | const playersAPI = new PlayersPubgAPI(api); 52 | const playersData = await playersAPI.listByID(playerIds); 53 | return Player.fromList(playersData.data); 54 | } 55 | 56 | /** 57 | * Fetch a list of Players from PUBG API, given a list of player names as input. 58 | * 59 | * Returns a `Promise` of a list of `Player` instances of players with the given names. 60 | * 61 | * To retrieve a list of `Player`s, **await** on the result of this method. 62 | * 63 | * @param api instance of `PubgAPI` that will be used to make the API request 64 | * @param playerNames list of player names 65 | */ 66 | static async filterByName(api: PubgAPI, playerNames: string[]) { 67 | const playersAPI = new PlayersPubgAPI(api); 68 | const playersData = await playersAPI.listByName(playerNames); 69 | return Player.fromList(playersData.data); 70 | } 71 | 72 | /** 73 | * Create and return a Player instance from an API player detail reply. 74 | * @param playerDetail Player resource as returned from PUBG API 75 | */ 76 | static fromDetail(playerDetail: IPlayer): Player { 77 | return new Player(playerDetail.data); 78 | } 79 | 80 | /** 81 | * Create and return a list of Player instances from an API player list reply. 82 | * @param playerList PlayerList resource as returned from PUBG API 83 | */ 84 | static fromList(playerList: IPlayerList): Player[] { 85 | const players: Player[] = []; 86 | playerList.data.forEach(playerData => { 87 | const player = new Player(playerData); 88 | players.push(player); 89 | }); 90 | return players; 91 | } 92 | 93 | /** 94 | * Player ID. 95 | */ 96 | get id() { 97 | return this._id; 98 | } 99 | 100 | /** 101 | * Player name. 102 | */ 103 | get name() { 104 | return this._name; 105 | } 106 | 107 | /** 108 | * List of match IDs this player took part in. 109 | * This list is ordered from most recent to oldest. 110 | */ 111 | get matchIds() { 112 | return this._matchIds; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/entities/playerSeason.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import 'mocha'; 3 | 4 | import { IPlayerSeason, PlayerSeason } from '..'; 5 | 6 | 7 | /* tslint:disable */ 8 | const API_RESPONSE: IPlayerSeason = { 9 | "data": { 10 | "type": "playerSeason", 11 | "attributes": { 12 | "gameModeStats": { 13 | "duo": { 14 | "assists": 0, 15 | "bestRankPoint": 0, 16 | "boosts": 0, 17 | "dBNOs": 0, 18 | "dailyKills": 0, 19 | "dailyWins": 0, 20 | "damageDealt": 0, 21 | "days": 0, 22 | "headshotKills": 0, 23 | "heals": 0, 24 | "killPoints": 0, 25 | "kills": 0, 26 | "longestKill": 0, 27 | "longestTimeSurvived": 0, 28 | "losses": 0, 29 | "maxKillStreaks": 0, 30 | "mostSurvivalTime": 0, 31 | "rankPoints": 0, 32 | "revives": 0, 33 | "rideDistance": 0, 34 | "roadKills": 0, 35 | "roundMostKills": 0, 36 | "roundsPlayed": 0, 37 | "suicides": 0, 38 | "swimDistance" : 0, 39 | "teamKills": 0, 40 | "timeSurvived": 0, 41 | "top10s": 0, 42 | "vehicleDestroys": 0, 43 | "walkDistance": 0, 44 | "weaponsAcquired": 0, 45 | "weeklyKills": 0, 46 | "weeklyWins": 0, 47 | "winPoints": 0, 48 | "wins": 0 49 | }, 50 | "duo-fpp": { 51 | "assists": 8, 52 | "bestRankPoint": 0, 53 | "boosts": 31, 54 | "dBNOs": 10, 55 | "dailyKills": 2, 56 | "dailyWins": 0, 57 | "damageDealt": 2730.9536, 58 | "days": 5, 59 | "headshotKills": 5, 60 | "heals": 25, 61 | "killPoints": 1180.1758, 62 | "kills": 15, 63 | "longestKill": 323.9015, 64 | "longestTimeSurvived": 1892.233, 65 | "losses": 23, 66 | "maxKillStreaks": 2, 67 | "mostSurvivalTime": 1892.233, 68 | "rankPoints": 0, 69 | "revives": 3, 70 | "rideDistance": 46569.055, 71 | "roadKills": 0, 72 | "roundMostKills": 4, 73 | "roundsPlayed": 24, 74 | "suicides": 1, 75 | "swimDistance" : 0, 76 | "teamKills": 2, 77 | "timeSurvived": 22971.379, 78 | "top10s": 8, 79 | "vehicleDestroys": 1, 80 | "walkDistance": 45455.348, 81 | "weaponsAcquired": 83, 82 | "weeklyKills": 6, 83 | "weeklyWins": 0, 84 | "winPoints": 1280.7273, 85 | "wins": 1 86 | }, 87 | "solo": { 88 | "assists": 0, 89 | "bestRankPoint": 0, 90 | "boosts": 0, 91 | "dBNOs": 0, 92 | "dailyKills": 0, 93 | "dailyWins": 0, 94 | "damageDealt": 0, 95 | "days": 0, 96 | "headshotKills": 0, 97 | "heals": 0, 98 | "killPoints": 0, 99 | "kills": 0, 100 | "longestKill": 0, 101 | "longestTimeSurvived": 0, 102 | "losses": 0, 103 | "maxKillStreaks": 0, 104 | "mostSurvivalTime": 0, 105 | "rankPoints": 0, 106 | "revives": 0, 107 | "rideDistance": 0, 108 | "roadKills": 0, 109 | "roundMostKills": 0, 110 | "roundsPlayed": 0, 111 | "suicides": 0, 112 | "swimDistance" : 0, 113 | "teamKills": 0, 114 | "timeSurvived": 0, 115 | "top10s": 0, 116 | "vehicleDestroys": 0, 117 | "walkDistance": 0, 118 | "weaponsAcquired": 0, 119 | "weeklyKills": 0, 120 | "weeklyWins": 0, 121 | "winPoints": 0, 122 | "wins": 0 123 | }, 124 | "solo-fpp": { 125 | "assists": 0, 126 | "bestRankPoint": 0, 127 | "boosts": 0, 128 | "dBNOs": 0, 129 | "dailyKills": 0, 130 | "dailyWins": 0, 131 | "damageDealt": 0, 132 | "days": 0, 133 | "headshotKills": 0, 134 | "heals": 0, 135 | "killPoints": 0, 136 | "kills": 0, 137 | "longestKill": 0, 138 | "longestTimeSurvived": 0, 139 | "losses": 0, 140 | "maxKillStreaks": 0, 141 | "mostSurvivalTime": 0, 142 | "rankPoints": 0, 143 | "revives": 0, 144 | "rideDistance": 0, 145 | "roadKills": 0, 146 | "roundMostKills": 0, 147 | "roundsPlayed": 0, 148 | "suicides": 0, 149 | "swimDistance" : 0, 150 | "teamKills": 0, 151 | "timeSurvived": 0, 152 | "top10s": 0, 153 | "vehicleDestroys": 0, 154 | "walkDistance": 0, 155 | "weaponsAcquired": 0, 156 | "weeklyKills": 0, 157 | "weeklyWins": 0, 158 | "winPoints": 0, 159 | "wins": 0 160 | }, 161 | "squad": { 162 | "assists": 0, 163 | "bestRankPoint": 0, 164 | "boosts": 0, 165 | "dBNOs": 0, 166 | "dailyKills": 0, 167 | "dailyWins": 0, 168 | "damageDealt": 0, 169 | "days": 0, 170 | "headshotKills": 0, 171 | "heals": 0, 172 | "killPoints": 0, 173 | "kills": 0, 174 | "longestKill": 0, 175 | "longestTimeSurvived": 0, 176 | "losses": 0, 177 | "maxKillStreaks": 0, 178 | "mostSurvivalTime": 0, 179 | "rankPoints": 0, 180 | "revives": 0, 181 | "rideDistance": 0, 182 | "roadKills": 0, 183 | "roundMostKills": 0, 184 | "roundsPlayed": 0, 185 | "suicides": 0, 186 | "swimDistance" : 0, 187 | "teamKills": 0, 188 | "timeSurvived": 0, 189 | "top10s": 0, 190 | "vehicleDestroys": 0, 191 | "walkDistance": 0, 192 | "weaponsAcquired": 0, 193 | "weeklyKills": 0, 194 | "weeklyWins": 0, 195 | "winPoints": 0, 196 | "wins": 0 197 | }, 198 | "squad-fpp": { 199 | "assists": 26, 200 | "bestRankPoint": 0, 201 | "boosts": 139, 202 | "dBNOs": 60, 203 | "dailyKills": 4, 204 | "dailyWins": 0, 205 | "damageDealt": 11883.432, 206 | "days": 18, 207 | "headshotKills": 12, 208 | "heals": 209, 209 | "killPoints": 1385.5311, 210 | "kills": 61, 211 | "longestKill": 249.45906, 212 | "longestTimeSurvived": 1935.326, 213 | "losses": 107, 214 | "maxKillStreaks": 4, 215 | "mostSurvivalTime": 1935.326, 216 | "rankPoints": 0, 217 | "revives": 20, 218 | "rideDistance": 240468.52, 219 | "roadKills": 2, 220 | "roundMostKills": 4, 221 | "roundsPlayed": 108, 222 | "suicides": 0, 223 | "swimDistance" : 0, 224 | "teamKills": 0, 225 | "timeSurvived": 110515.695, 226 | "top10s": 53, 227 | "vehicleDestroys": 1, 228 | "walkDistance": 208484.62, 229 | "weaponsAcquired": 381, 230 | "weeklyKills": 4, 231 | "weeklyWins": 0, 232 | "winPoints": 1519.7654, 233 | "wins": 1 234 | } 235 | } 236 | }, 237 | "relationships": { 238 | "matchesSquadFPP": { 239 | "data": [ 240 | { 241 | "type": "match", 242 | "id": "be4aa1ae-07a8-4511-99a6-eb81f7230a67" 243 | }, 244 | { 245 | "type": "match", 246 | "id": "0f13a919-0f9b-46bb-b7a6-809248f0455a" 247 | } 248 | ] 249 | }, 250 | "season": { 251 | "data": { 252 | "type": "season", 253 | "id": "division.bro.official.2018-04" 254 | } 255 | }, 256 | "player": { 257 | "data": { 258 | "type": "player", 259 | "id": "account.a540a32a49784025939a975b45e86bfe" 260 | } 261 | }, 262 | "matchesSolo": { 263 | "data": [] 264 | }, 265 | "matchesSoloFPP": { 266 | "data": [] 267 | }, 268 | "matchesDuo": { 269 | "data": [] 270 | }, 271 | "matchesDuoFPP": { 272 | "data": [ 273 | { 274 | "type": "match", 275 | "id": "dcc06c80-0216-47c8-8a68-935edff50e7f" 276 | }, 277 | { 278 | "type": "match", 279 | "id": "05c1bd64-323d-44e9-8b99-5dac92996964" 280 | } 281 | ] 282 | }, 283 | "matchesSquad": { 284 | "data": [] 285 | } 286 | } 287 | }, 288 | "links": { 289 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/players/account.a540a32a49784025939a975b45e86bfe/seasons/division.bro.official.2018-04" 290 | }, 291 | "meta": {} 292 | } 293 | /* tslint:enable */ 294 | 295 | describe('PlayerSeason entity', () => { 296 | it('should initialize a PlayerSeason from API response', () => { 297 | const playerSeason = PlayerSeason.fromSeasonData(API_RESPONSE); 298 | expect(playerSeason.playerId).to.eq('account.a540a32a49784025939a975b45e86bfe'); 299 | expect(playerSeason.seasonId).to.eq('division.bro.official.2018-04'); 300 | 301 | expect(playerSeason.duoFPPMatchIds).to.eql([ 302 | 'dcc06c80-0216-47c8-8a68-935edff50e7f', 303 | '05c1bd64-323d-44e9-8b99-5dac92996964', 304 | ]); 305 | expect(playerSeason.duoMatchIds).to.eql([]); 306 | expect(playerSeason.soloFPPMatchIds).to.eql([]); 307 | expect(playerSeason.soloMatchIds).to.eql([]); 308 | expect(playerSeason.squadFPPMatchIds).to.eql([ 309 | 'be4aa1ae-07a8-4511-99a6-eb81f7230a67', 310 | '0f13a919-0f9b-46bb-b7a6-809248f0455a', 311 | ]); 312 | expect(playerSeason.squadMatchIds).to.eql([]); 313 | 314 | expect(playerSeason.duoFPPStats.assists).to.eq(8); 315 | expect(playerSeason.duoFPPStats.bestRankPoint).to.eq(0); 316 | expect(playerSeason.duoFPPStats.boosts).to.eq(31); 317 | expect(playerSeason.duoFPPStats.dBNOs).to.eq(10); 318 | expect(playerSeason.duoFPPStats.dailyKills).to.eq(2); 319 | expect(playerSeason.squadFPPStats.dailyWins).to.eq(0); 320 | expect(playerSeason.duoFPPStats.damageDealt).to.eq(2730.9536); 321 | expect(playerSeason.duoFPPStats.days).to.eq(5); 322 | expect(playerSeason.duoFPPStats.headshotKills).to.eq(5); 323 | expect(playerSeason.duoFPPStats.heals).to.eq(25); 324 | expect(playerSeason.duoFPPStats.killPoints).to.eq(1180.1758); 325 | expect(playerSeason.duoFPPStats.kills).to.eq(15); 326 | expect(playerSeason.duoFPPStats.longestKill).to.eq(323.9015); 327 | expect(playerSeason.duoFPPStats.longestTimeSurvived).to.eq(1892.233); 328 | expect(playerSeason.duoFPPStats.losses).to.eq(23); 329 | expect(playerSeason.duoFPPStats.maxKillStreaks).to.eq(2); 330 | expect(playerSeason.duoFPPStats.mostSurvivalTime).to.eq(1892.233); 331 | expect(playerSeason.duoFPPStats.rankPoints).to.eq(0); 332 | expect(playerSeason.duoFPPStats.revives).to.eq(3); 333 | expect(playerSeason.duoFPPStats.rideDistance).to.eq(46569.055); 334 | expect(playerSeason.duoFPPStats.roadKills).to.eq(0); 335 | expect(playerSeason.duoFPPStats.roundMostKills).to.eq(4); 336 | expect(playerSeason.duoFPPStats.roundsPlayed).to.eq(24); 337 | expect(playerSeason.duoFPPStats.suicides).to.eq(1); 338 | expect(playerSeason.duoFPPStats.swimDistance).to.eq(0); 339 | expect(playerSeason.duoFPPStats.teamKills).to.eq(2); 340 | expect(playerSeason.duoFPPStats.timeSurvived).to.eq(22971.379); 341 | expect(playerSeason.duoFPPStats.top10s).to.eq(8); 342 | expect(playerSeason.duoFPPStats.vehicleDestroys).to.eq(1); 343 | expect(playerSeason.duoFPPStats.walkDistance).to.eq(45455.348); 344 | expect(playerSeason.duoFPPStats.weaponsAcquired).to.eq(83); 345 | expect(playerSeason.duoFPPStats.weeklyKills).to.eq(6); 346 | expect(playerSeason.duoFPPStats.weeklyWins).to.eq(0); 347 | expect(playerSeason.duoFPPStats.winPoints).to.eq(1280.7273); 348 | expect(playerSeason.duoFPPStats.wins).to.eq(1); 349 | 350 | expect(playerSeason.duoStats.assists).to.eq(0); 351 | expect(playerSeason.duoStats.bestRankPoint).to.eq(0); 352 | expect(playerSeason.duoStats.boosts).to.eq(0); 353 | expect(playerSeason.duoStats.dBNOs).to.eq(0); 354 | expect(playerSeason.duoStats.dailyKills).to.eq(0); 355 | expect(playerSeason.duoStats.dailyWins).to.eq(0); 356 | expect(playerSeason.duoStats.damageDealt).to.eq(0); 357 | expect(playerSeason.duoStats.days).to.eq(0); 358 | expect(playerSeason.duoStats.headshotKills).to.eq(0); 359 | expect(playerSeason.duoStats.heals).to.eq(0); 360 | expect(playerSeason.duoStats.killPoints).to.eq(0); 361 | expect(playerSeason.duoStats.kills).to.eq(0); 362 | expect(playerSeason.duoStats.longestKill).to.eq(0); 363 | expect(playerSeason.duoStats.longestTimeSurvived).to.eq(0); 364 | expect(playerSeason.duoStats.losses).to.eq(0); 365 | expect(playerSeason.duoStats.maxKillStreaks).to.eq(0); 366 | expect(playerSeason.duoStats.mostSurvivalTime).to.eq(0); 367 | expect(playerSeason.duoStats.rankPoints).to.eq(0); 368 | expect(playerSeason.duoStats.revives).to.eq(0); 369 | expect(playerSeason.duoStats.rideDistance).to.eq(0); 370 | expect(playerSeason.duoStats.roadKills).to.eq(0); 371 | expect(playerSeason.duoStats.roundMostKills).to.eq(0); 372 | expect(playerSeason.duoStats.roundsPlayed).to.eq(0); 373 | expect(playerSeason.duoStats.suicides).to.eq(0); 374 | expect(playerSeason.duoStats.swimDistance).to.eq(0); 375 | expect(playerSeason.duoStats.teamKills).to.eq(0); 376 | expect(playerSeason.duoStats.timeSurvived).to.eq(0); 377 | expect(playerSeason.duoStats.top10s).to.eq(0); 378 | expect(playerSeason.duoStats.vehicleDestroys).to.eq(0); 379 | expect(playerSeason.duoStats.walkDistance).to.eq(0); 380 | expect(playerSeason.duoStats.weaponsAcquired).to.eq(0); 381 | expect(playerSeason.duoStats.weeklyKills).to.eq(0); 382 | expect(playerSeason.duoStats.weeklyWins).to.eq(0); 383 | expect(playerSeason.duoStats.winPoints).to.eq(0); 384 | expect(playerSeason.duoStats.wins).to.eq(0); 385 | 386 | expect(playerSeason.soloStats.assists).to.eq(0); 387 | expect(playerSeason.soloStats.bestRankPoint).to.eq(0); 388 | expect(playerSeason.soloStats.boosts).to.eq(0); 389 | expect(playerSeason.soloStats.dBNOs).to.eq(0); 390 | expect(playerSeason.soloStats.dailyKills).to.eq(0); 391 | expect(playerSeason.soloStats.dailyWins).to.eq(0); 392 | expect(playerSeason.soloStats.damageDealt).to.eq(0); 393 | expect(playerSeason.soloStats.days).to.eq(0); 394 | expect(playerSeason.soloStats.headshotKills).to.eq(0); 395 | expect(playerSeason.soloStats.heals).to.eq(0); 396 | expect(playerSeason.soloStats.killPoints).to.eq(0); 397 | expect(playerSeason.soloStats.kills).to.eq(0); 398 | expect(playerSeason.soloStats.longestKill).to.eq(0); 399 | expect(playerSeason.soloStats.longestTimeSurvived).to.eq(0); 400 | expect(playerSeason.soloStats.losses).to.eq(0); 401 | expect(playerSeason.soloStats.maxKillStreaks).to.eq(0); 402 | expect(playerSeason.soloStats.mostSurvivalTime).to.eq(0); 403 | expect(playerSeason.soloStats.rankPoints).to.eq(0); 404 | expect(playerSeason.soloStats.revives).to.eq(0); 405 | expect(playerSeason.soloStats.rideDistance).to.eq(0); 406 | expect(playerSeason.soloStats.roadKills).to.eq(0); 407 | expect(playerSeason.soloStats.roundMostKills).to.eq(0); 408 | expect(playerSeason.soloStats.roundsPlayed).to.eq(0); 409 | expect(playerSeason.soloStats.suicides).to.eq(0); 410 | expect(playerSeason.soloStats.swimDistance).to.eq(0); 411 | expect(playerSeason.soloStats.teamKills).to.eq(0); 412 | expect(playerSeason.soloStats.timeSurvived).to.eq(0); 413 | expect(playerSeason.soloStats.top10s).to.eq(0); 414 | expect(playerSeason.soloStats.vehicleDestroys).to.eq(0); 415 | expect(playerSeason.soloStats.walkDistance).to.eq(0); 416 | expect(playerSeason.soloStats.weaponsAcquired).to.eq(0); 417 | expect(playerSeason.soloStats.weeklyKills).to.eq(0); 418 | expect(playerSeason.soloStats.weeklyWins).to.eq(0); 419 | expect(playerSeason.soloStats.winPoints).to.eq(0); 420 | expect(playerSeason.soloStats.wins).to.eq(0); 421 | 422 | expect(playerSeason.soloFPPStats.assists).to.eq(0); 423 | expect(playerSeason.soloFPPStats.bestRankPoint).to.eq(0); 424 | expect(playerSeason.soloFPPStats.boosts).to.eq(0); 425 | expect(playerSeason.soloFPPStats.dBNOs).to.eq(0); 426 | expect(playerSeason.soloFPPStats.dailyKills).to.eq(0); 427 | expect(playerSeason.soloFPPStats.dailyWins).to.eq(0); 428 | expect(playerSeason.soloFPPStats.damageDealt).to.eq(0); 429 | expect(playerSeason.soloFPPStats.days).to.eq(0); 430 | expect(playerSeason.soloFPPStats.headshotKills).to.eq(0); 431 | expect(playerSeason.soloFPPStats.heals).to.eq(0); 432 | expect(playerSeason.soloFPPStats.killPoints).to.eq(0); 433 | expect(playerSeason.soloFPPStats.kills).to.eq(0); 434 | expect(playerSeason.soloFPPStats.longestKill).to.eq(0); 435 | expect(playerSeason.soloFPPStats.longestTimeSurvived).to.eq(0); 436 | expect(playerSeason.soloFPPStats.losses).to.eq(0); 437 | expect(playerSeason.soloFPPStats.maxKillStreaks).to.eq(0); 438 | expect(playerSeason.soloFPPStats.mostSurvivalTime).to.eq(0); 439 | expect(playerSeason.soloFPPStats.rankPoints).to.eq(0); 440 | expect(playerSeason.soloFPPStats.revives).to.eq(0); 441 | expect(playerSeason.soloFPPStats.rideDistance).to.eq(0); 442 | expect(playerSeason.soloFPPStats.roadKills).to.eq(0); 443 | expect(playerSeason.soloFPPStats.roundMostKills).to.eq(0); 444 | expect(playerSeason.soloFPPStats.roundsPlayed).to.eq(0); 445 | expect(playerSeason.soloFPPStats.suicides).to.eq(0); 446 | expect(playerSeason.soloFPPStats.swimDistance).to.eq(0); 447 | expect(playerSeason.soloFPPStats.teamKills).to.eq(0); 448 | expect(playerSeason.soloFPPStats.timeSurvived).to.eq(0); 449 | expect(playerSeason.soloFPPStats.top10s).to.eq(0); 450 | expect(playerSeason.soloFPPStats.vehicleDestroys).to.eq(0); 451 | expect(playerSeason.soloFPPStats.walkDistance).to.eq(0); 452 | expect(playerSeason.soloFPPStats.weaponsAcquired).to.eq(0); 453 | expect(playerSeason.soloFPPStats.weeklyKills).to.eq(0); 454 | expect(playerSeason.soloFPPStats.weeklyWins).to.eq(0); 455 | expect(playerSeason.soloFPPStats.winPoints).to.eq(0); 456 | expect(playerSeason.soloFPPStats.wins).to.eq(0); 457 | 458 | expect(playerSeason.squadStats.assists).to.eq(0); 459 | expect(playerSeason.squadStats.bestRankPoint).to.eq(0); 460 | expect(playerSeason.squadStats.boosts).to.eq(0); 461 | expect(playerSeason.squadStats.dBNOs).to.eq(0); 462 | expect(playerSeason.squadStats.dailyKills).to.eq(0); 463 | expect(playerSeason.squadStats.dailyWins).to.eq(0); 464 | expect(playerSeason.squadStats.damageDealt).to.eq(0); 465 | expect(playerSeason.squadStats.days).to.eq(0); 466 | expect(playerSeason.squadStats.headshotKills).to.eq(0); 467 | expect(playerSeason.squadStats.heals).to.eq(0); 468 | expect(playerSeason.squadStats.killPoints).to.eq(0); 469 | expect(playerSeason.squadStats.kills).to.eq(0); 470 | expect(playerSeason.squadStats.longestKill).to.eq(0); 471 | expect(playerSeason.squadStats.longestTimeSurvived).to.eq(0); 472 | expect(playerSeason.squadStats.losses).to.eq(0); 473 | expect(playerSeason.squadStats.maxKillStreaks).to.eq(0); 474 | expect(playerSeason.squadStats.mostSurvivalTime).to.eq(0); 475 | expect(playerSeason.squadStats.rankPoints).to.eq(0); 476 | expect(playerSeason.squadStats.revives).to.eq(0); 477 | expect(playerSeason.squadStats.rideDistance).to.eq(0); 478 | expect(playerSeason.squadStats.roadKills).to.eq(0); 479 | expect(playerSeason.squadStats.roundMostKills).to.eq(0); 480 | expect(playerSeason.squadStats.roundsPlayed).to.eq(0); 481 | expect(playerSeason.squadStats.suicides).to.eq(0); 482 | expect(playerSeason.squadStats.swimDistance).to.eq(0); 483 | expect(playerSeason.squadStats.teamKills).to.eq(0); 484 | expect(playerSeason.squadStats.timeSurvived).to.eq(0); 485 | expect(playerSeason.squadStats.top10s).to.eq(0); 486 | expect(playerSeason.squadStats.vehicleDestroys).to.eq(0); 487 | expect(playerSeason.squadStats.walkDistance).to.eq(0); 488 | expect(playerSeason.squadStats.weaponsAcquired).to.eq(0); 489 | expect(playerSeason.squadStats.weeklyKills).to.eq(0); 490 | expect(playerSeason.squadStats.weeklyWins).to.eq(0); 491 | expect(playerSeason.squadStats.winPoints).to.eq(0); 492 | expect(playerSeason.squadStats.wins).to.eq(0); 493 | 494 | expect(playerSeason.squadFPPStats.assists).to.eq(26); 495 | expect(playerSeason.squadFPPStats.bestRankPoint).to.eq(0); 496 | expect(playerSeason.squadFPPStats.boosts).to.eq(139); 497 | expect(playerSeason.squadFPPStats.dBNOs).to.eq(60); 498 | expect(playerSeason.squadFPPStats.dailyKills).to.eq(4); 499 | expect(playerSeason.squadFPPStats.dailyWins).to.eq(0); 500 | expect(playerSeason.squadFPPStats.damageDealt).to.eq(11883.432); 501 | expect(playerSeason.squadFPPStats.days).to.eq(18); 502 | expect(playerSeason.squadFPPStats.headshotKills).to.eq(12); 503 | expect(playerSeason.squadFPPStats.heals).to.eq(209); 504 | expect(playerSeason.squadFPPStats.killPoints).to.eq(1385.5311); 505 | expect(playerSeason.squadFPPStats.kills).to.eq(61); 506 | expect(playerSeason.squadFPPStats.longestKill).to.eq(249.45906); 507 | expect(playerSeason.squadFPPStats.longestTimeSurvived).to.eq(1935.326); 508 | expect(playerSeason.squadFPPStats.losses).to.eq(107); 509 | expect(playerSeason.squadFPPStats.maxKillStreaks).to.eq(4); 510 | expect(playerSeason.squadFPPStats.mostSurvivalTime).to.eq(1935.326); 511 | expect(playerSeason.squadFPPStats.rankPoints).to.eq(0); 512 | expect(playerSeason.squadFPPStats.revives).to.eq(20); 513 | expect(playerSeason.squadFPPStats.rideDistance).to.eq(240468.52); 514 | expect(playerSeason.squadFPPStats.roadKills).to.eq(2); 515 | expect(playerSeason.squadFPPStats.roundMostKills).to.eq(4); 516 | expect(playerSeason.squadFPPStats.roundsPlayed).to.eq(108); 517 | expect(playerSeason.squadFPPStats.suicides).to.eq(0); 518 | expect(playerSeason.squadFPPStats.swimDistance).to.eq(0); 519 | expect(playerSeason.squadFPPStats.teamKills).to.eq(0); 520 | expect(playerSeason.squadFPPStats.timeSurvived).to.eq(110515.695); 521 | expect(playerSeason.squadFPPStats.top10s).to.eq(53); 522 | expect(playerSeason.squadFPPStats.vehicleDestroys).to.eq(1); 523 | expect(playerSeason.squadFPPStats.walkDistance).to.eq(208484.62); 524 | expect(playerSeason.squadFPPStats.weaponsAcquired).to.eq(381); 525 | expect(playerSeason.squadFPPStats.weeklyKills).to.eq(4); 526 | expect(playerSeason.squadFPPStats.weeklyWins).to.eq(0); 527 | expect(playerSeason.squadFPPStats.winPoints).to.eq(1519.7654); 528 | expect(playerSeason.squadFPPStats.wins).to.eq(1); 529 | }); 530 | }); 531 | -------------------------------------------------------------------------------- /src/entities/playerSeason.ts: -------------------------------------------------------------------------------- 1 | import { GameModeStats, IPlayerSeason, PlayersPubgAPI, PubgAPI } from '..'; 2 | 3 | 4 | /** 5 | * Statistics for a player in a given season. 6 | * 7 | * Initialize this by calling the `get` method with an instance of `PubgAPI`, a player ID and 8 | * a season ID. 9 | * 10 | * The returned instance of this class will contain, for each game mode, the stats and a list of 11 | * Match IDs. 12 | */ 13 | export class PlayerSeason { 14 | private _playerId: string; 15 | private _seasonId: string; 16 | 17 | private _duoFPPStats: GameModeStats; 18 | private _duoStats: GameModeStats; 19 | private _duoMatchIds: string[]; 20 | private _duoFPPMatchIds: string[]; 21 | 22 | private _soloFPPStats: GameModeStats; 23 | private _soloStats: GameModeStats; 24 | private _soloMatchIds: string[]; 25 | private _soloFPPMatchIds: string[]; 26 | 27 | private _squadFPPStats: GameModeStats; 28 | private _squadStats: GameModeStats; 29 | private _squadMatchIds: string[]; 30 | private _squadFPPMatchIds: string[]; 31 | 32 | private constructor(playerSeason: IPlayerSeason) { 33 | const relationships = playerSeason.data.relationships; 34 | this._playerId = relationships.player.data.id; 35 | this._seasonId = relationships.season.data.id; 36 | 37 | const gameModesStats = playerSeason.data.attributes.gameModeStats; 38 | this._duoStats = new GameModeStats(gameModesStats.duo); 39 | this._duoFPPStats = new GameModeStats(gameModesStats['duo-fpp']); 40 | this._duoMatchIds = relationships.matchesDuo.data.map(elem => elem.id); 41 | this._duoFPPMatchIds = relationships.matchesDuoFPP.data.map(elem => elem.id); 42 | 43 | this._soloStats = new GameModeStats(gameModesStats.solo); 44 | this._soloFPPStats = new GameModeStats(gameModesStats['solo-fpp']); 45 | this._soloMatchIds = relationships.matchesSolo.data.map(elem => elem.id); 46 | this._soloFPPMatchIds = relationships.matchesSoloFPP.data.map(elem => elem.id); 47 | 48 | this._squadStats = new GameModeStats(gameModesStats.squad); 49 | this._squadFPPStats = new GameModeStats(gameModesStats['squad-fpp']); 50 | this._squadMatchIds = relationships.matchesSquad.data.map(elem => elem.id); 51 | this._squadFPPMatchIds = relationships.matchesSquadFPP.data.map(elem => elem.id); 52 | } 53 | 54 | static async get(api: PubgAPI, playerId: string, seasonId: string) { 55 | const playerAPI = new PlayersPubgAPI(api); 56 | const seasonData = await playerAPI.getSeasonStats(playerId, seasonId); 57 | return PlayerSeason.fromSeasonData(seasonData.data); 58 | } 59 | 60 | static fromSeasonData(seasonData: IPlayerSeason) { 61 | return new PlayerSeason(seasonData); 62 | } 63 | 64 | get playerId(): string { 65 | return this._playerId; 66 | } 67 | 68 | get seasonId(): string { 69 | return this._seasonId; 70 | } 71 | 72 | get duoFPPStats(): GameModeStats { 73 | return this._duoFPPStats; 74 | } 75 | 76 | get duoStats(): GameModeStats { 77 | return this._duoStats; 78 | } 79 | 80 | get duoMatchIds(): string[] { 81 | return this._duoMatchIds; 82 | } 83 | 84 | get duoFPPMatchIds(): string[] { 85 | return this._duoFPPMatchIds; 86 | } 87 | 88 | get soloFPPStats(): GameModeStats { 89 | return this._soloFPPStats; 90 | } 91 | 92 | get soloStats(): GameModeStats { 93 | return this._soloStats; 94 | } 95 | 96 | get soloMatchIds(): string[] { 97 | return this._soloMatchIds; 98 | } 99 | 100 | get soloFPPMatchIds(): string[] { 101 | return this._soloFPPMatchIds; 102 | } 103 | 104 | get squadFPPStats(): GameModeStats { 105 | return this._squadFPPStats; 106 | } 107 | 108 | get squadStats(): GameModeStats { 109 | return this._squadStats; 110 | } 111 | 112 | get squadMatchIds(): string[] { 113 | return this._squadMatchIds; 114 | } 115 | 116 | get squadFPPMatchIds(): string[] { 117 | return this._squadFPPMatchIds; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/entities/roster.ts: -------------------------------------------------------------------------------- 1 | import { IRoster } from '..'; 2 | 3 | import { Participant } from './participant'; 4 | 5 | 6 | export class Roster { 7 | private _id: string; 8 | private _hasWon: boolean; 9 | private _rank: number; 10 | private _teamId: number; 11 | 12 | private _participants: Participant[]; 13 | 14 | constructor(roster: IRoster) { 15 | this._id = roster.id; 16 | this._hasWon = roster.attributes.won === 'true'; 17 | this._rank = roster.attributes.stats.rank; 18 | this._teamId = roster.attributes.stats.teamId; 19 | this._participants = []; 20 | } 21 | 22 | get id() { 23 | return this._id; 24 | } 25 | 26 | get hasWon() { 27 | return this._hasWon; 28 | } 29 | 30 | get rank() { 31 | return this._rank; 32 | } 33 | 34 | get teamId() { 35 | return this._teamId; 36 | } 37 | 38 | get participants() { 39 | return this._participants; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/entities/sample.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import 'mocha'; 3 | 4 | import { ISample, PlatformRegion } from '..'; 5 | 6 | import { Sample } from './sample'; 7 | 8 | 9 | /* tslint:disable */ 10 | const API_RESPONSE: ISample = { 11 | "data": { 12 | "type": "sample", 13 | "id": "258d93e8-9250-467b-84e0-13444d3e4080", 14 | "attributes": { 15 | "createdAt": "2018-04-25T23:57:50Z", 16 | "titleId": "bluehole-pubg", 17 | "shardId": "pc-na" 18 | }, 19 | "relationships": { 20 | "matches": { 21 | "data": [ 22 | { 23 | "type": "match", 24 | "id": "83f01a5f-9664-4e4d-be60-f6a5ba332f40" 25 | }, 26 | { 27 | "type": "match", 28 | "id": "81dff04f-115c-4edd-b2ef-ba9eafeb683d" 29 | }, 30 | { 31 | "type": "match", 32 | "id": "db4c21ef-84c7-4bdb-97a4-2f4a6f40361a" 33 | } 34 | // *snip* 35 | ] 36 | } 37 | } 38 | } 39 | } 40 | /* tslint:enable */ 41 | 42 | describe('Sample entity', () => { 43 | 44 | it('should initialize Sample object from response', () => { 45 | const sample = Sample.fromDetail(API_RESPONSE); 46 | expect(sample.id).to.equal('258d93e8-9250-467b-84e0-13444d3e4080'); 47 | expect(sample.dateCreated).to.deep.equal(new Date('2018-04-25T23:57:50Z')); 48 | expect(sample.shardId).to.equal(PlatformRegion.PC_NA); 49 | expect(sample.matchIds).to.eql([ 50 | '83f01a5f-9664-4e4d-be60-f6a5ba332f40', 51 | '81dff04f-115c-4edd-b2ef-ba9eafeb683d', 52 | 'db4c21ef-84c7-4bdb-97a4-2f4a6f40361a', 53 | ]); 54 | }); 55 | 56 | }); 57 | -------------------------------------------------------------------------------- /src/entities/sample.ts: -------------------------------------------------------------------------------- 1 | import { ISample, PlatformRegion, PubgAPI, SamplesPubgAPI } from '..'; 2 | 3 | 4 | /** 5 | * A list of sample match IDs. 6 | */ 7 | export class Sample { 8 | private _id: string; 9 | private _dateCreated: Date; 10 | private _shardId: PlatformRegion; 11 | 12 | private _matchIds: string[]; 13 | 14 | private constructor(sampleData: ISample) { 15 | this._id = sampleData.data.id; 16 | this._dateCreated = new Date(sampleData.data.attributes.createdAt); 17 | this._shardId = sampleData.data.attributes.shardId as PlatformRegion; 18 | const matchIds: string[] = []; 19 | sampleData.data.relationships.matches.data.forEach(matchData => { 20 | matchIds.push(matchData.id); 21 | }); 22 | this._matchIds = matchIds; 23 | } 24 | 25 | static async get(api: PubgAPI, fromDate?: Date) { 26 | const samplesAPI = new SamplesPubgAPI(api); 27 | const samplesData = await samplesAPI.get(fromDate); 28 | return Sample.fromDetail(samplesData.data); 29 | } 30 | 31 | static fromDetail(matchDetail: ISample): Sample { 32 | return new Sample(matchDetail); 33 | } 34 | 35 | get id() { 36 | return this._id; 37 | } 38 | 39 | get dateCreated() { 40 | return this._dateCreated; 41 | } 42 | 43 | get shardId() { 44 | return this._shardId; 45 | } 46 | 47 | get matchIds() { 48 | return this._matchIds; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/entities/season.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import 'mocha'; 3 | 4 | import { ISeasonList } from '..'; 5 | 6 | import { Season } from './season'; 7 | 8 | 9 | /* tslint:disable */ 10 | const API_RESPONSE: ISeasonList = { 11 | "data": [ 12 | { 13 | "type": "season", 14 | "id": "division.bro.official.2018-03", 15 | "attributes": { 16 | "isCurrentSeason": false, 17 | "isOffseason": false 18 | } 19 | }, 20 | { 21 | "type": "season", 22 | "id": "division.bro.official.2018-04", 23 | "attributes": { 24 | "isCurrentSeason": true, 25 | "isOffseason": false 26 | } 27 | } 28 | ], 29 | "links": { 30 | "self": "https://api.playbattlegrounds.com/shards/pc-eu/seasons" 31 | }, 32 | "meta": {} 33 | } 34 | /* tslint:enable */ 35 | 36 | describe('Season entity', () => { 37 | it('should initialize a list of Season from API list response', () => { 38 | const seasons = Season.fromList(API_RESPONSE); 39 | expect(seasons).to.be.an('Array'); 40 | expect(seasons).to.have.length(2); 41 | const [s1, s2] = seasons; 42 | expect(s1.id).to.eq('division.bro.official.2018-03'); 43 | expect(s1.isCurrentSeason).to.be.false; 44 | expect(s1.isOffSeason).to.be.false; 45 | expect(s2.isCurrentSeason).to.be.true; 46 | expect(s2.isOffSeason).to.be.false; 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/entities/season.ts: -------------------------------------------------------------------------------- 1 | import { ISeason, ISeasonList, PubgAPI, SeasonsPubgAPI } from '..'; 2 | 3 | 4 | /** 5 | * A PUBG Season. 6 | * 7 | * Contains ID and info on a Season. The season has an ID and two boolean values that indicate 8 | * whether or not it is the current season or if it is off-season. 9 | * 10 | * Use the `list` static method to get a list of all the seasons. 11 | */ 12 | export class Season { 13 | private _id: string; 14 | private _isCurrentSeason: boolean; 15 | private _isOffSeason: boolean; 16 | 17 | private constructor(season: ISeason) { 18 | this._id = season.id; 19 | this._isCurrentSeason = season.attributes.isCurrentSeason; 20 | this._isOffSeason = season.attributes.isOffseason; 21 | } 22 | 23 | /** 24 | * Return a complete list of Season objects from PUBG API. 25 | * 26 | * @param api instance of `PubgAPI` that will be used to make the API request 27 | */ 28 | static async list(api: PubgAPI) { 29 | const seasonsAPI = new SeasonsPubgAPI(api); 30 | const seasonsData = await seasonsAPI.list(); 31 | return Season.fromList(seasonsData.data); 32 | } 33 | 34 | static fromList(seasonList: ISeasonList): Season[] { 35 | const seasons: Season[] = []; 36 | seasonList.data.forEach(season => { 37 | seasons.push(new Season(season)); 38 | }); 39 | 40 | return seasons; 41 | } 42 | 43 | get id() { 44 | return this._id; 45 | } 46 | 47 | /** 48 | * Indicates if the season is active. 49 | */ 50 | get isCurrentSeason() { 51 | return this._isCurrentSeason; 52 | } 53 | 54 | /** 55 | * Indicates if the season is not active. 56 | */ 57 | get isOffSeason() { 58 | return this._isOffSeason; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/entities/status.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import 'mocha'; 3 | 4 | import { IStatus, Status } from '..'; 5 | 6 | 7 | /* tslint:disable */ 8 | const API_RESPONSE: IStatus = { 9 | "data": { 10 | "type": "status", 11 | "id": "pubg-api", 12 | "ping": 20 13 | } 14 | } 15 | /* tslint:enable */ 16 | 17 | describe('Status entity', () => { 18 | 19 | it('should initialize Status object from response', () => { 20 | const status: Status = Status.fromDetail(API_RESPONSE); 21 | expect(status.id).to.equal('pubg-api'); 22 | expect(status.type).to.equal('status'); 23 | expect(status.ping).to.equal(20); 24 | }); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /src/entities/status.ts: -------------------------------------------------------------------------------- 1 | import { IStatus, PubgAPI, StatusPubgAPI } from '..'; 2 | 3 | 4 | /** 5 | * The status of the api 6 | */ 7 | export class Status { 8 | private _id: string; 9 | private _ping: number; 10 | private _type: string; 11 | 12 | private constructor(statusData: IStatus) { 13 | this._id = statusData.data.id; 14 | this._ping = statusData.data.ping; 15 | this._type = statusData.data.type; 16 | } 17 | 18 | static async get(api: PubgAPI): Promise { 19 | const statusAPI: StatusPubgAPI = new StatusPubgAPI(); 20 | const startDate: Date = new Date(); 21 | 22 | const statusData = await statusAPI.get(); 23 | const ping: number = (new Date().getTime() - startDate.getTime()); 24 | statusData.data.data.ping = ping; 25 | 26 | return Status.fromDetail(statusData.data); 27 | } 28 | 29 | static fromDetail(statusDetail: IStatus): Status { 30 | return new Status(statusDetail); 31 | } 32 | 33 | get id(): string { 34 | return this._id; 35 | } 36 | 37 | get ping(): number { 38 | return this._ping; 39 | } 40 | 41 | get type(): string { 42 | return this._type; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/armorDestroy.ts: -------------------------------------------------------------------------------- 1 | import { ILogArmorDestroy } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ArmorDestroy extends TelemetryEvent { 10 | private _attackId: number; 11 | private _attacker: Character; 12 | private _victim: Character; 13 | private _damageTypeCategory: string; 14 | private _damageReason: string; 15 | private _damageCauserName: string; 16 | private _item: Item; 17 | private _distance: number; 18 | 19 | constructor(event: ILogArmorDestroy) { 20 | super(event); 21 | this._attackId = event.attackId; 22 | this._attacker = new Character(event.attacker); 23 | this._victim = new Character(event.victim); 24 | this._damageTypeCategory = event.damageTypeCategory; 25 | this._damageReason = event.damageReason; 26 | this._damageCauserName = event.damageCauserName; 27 | this._item = new Item(event.item); 28 | this._distance = event.distance; 29 | } 30 | 31 | get attackId(): number { 32 | return this._attackId; 33 | } 34 | 35 | get attacker(): Character { 36 | return this._attacker; 37 | } 38 | 39 | get victim(): Character { 40 | return this._victim; 41 | } 42 | 43 | get damageTypeCategory(): string { 44 | return this._damageTypeCategory; 45 | } 46 | 47 | get damageReason(): string { 48 | return this._damageReason; 49 | } 50 | 51 | get damageCauserName(): string { 52 | return this._damageCauserName; 53 | } 54 | 55 | get item(): Item { 56 | return this._item; 57 | } 58 | 59 | get distance(): number { 60 | return this._distance; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/carePackageLand.ts: -------------------------------------------------------------------------------- 1 | import { ILogCarePackageLand } from '../../..'; 2 | 3 | import { ItemPackage } from '../objects/itemPackage'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class CarePackageLand extends TelemetryEvent { 9 | private _itemPackage: ItemPackage; 10 | 11 | constructor(event: ILogCarePackageLand) { 12 | super(event); 13 | this._itemPackage = new ItemPackage(event.itemPackage); 14 | } 15 | 16 | get itemPackage() { 17 | return this._itemPackage; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/carePackageSpawn.ts: -------------------------------------------------------------------------------- 1 | import { ILogCarePackageSpawn } from '../../..'; 2 | 3 | import { ItemPackage } from '../objects/itemPackage'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class CarePackageSpawn extends TelemetryEvent { 9 | private _itemPackage: ItemPackage; 10 | 11 | constructor(event: ILogCarePackageSpawn) { 12 | super(event); 13 | this._itemPackage = new ItemPackage(event.itemPackage); 14 | } 15 | 16 | get itemPackage() { 17 | return this._itemPackage; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/gameStatePeriodic.ts: -------------------------------------------------------------------------------- 1 | import { ILogGameStatePeriodic } from '../../..'; 2 | 3 | import { GameState } from '../objects/gameState'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class GameStatePeriodic extends TelemetryEvent { 9 | private _gameState: GameState; 10 | 11 | constructor(event: ILogGameStatePeriodic) { 12 | super(event); 13 | this._gameState = new GameState(event.gameState); 14 | } 15 | 16 | get gameState(): GameState { 17 | return this._gameState; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/index.ts: -------------------------------------------------------------------------------- 1 | export * from './armorDestroy'; 2 | export * from './carePackageLand'; 3 | export * from './carePackageSpawn'; 4 | export * from './gameStatePeriodic'; 5 | export * from './itemAttach'; 6 | export * from './itemDetach'; 7 | export * from './itemDrop'; 8 | export * from './itemEquip'; 9 | export * from './itemPickup'; 10 | export * from './itemUnequip'; 11 | export * from './itemUse'; 12 | export * from './matchDefinition'; 13 | export * from './matchEnd'; 14 | export * from './matchStart'; 15 | export * from './playerAttack'; 16 | export * from './playerCreate'; 17 | export * from './playerKill'; 18 | export * from './playerLogin'; 19 | export * from './playerLogout'; 20 | export * from './playerMakeGroggy'; 21 | export * from './playerPosition'; 22 | export * from './playerRevive'; 23 | export * from './playerTakeDamage'; 24 | export * from './swimEnd'; 25 | export * from './swimStart'; 26 | export * from './telemetryEvent'; 27 | export * from './vehicleDestroy'; 28 | export * from './vehicleLeave'; 29 | export * from './vehicleRide'; 30 | export * from './wheelDestroy'; 31 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemAttach.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemAttach } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemAttach extends TelemetryEvent { 10 | private _character: Character; 11 | private _parentItem: Item; 12 | private _childItem: Item; 13 | 14 | constructor(event: ILogItemAttach) { 15 | super(event); 16 | this._character = new Character(event.character); 17 | this._parentItem = new Item(event.parentItem); 18 | this._childItem = new Item(event.childItem); 19 | } 20 | 21 | get character(): Character { 22 | return this._character; 23 | } 24 | 25 | get parentItem(): Item { 26 | return this._parentItem; 27 | } 28 | 29 | get childItem(): Item { 30 | return this._childItem; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemDetach.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemDetach } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemDetach extends TelemetryEvent { 10 | private _character: Character; 11 | private _parentItem: Item; 12 | private _childItem: Item; 13 | 14 | constructor(event: ILogItemDetach) { 15 | super(event); 16 | this._character = new Character(event.character); 17 | this._parentItem = new Item(event.parentItem); 18 | this._childItem = new Item(event.childItem); 19 | } 20 | 21 | get character(): Character { 22 | return this._character; 23 | } 24 | 25 | get parentItem(): Item { 26 | return this._parentItem; 27 | } 28 | 29 | get childItem(): Item { 30 | return this._childItem; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemDrop.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemDrop } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemDrop extends TelemetryEvent { 10 | private _character: Character; 11 | private _item: Item; 12 | 13 | constructor(event: ILogItemDrop) { 14 | super(event); 15 | this._character = new Character(event.character); 16 | this._item = new Item(event.item); 17 | } 18 | 19 | get character(): Character { 20 | return this._character; 21 | } 22 | 23 | get item(): Item { 24 | return this._item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemEquip.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemEquip } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemEquip extends TelemetryEvent { 10 | private _character: Character; 11 | private _item: Item; 12 | 13 | constructor(event: ILogItemEquip) { 14 | super(event); 15 | this._character = new Character(event.character); 16 | this._item = new Item(event.item); 17 | } 18 | 19 | get character(): Character { 20 | return this._character; 21 | } 22 | 23 | get item(): Item { 24 | return this._item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemPickup.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemPickup } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemPickup extends TelemetryEvent { 10 | private _character: Character; 11 | private _item: Item; 12 | 13 | constructor(event: ILogItemPickup) { 14 | super(event); 15 | this._character = new Character(event.character); 16 | this._item = new Item(event.item); 17 | } 18 | 19 | get character(): Character { 20 | return this._character; 21 | } 22 | 23 | get item(): Item { 24 | return this._item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemUnequip.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemUnequip } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemUnequip extends TelemetryEvent { 10 | private _character: Character; 11 | private _item: Item; 12 | 13 | constructor(event: ILogItemUnequip) { 14 | super(event); 15 | this._character = new Character(event.character); 16 | this._item = new Item(event.item); 17 | } 18 | 19 | get character(): Character { 20 | return this._character; 21 | } 22 | 23 | get item(): Item { 24 | return this._item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/itemUse.ts: -------------------------------------------------------------------------------- 1 | import { ILogItemUse } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class ItemUse extends TelemetryEvent { 10 | private _character: Character; 11 | private _item: Item; 12 | 13 | constructor(event: ILogItemUse) { 14 | super(event); 15 | this._character = new Character(event.character); 16 | this._item = new Item(event.item); 17 | } 18 | 19 | get character(): Character { 20 | return this._character; 21 | } 22 | 23 | get item(): Item { 24 | return this._item; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/matchDefinition.ts: -------------------------------------------------------------------------------- 1 | import { ILogMatchDefinition, SeasonState } from '../../..'; 2 | 3 | import { TelemetryEvent } from './telemetryEvent'; 4 | 5 | 6 | export class MatchDefinition extends TelemetryEvent { 7 | private _matchId: string; 8 | private _pingQuality: string; 9 | private _seasonState: SeasonState; 10 | 11 | constructor(event: ILogMatchDefinition) { 12 | super(event); 13 | this._matchId = event.MatchId; 14 | this._pingQuality = event.PingQuality; 15 | this._seasonState = event.SeasonState as SeasonState; 16 | } 17 | 18 | get matchId(): string { 19 | return this._matchId; 20 | } 21 | 22 | get pingQuality(): string { 23 | return this._pingQuality; 24 | } 25 | 26 | get seasonState(): SeasonState { 27 | return this._seasonState; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/matchEnd.ts: -------------------------------------------------------------------------------- 1 | import { ILogMatchEnd } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class MatchEnd extends TelemetryEvent { 9 | private _characters: Character[]; 10 | 11 | constructor(event: ILogMatchEnd) { 12 | super(event); 13 | this._characters = event.characters.map(e => new Character(e)); 14 | } 15 | 16 | get characters(): Character[] { 17 | return this._characters; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/matchStart.ts: -------------------------------------------------------------------------------- 1 | import { ILogMatchStart } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class MatchStart extends TelemetryEvent { 9 | private _mapName: string; 10 | private _weatherId: string; 11 | private _characters: Character[]; 12 | private _cameraViewBehaviour: string; 13 | private _teamSize: number; 14 | private _isCustomGame: boolean; 15 | private _isEventMode: boolean; 16 | private _blueZoneCustomOptions: string; 17 | 18 | constructor(event: ILogMatchStart) { 19 | super(event); 20 | this._mapName = event.mapName; 21 | this._weatherId = event.weatherId; 22 | this._characters = event.characters.map(e => new Character(e)); 23 | this._cameraViewBehaviour = event.cameraViewBehaviour; 24 | this._teamSize = event.teamSize; 25 | this._isCustomGame = event.isCustomGame; 26 | this._isEventMode = event.isEventMode; 27 | this._blueZoneCustomOptions = event.blueZoneCustomOptions; 28 | } 29 | 30 | get mapName(): string { 31 | return this._mapName; 32 | } 33 | 34 | get weatherId(): string { 35 | return this._weatherId; 36 | } 37 | 38 | get characters(): Character[] { 39 | return this._characters; 40 | } 41 | 42 | get cameraViewBehaviour(): string { 43 | return this._cameraViewBehaviour; 44 | } 45 | 46 | get teamSize(): number { 47 | return this._teamSize; 48 | } 49 | 50 | get isCustomGame(): boolean { 51 | return this._isCustomGame; 52 | } 53 | 54 | get isEventMode(): boolean { 55 | return this._isEventMode; 56 | } 57 | 58 | get blueZoneCustomOptions(): string { 59 | return this._blueZoneCustomOptions; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerAttack.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerAttack } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Item } from '../objects/item'; 5 | import { Vehicle } from '../objects/vehicle'; 6 | 7 | import { TelemetryEvent } from './telemetryEvent'; 8 | 9 | 10 | export class PlayerAttack extends TelemetryEvent { 11 | private _attackId: number; 12 | private _attacker: Character; 13 | private _attackType: string; 14 | private _fireWeaponStackCount: number; 15 | private _weapon: Item; 16 | private _vehicle?: Vehicle; 17 | 18 | constructor(event: ILogPlayerAttack) { 19 | super(event); 20 | this._attackId = event.attackId; 21 | this._attacker = new Character(event.attacker); 22 | this._attackType = event.attackType; 23 | this._fireWeaponStackCount = event.fireWeaponStackCount; 24 | this._weapon = new Item(event.weapon); 25 | if (event.vehicle) { 26 | this._vehicle = new Vehicle(event.vehicle); 27 | } 28 | } 29 | 30 | get attackId(): number { 31 | return this._attackId; 32 | } 33 | 34 | get attacker(): Character { 35 | return this._attacker; 36 | } 37 | 38 | get attackType(): string { 39 | return this._attackType; 40 | } 41 | 42 | get fireWeaponStackCount(): number { 43 | return this._fireWeaponStackCount; 44 | } 45 | 46 | get weapon(): Item { 47 | return this._weapon; 48 | } 49 | 50 | get vehicle(): Vehicle | undefined { 51 | return this._vehicle; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerCreate.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerCreate } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class PlayerCreate extends TelemetryEvent { 9 | private _character: Character; 10 | 11 | constructor(event: ILogPlayerCreate) { 12 | super(event); 13 | this._character = new Character(event.character); 14 | } 15 | 16 | get character(): Character { 17 | return this._character; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerKill.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerKill } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class PlayerKill extends TelemetryEvent { 9 | private _attackId: number; 10 | private _killer: Character; 11 | private _victim: Character; 12 | private _damageReason: string; 13 | private _damageTypeCategory: string; 14 | private _damageCauserName: string; 15 | private _distance: number; 16 | 17 | constructor(event: ILogPlayerKill) { 18 | super(event); 19 | this._attackId = event.attackId; 20 | this._killer = new Character(event.killer); 21 | this._victim = new Character(event.victim); 22 | this._damageReason = event.damageReason; 23 | this._damageTypeCategory = event.damageTypeCategory; 24 | this._damageCauserName = event.damageCauserName; 25 | this._distance = event.distance; 26 | } 27 | 28 | get attackId(): number { 29 | return this._attackId; 30 | } 31 | 32 | get killer(): Character { 33 | return this._killer; 34 | } 35 | 36 | get victim(): Character { 37 | return this._victim; 38 | } 39 | 40 | get damageReason(): string { 41 | return this._damageReason; 42 | } 43 | 44 | get damageTypeCategory(): string { 45 | return this._damageTypeCategory; 46 | } 47 | 48 | get damageCauserName(): string { 49 | return this._damageCauserName; 50 | } 51 | 52 | get distance(): number { 53 | return this._distance; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerLogin.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerLogin } from '../../..'; 2 | 3 | import { TelemetryEvent } from './telemetryEvent'; 4 | 5 | 6 | export class PlayerLogin extends TelemetryEvent { 7 | private _accountId: string; 8 | 9 | constructor(event: ILogPlayerLogin) { 10 | super(event); 11 | this._accountId = event.accountId; 12 | } 13 | 14 | get accountId(): string { 15 | return this._accountId; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerLogout.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerLogout } from '../../..'; 2 | 3 | import { TelemetryEvent } from './telemetryEvent'; 4 | 5 | 6 | export class PlayerLogout extends TelemetryEvent { 7 | private _accountId: string; 8 | 9 | constructor(event: ILogPlayerLogout) { 10 | super(event); 11 | this._accountId = event.accountId; 12 | } 13 | 14 | get accountId(): string { 15 | return this._accountId; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerMakeGroggy.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerMakeGroggy } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class PlayerMakeGroggy extends TelemetryEvent { 9 | private _attackId: number; 10 | private _attacker: Character; 11 | private _victim: Character; 12 | private _damageReason: string; 13 | private _damageTypeCategory: string; 14 | private _damageCauserName: string; 15 | private _distance: number; 16 | private _isAttackerInVehicle: boolean; 17 | private _dBNOId: number; 18 | 19 | constructor(event: ILogPlayerMakeGroggy) { 20 | super(event); 21 | this._attackId = event.attackId; 22 | this._attacker = new Character(event.attacker); 23 | this._victim = new Character(event.victim); 24 | this._damageReason = event.damageReason; 25 | this._damageTypeCategory = event.damageTypeCategory; 26 | this._damageCauserName = event.damageCauserName; 27 | this._distance = event.distance; 28 | this._isAttackerInVehicle = event.isAttackerInVehicle; 29 | this._dBNOId = event.dBNOId; 30 | } 31 | 32 | get attackId(): number { 33 | return this._attackId; 34 | } 35 | 36 | get attacker(): Character { 37 | return this._attacker; 38 | } 39 | 40 | get victim(): Character { 41 | return this._victim; 42 | } 43 | 44 | get damageReason(): string { 45 | return this._damageReason; 46 | } 47 | 48 | get damageTypeCategory(): string { 49 | return this._damageTypeCategory; 50 | } 51 | 52 | get damageCauserName(): string { 53 | return this._damageCauserName; 54 | } 55 | 56 | get distance(): number { 57 | return this._distance; 58 | } 59 | 60 | get isAttackerInVehicle(): boolean { 61 | return this._isAttackerInVehicle; 62 | } 63 | 64 | get dBNOId(): number { 65 | return this._dBNOId; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerPosition.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerPosition } from '../../..'; 2 | import { Vehicle } from '../objects'; 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class PlayerPosition extends TelemetryEvent { 9 | private _character: Character; 10 | private _elapsedTime: number; 11 | private _numAlivePlayers: number; 12 | private _vehicle?: Vehicle; 13 | 14 | constructor(event: ILogPlayerPosition) { 15 | super(event); 16 | this._character = new Character(event.character); 17 | this._elapsedTime = event.elapsedTime; 18 | this._numAlivePlayers = event.numAlivePlayers; 19 | if (event.vehicle) { 20 | this._vehicle = new Vehicle(event.vehicle); 21 | } 22 | } 23 | 24 | get character(): Character { 25 | return this._character; 26 | } 27 | 28 | get elapsedTime(): number { 29 | return this._elapsedTime; 30 | } 31 | 32 | get numAlivePlayers(): number { 33 | return this._numAlivePlayers; 34 | } 35 | 36 | get vehicle(): Vehicle | undefined { 37 | return this._vehicle; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerRevive.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerRevive } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class PlayerRevive extends TelemetryEvent { 9 | private _reviver: Character; 10 | private _victim: Character; 11 | 12 | constructor(event: ILogPlayerRevive) { 13 | super(event); 14 | this._reviver = new Character(event.reviver); 15 | this._victim = new Character(event.victim); 16 | } 17 | 18 | get reviver(): Character { 19 | return this._reviver; 20 | } 21 | 22 | get victim(): Character { 23 | return this._victim; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/playerTakeDamage.ts: -------------------------------------------------------------------------------- 1 | import { ILogPlayerTakeDamage } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class PlayerTakeDamage extends TelemetryEvent { 9 | private _attackId: number; 10 | private _attacker?: Character; 11 | private _victim: Character; 12 | private _damageTypeCategory: string; 13 | private _damageCauserName: string; 14 | private _damageReason: string; 15 | private _damage: number; 16 | 17 | constructor(event: ILogPlayerTakeDamage) { 18 | super(event); 19 | this._attackId = event.attackId; 20 | this._victim = new Character(event.victim); 21 | this._damageTypeCategory = event.damageTypeCategory; 22 | this._damageCauserName = event.damageCauserName; 23 | this._damageReason = event.damageReason; 24 | this._damage = event.damage; 25 | if (event.attacker) { 26 | this._attacker = new Character(event.attacker); 27 | } 28 | } 29 | 30 | get attackId(): number { 31 | return this._attackId; 32 | } 33 | 34 | get attacker(): Character | undefined { 35 | return this._attacker; 36 | } 37 | 38 | get victim(): Character { 39 | return this._victim; 40 | } 41 | 42 | get damageTypeCategory(): string { 43 | return this._damageTypeCategory; 44 | } 45 | 46 | get damageCauserName(): string { 47 | return this._damageCauserName; 48 | } 49 | 50 | get damageReason(): string { 51 | return this._damageReason; 52 | } 53 | 54 | get damage(): number { 55 | return this._damage; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/swimEnd.ts: -------------------------------------------------------------------------------- 1 | import { ILogSwimEnd } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class SwimEnd extends TelemetryEvent { 9 | private _character: Character; 10 | private _swimDistance: number; 11 | 12 | constructor(event: ILogSwimEnd) { 13 | super(event); 14 | this._character = new Character(event.character); 15 | this._swimDistance = event.swimDistance; 16 | } 17 | 18 | get character(): Character { 19 | return this._character; 20 | } 21 | 22 | get swimDistance(): number { 23 | return this._swimDistance; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/swimStart.ts: -------------------------------------------------------------------------------- 1 | import { ILogSwimStart } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | 5 | import { TelemetryEvent } from './telemetryEvent'; 6 | 7 | 8 | export class SwimStart extends TelemetryEvent { 9 | private _character: Character; 10 | 11 | constructor(event: ILogSwimStart) { 12 | super(event); 13 | this._character = new Character(event.character); 14 | } 15 | 16 | get character(): Character { 17 | return this._character; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/telemetryEvent.ts: -------------------------------------------------------------------------------- 1 | import { IBaseTelemetryEvent } from '../../..'; 2 | 3 | 4 | export abstract class TelemetryEvent { 5 | private _D: Date; 6 | 7 | protected constructor(event: IBaseTelemetryEvent) { 8 | this._D = new Date(event._D); 9 | } 10 | 11 | get dateTime(): Date { 12 | return this._D; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/vehicleDestroy.ts: -------------------------------------------------------------------------------- 1 | import { ILogVehicleDestroy } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Vehicle } from '../objects/vehicle'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class VehicleDestroy extends TelemetryEvent { 10 | private _attackId: number; 11 | private _attacker: Character; 12 | private _vehicle: Vehicle; 13 | private _damageTypeCategory: string; 14 | private _damageCauserName: string; 15 | private _distance: number; 16 | 17 | constructor(event: ILogVehicleDestroy) { 18 | super(event); 19 | this._attackId = event.attackId; 20 | this._attacker = new Character(event.attacker); 21 | this._vehicle = new Vehicle(event.vehicle); 22 | this._damageTypeCategory = event.damageTypeCategory; 23 | this._damageCauserName = event.damageCauserName; 24 | this._distance = event.distance; 25 | } 26 | 27 | get attackId(): number { 28 | return this._attackId; 29 | } 30 | 31 | get attacker(): Character { 32 | return this._attacker; 33 | } 34 | 35 | get vehicle(): Vehicle { 36 | return this._vehicle; 37 | } 38 | 39 | get damageTypeCategory(): string { 40 | return this._damageTypeCategory; 41 | } 42 | 43 | get damageCauserName(): string { 44 | return this._damageCauserName; 45 | } 46 | 47 | get distance(): number { 48 | return this._distance; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/vehicleLeave.ts: -------------------------------------------------------------------------------- 1 | import { ILogVehicleLeave } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Vehicle } from '../objects/vehicle'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class VehicleLeave extends TelemetryEvent { 10 | private _character: Character; 11 | private _vehicle: Vehicle; 12 | private _rideDistance: number; 13 | private _seatIndex: number; 14 | 15 | constructor(event: ILogVehicleLeave) { 16 | super(event); 17 | this._character = new Character(event.character); 18 | this._vehicle = new Vehicle(event.vehicle); 19 | this._rideDistance = event.rideDistance; 20 | this._seatIndex = event.seatIndex; 21 | } 22 | 23 | get character(): Character { 24 | return this._character; 25 | } 26 | 27 | get vehicle(): Vehicle { 28 | return this._vehicle; 29 | } 30 | 31 | get rideDistance(): number { 32 | return this._rideDistance; 33 | } 34 | 35 | get seatIndex(): number { 36 | return this._seatIndex; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/vehicleRide.ts: -------------------------------------------------------------------------------- 1 | import { ILogVehicleRide } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Vehicle } from '../objects/vehicle'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class VehicleRide extends TelemetryEvent { 10 | private _character: Character; 11 | private _vehicle: Vehicle; 12 | private _seatIndex: number; 13 | 14 | constructor(event: ILogVehicleRide) { 15 | super(event); 16 | this._character = new Character(event.character); 17 | this._vehicle = new Vehicle(event.vehicle); 18 | this._seatIndex = event.seatIndex; 19 | } 20 | 21 | get character(): Character { 22 | return this._character; 23 | } 24 | 25 | get vehicle(): Vehicle { 26 | return this._vehicle; 27 | } 28 | 29 | get seatIndex(): number { 30 | return this._seatIndex; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/entities/telemetry/events/wheelDestroy.ts: -------------------------------------------------------------------------------- 1 | import { ILogWheelDestroy } from '../../..'; 2 | 3 | import { Character } from '../objects/character'; 4 | import { Vehicle } from '../objects/vehicle'; 5 | 6 | import { TelemetryEvent } from './telemetryEvent'; 7 | 8 | 9 | export class WheelDestroy extends TelemetryEvent { 10 | private _attackId: number; 11 | private _attacker: Character; 12 | private _vehicle: Vehicle; 13 | private _damageTypeCategory: string; 14 | private _damageCauserName: string; 15 | 16 | constructor(event: ILogWheelDestroy) { 17 | super(event); 18 | this._attackId = event.attackId; 19 | this._attacker = new Character(event.attacker); 20 | this._vehicle = new Vehicle(event.vehicle); 21 | this._damageTypeCategory = event.damageTypeCategory; 22 | this._damageCauserName = event.damageCauserName; 23 | } 24 | 25 | get attackId(): number { 26 | return this._attackId; 27 | } 28 | 29 | get attacker(): Character { 30 | return this._attacker; 31 | } 32 | 33 | get vehicle(): Vehicle { 34 | return this._vehicle; 35 | } 36 | 37 | get damageTypeCategory(): string { 38 | return this._damageTypeCategory; 39 | } 40 | 41 | get damageCauserName(): string { 42 | return this._damageCauserName; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/character.ts: -------------------------------------------------------------------------------- 1 | import { ICharacter } from '../../..'; 2 | 3 | import { Location } from './location'; 4 | 5 | 6 | export class Character { 7 | private _name: string; 8 | private _teamId: number; 9 | private _health: number; 10 | private _location: Location; 11 | private _ranking: number; 12 | private _accountId: string; 13 | 14 | constructor(character: ICharacter) { 15 | this._name = character.name; 16 | this._teamId = character.teamId; 17 | this._health = character.health; 18 | this._location = new Location(character.location); 19 | this._ranking = character.ranking; 20 | this._accountId = character.accountId; 21 | } 22 | 23 | get name(): string { 24 | return this._name; 25 | } 26 | 27 | get teamId(): number { 28 | return this._teamId; 29 | } 30 | 31 | get health(): number { 32 | return this._health; 33 | } 34 | 35 | get location(): Location { 36 | return this._location; 37 | } 38 | 39 | get ranking(): number { 40 | return this._ranking; 41 | } 42 | 43 | get accountId(): string { 44 | return this._accountId; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/gameState.ts: -------------------------------------------------------------------------------- 1 | import { IGameState } from '../../..'; 2 | 3 | import { Location } from './location'; 4 | 5 | 6 | export class GameState { 7 | private _elapsedTime: number; 8 | private _numAliveTeams: number; 9 | private _numJoinPlayers: number; 10 | private _numAlivePlayers: number; 11 | private _safetyZonePosition: Location; 12 | private _safetyZoneRadius: number; 13 | private _poisonGasWarningPosition: Location; 14 | private _poisonGasWarningRadius: number; 15 | private _redZonePosition: Location; 16 | private _redZoneRadius: number; 17 | 18 | constructor(gs: IGameState) { 19 | this._elapsedTime = gs.elapsedTime; 20 | this._numAliveTeams = gs.numAliveTeams; 21 | this._numJoinPlayers = gs.numJoinPlayers; 22 | this._numAlivePlayers = gs.numAlivePlayers; 23 | this._safetyZonePosition = new Location(gs.safetyZonePosition); 24 | this._safetyZoneRadius = gs.safetyZoneRadius; 25 | this._poisonGasWarningPosition = new Location(gs.poisonGasWarningPosition); 26 | this._poisonGasWarningRadius = gs.poisonGasWarningRadius; 27 | this._redZonePosition = new Location(gs.redZonePosition); 28 | this._redZoneRadius = gs.redZoneRadius; 29 | } 30 | 31 | get elapsedTime(): number { 32 | return this._elapsedTime; 33 | } 34 | 35 | get numAliveTeams(): number { 36 | return this._numAliveTeams; 37 | } 38 | 39 | get numJoinPlayers(): number { 40 | return this._numJoinPlayers; 41 | } 42 | 43 | get numAlivePlayers(): number { 44 | return this._numAlivePlayers; 45 | } 46 | 47 | get safetyZonePosition(): Location { 48 | return this._safetyZonePosition; 49 | } 50 | 51 | get safetyZoneRadius(): number { 52 | return this._safetyZoneRadius; 53 | } 54 | 55 | get poisonGasWarningPosition(): Location { 56 | return this._poisonGasWarningPosition; 57 | } 58 | 59 | get poisonGasWarningRadius(): number { 60 | return this._poisonGasWarningRadius; 61 | } 62 | 63 | get redZonePosition(): Location { 64 | return this._redZonePosition; 65 | } 66 | 67 | get redZoneRadius(): number { 68 | return this._redZoneRadius; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/index.ts: -------------------------------------------------------------------------------- 1 | export * from './character'; 2 | export * from './gameState'; 3 | export * from './item'; 4 | export * from './itemPackage'; 5 | export * from './location'; 6 | export * from './vehicle'; 7 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/item.ts: -------------------------------------------------------------------------------- 1 | import { IItem } from '../../..'; 2 | 3 | 4 | export class Item { 5 | private _itemId: string; 6 | private _stackCount: number; 7 | private _category: string; 8 | private _subCategory: string; 9 | private _attachedItems: string[]; // TODO: use list of enum 10 | 11 | constructor(item: IItem) { 12 | this._itemId = item.itemId; 13 | this._stackCount = item.stackCount; 14 | this._category = item.category; 15 | this._subCategory = item.subCategory; 16 | this._attachedItems = item.attachedItems; 17 | } 18 | 19 | get itemId() { 20 | return this._itemId; 21 | } 22 | 23 | get stackCount() { 24 | return this._stackCount; 25 | } 26 | 27 | get category() { 28 | return this._category; 29 | } 30 | 31 | get subCategory() { 32 | return this._subCategory; 33 | } 34 | 35 | get attachedItems() { 36 | return this._attachedItems; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/itemPackage.ts: -------------------------------------------------------------------------------- 1 | import { IItemPackage } from '../../..'; 2 | 3 | import { Item } from './item'; 4 | import { Location } from './location'; 5 | 6 | 7 | export class ItemPackage { 8 | private _itemPackageId: string; 9 | private _location: Location; 10 | private _items: Item[] = []; 11 | 12 | constructor(itemPackage: IItemPackage) { 13 | this._itemPackageId = itemPackage.itemPackageId; 14 | this._location = new Location(itemPackage.location); 15 | this._items = itemPackage.items.map(item => new Item(item)); 16 | } 17 | 18 | get itemPackageId() { 19 | return this._itemPackageId; 20 | } 21 | 22 | get location() { 23 | return this._location; 24 | } 25 | 26 | get items() { 27 | return this._items; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/location.ts: -------------------------------------------------------------------------------- 1 | import { ILocation } from '../../..'; 2 | 3 | 4 | export class Location { 5 | private _x: number; 6 | private _y: number; 7 | private _z: number; 8 | 9 | constructor(loc: ILocation) { 10 | this._x = loc.x; 11 | this._y = loc.y; 12 | this._z = loc.z; 13 | } 14 | 15 | get x() { 16 | return this._x; 17 | } 18 | 19 | get y() { 20 | return this._y; 21 | } 22 | 23 | get z() { 24 | return this._z; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entities/telemetry/objects/vehicle.ts: -------------------------------------------------------------------------------- 1 | import { IVehicle } from '../../..'; 2 | 3 | 4 | export class Vehicle { 5 | private _vehicleType: string; 6 | private _vehicleId: string; 7 | private _healthPercent: number; 8 | private _feulPercent: number; // Typo in api 9 | 10 | constructor(vehicle: IVehicle) { 11 | this._vehicleType = vehicle.vehicleType; 12 | this._vehicleId = vehicle.vehicleId; 13 | this._healthPercent = vehicle.healthPercent; 14 | this._feulPercent = vehicle.feulPercent; 15 | } 16 | 17 | get vehicleType(): string { 18 | return this._vehicleType; 19 | } 20 | 21 | get vehicleId(): string { 22 | return this._vehicleId; 23 | } 24 | 25 | get healthPercent(): number { 26 | return this._healthPercent; 27 | } 28 | 29 | get feulPercent(): number { 30 | return this._feulPercent; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/entities/telemetry/telemetry.ts: -------------------------------------------------------------------------------- 1 | import { ITelemetry, TelemetryEventType } from '../..'; 2 | 3 | import { 4 | ArmorDestroy, 5 | CarePackageLand, 6 | CarePackageSpawn, 7 | GameStatePeriodic, 8 | ItemAttach, 9 | ItemDetach, 10 | ItemDrop, 11 | ItemEquip, 12 | ItemPickup, 13 | ItemUnequip, 14 | ItemUse, 15 | MatchDefinition, 16 | MatchEnd, 17 | MatchStart, 18 | PlayerAttack, 19 | PlayerCreate, 20 | PlayerKill, 21 | PlayerLogin, 22 | PlayerLogout, 23 | PlayerMakeGroggy, 24 | PlayerPosition, 25 | PlayerRevive, 26 | PlayerTakeDamage, 27 | SwimEnd, 28 | SwimStart, 29 | VehicleDestroy, 30 | VehicleLeave, 31 | VehicleRide, 32 | WheelDestroy, 33 | } from './events'; 34 | 35 | 36 | export class Telemetry { 37 | private _armorDestroyEvents: ArmorDestroy[] = []; 38 | private _carePackageLandEvents: CarePackageLand[] = []; 39 | private _carePackageSpawnEvents: CarePackageSpawn[] = []; 40 | private _gameStatePeriodicEvents: GameStatePeriodic[] = []; 41 | private _itemAttachEvents: ItemAttach[] = []; 42 | private _itemDetachEvents: ItemDetach[] = []; 43 | private _itemDropEvents: ItemDrop[] = []; 44 | private _itemEquipEvents: ItemEquip[] = []; 45 | private _itemPickupEvents: ItemPickup[] = []; 46 | private _itemUnequipEvents: ItemUnequip[] = []; 47 | private _itemUseEvents: ItemUse[] = []; 48 | private _matchDefinitionEvents: MatchDefinition[] = []; 49 | private _matchEndEvents: MatchEnd[] = []; 50 | private _matchStartEvents: MatchStart[] = []; 51 | private _playerAttackEvents: PlayerAttack[] = []; 52 | private _playerCreateEvents: PlayerCreate[] = []; 53 | private _playerKillEvents: PlayerKill[] = []; 54 | private _playerLoginEvents: PlayerLogin[] = []; 55 | private _playerLogoutEvents: PlayerLogout[] = []; 56 | private _playerMakeGroggyEvents: PlayerMakeGroggy[] = []; 57 | private _playerPositionEvents: PlayerPosition[] = []; 58 | private _playerReviveEvents: PlayerRevive[] = []; 59 | private _playerTakeDamageEvents: PlayerTakeDamage[] = []; 60 | private _swimEndEvents: SwimEnd[] = []; 61 | private _swimStartEvents: SwimStart[] = []; 62 | private _vehicleDestroyEvents: VehicleDestroy[] = []; 63 | private _vehicleLeaveEvents: VehicleLeave[] = []; 64 | private _vehicleRideEvents: VehicleRide[] = []; 65 | private _wheelDestroyEvents: WheelDestroy[] = []; 66 | 67 | constructor(telemetryData: ITelemetry) { 68 | telemetryData.forEach(elem => { 69 | switch (elem._T) { 70 | // switch on discriminant = elem type automatically "cast" as correct type 71 | case TelemetryEventType.LOGARMORDESTROY: 72 | this._armorDestroyEvents.push(new ArmorDestroy(elem)); 73 | break; 74 | case TelemetryEventType.LOGCAREPACKAGELAND: 75 | this._carePackageLandEvents.push(new CarePackageLand(elem)); 76 | break; 77 | case TelemetryEventType.LOGCAREPACKAGESPAWN: 78 | this._carePackageSpawnEvents.push(new CarePackageSpawn(elem)); 79 | break; 80 | case TelemetryEventType.LOGGAMESTATEPERIODIC: 81 | this._gameStatePeriodicEvents.push(new GameStatePeriodic(elem)); 82 | break; 83 | case TelemetryEventType.LOGITEMATTACH: 84 | this._itemAttachEvents.push(new ItemAttach(elem)); 85 | break; 86 | case TelemetryEventType.LOGITEMDETACH: 87 | this._itemDetachEvents.push(new ItemDetach(elem)); 88 | break; 89 | case TelemetryEventType.LOGITEMDROP: 90 | this._itemDropEvents.push(new ItemDrop(elem)); 91 | break; 92 | case TelemetryEventType.LOGITEMEQUIP: 93 | this._itemEquipEvents.push(new ItemEquip(elem)); 94 | break; 95 | case TelemetryEventType.LOGITEMPICKUP: 96 | this._itemPickupEvents.push(new ItemPickup(elem)); 97 | break; 98 | case TelemetryEventType.LOGITEMUNEQUIP: 99 | this._itemUnequipEvents.push(new ItemUnequip(elem)); 100 | break; 101 | case TelemetryEventType.LOGITEMUSE: 102 | this._itemUseEvents.push(new ItemUse(elem)); 103 | break; 104 | case TelemetryEventType.LOGMATCHDEFINITION: 105 | this._matchDefinitionEvents.push(new MatchDefinition(elem)); 106 | break; 107 | case TelemetryEventType.LOGMATCHEND: 108 | this._matchEndEvents.push(new MatchEnd(elem)); 109 | break; 110 | case TelemetryEventType.LOGMATCHSTART: 111 | this._matchStartEvents.push(new MatchStart(elem)); 112 | break; 113 | case TelemetryEventType.LOGPLAYERATTACK: 114 | this._playerAttackEvents.push(new PlayerAttack(elem)); 115 | break; 116 | case TelemetryEventType.LOGPLAYERCREATE: 117 | this._playerCreateEvents.push(new PlayerCreate(elem)); 118 | break; 119 | case TelemetryEventType.LOGPLAYERKILL: 120 | this._playerKillEvents.push(new PlayerKill(elem)); 121 | break; 122 | case TelemetryEventType.LOGPLAYERLOGIN: 123 | this._playerLoginEvents.push(new PlayerLogin(elem)); 124 | break; 125 | case TelemetryEventType.LOGPLAYERLOGOUT: 126 | this._playerLogoutEvents.push(new PlayerLogout(elem)); 127 | break; 128 | case TelemetryEventType.LOGPLAYERMAKEGROGGY: 129 | this._playerMakeGroggyEvents.push(new PlayerMakeGroggy(elem)); 130 | break; 131 | case TelemetryEventType.LOGPLAYERPOSITION: 132 | this._playerPositionEvents.push(new PlayerPosition(elem)); 133 | break; 134 | case TelemetryEventType.LOGPLAYERREVIVE: 135 | this._playerReviveEvents.push(new PlayerRevive(elem)); 136 | break; 137 | case TelemetryEventType.LOGPLAYERTAKEDAMAGE: 138 | this._playerTakeDamageEvents.push(new PlayerTakeDamage(elem)); 139 | break; 140 | case TelemetryEventType.LOGSWIMSTART: 141 | this._swimStartEvents.push(new SwimStart(elem)); 142 | break; 143 | case TelemetryEventType.LOGSWIMEND: 144 | this._swimEndEvents.push(new SwimEnd(elem)); 145 | break; 146 | case TelemetryEventType.LOGVEHICLEDESTROY: 147 | this._vehicleDestroyEvents.push(new VehicleDestroy(elem)); 148 | break; 149 | case TelemetryEventType.LOGVEHICLELEAVE: 150 | this._vehicleLeaveEvents.push(new VehicleLeave(elem)); 151 | break; 152 | case TelemetryEventType.LOGVEHICLERIDE: 153 | this._vehicleRideEvents.push(new VehicleRide(elem)); 154 | break; 155 | case TelemetryEventType.LOGWHEELDESTROY: 156 | this._wheelDestroyEvents.push(new WheelDestroy(elem)); 157 | break; 158 | } 159 | }); 160 | } 161 | 162 | //#region GETTERS 163 | 164 | get armorDestroyEvents() { 165 | return this._armorDestroyEvents; 166 | } 167 | 168 | get carePackageLandEvents() { 169 | return this._carePackageLandEvents; 170 | } 171 | 172 | get carePackageSpawnEvents() { 173 | return this._carePackageSpawnEvents; 174 | } 175 | 176 | get gameStatePeriodicEvents() { 177 | return this._gameStatePeriodicEvents; 178 | } 179 | 180 | get itemAttachEvents() { 181 | return this._itemAttachEvents; 182 | } 183 | 184 | get itemDetachEvents() { 185 | return this._itemDetachEvents; 186 | } 187 | 188 | get itemDropEvents() { 189 | return this._itemDropEvents; 190 | } 191 | 192 | get itemEquipEvents() { 193 | return this._itemEquipEvents; 194 | } 195 | 196 | get itemPickupEvents() { 197 | return this._itemPickupEvents; 198 | } 199 | 200 | get itemUnequipEvents() { 201 | return this._itemUnequipEvents; 202 | } 203 | 204 | get itemUseEvents() { 205 | return this._itemUseEvents; 206 | } 207 | 208 | get matchDefinitionEvents() { 209 | return this._matchDefinitionEvents; 210 | } 211 | 212 | get matchEndEvents() { 213 | return this._matchEndEvents; 214 | } 215 | 216 | get matchStartEvents() { 217 | return this._matchStartEvents; 218 | } 219 | 220 | get playerAttackEvents() { 221 | return this._playerAttackEvents; 222 | } 223 | 224 | get playerCreateEvents() { 225 | return this._playerCreateEvents; 226 | } 227 | 228 | get playerKillEvents() { 229 | return this._playerKillEvents; 230 | } 231 | 232 | get playerLoginEvents() { 233 | return this._playerLoginEvents; 234 | } 235 | 236 | get playerLogoutEvents() { 237 | return this._playerLogoutEvents; 238 | } 239 | 240 | get playerMakeGroggyEvents() { 241 | return this._playerMakeGroggyEvents; 242 | } 243 | 244 | get playerPositionEvents() { 245 | return this._playerPositionEvents; 246 | } 247 | 248 | get playerReviveEvents() { 249 | return this._playerReviveEvents; 250 | } 251 | 252 | get playerTakeDamageEvents() { 253 | return this._playerTakeDamageEvents; 254 | } 255 | 256 | get swimStartEvents() { 257 | return this._swimStartEvents; 258 | } 259 | 260 | get swimEndEvents() { 261 | return this._swimEndEvents; 262 | } 263 | 264 | get vehicleDestroyEvents() { 265 | return this._vehicleDestroyEvents; 266 | } 267 | 268 | get vehicleLeaveEvents() { 269 | return this._vehicleLeaveEvents; 270 | } 271 | 272 | get vehicleRideEvents() { 273 | return this._vehicleRideEvents; 274 | } 275 | 276 | get wheelDestroyEvents() { 277 | return this._wheelDestroyEvents; 278 | } 279 | 280 | //#endregion 281 | 282 | } 283 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api'; 2 | export * from './entities'; 3 | export * from './interfaces'; 4 | export * from './shared'; 5 | -------------------------------------------------------------------------------- /src/interfaces/common.ts: -------------------------------------------------------------------------------- 1 | export interface ISimpleAPIObject { 2 | type: string; 3 | id: string; 4 | } 5 | 6 | export interface IAPIObject extends ISimpleAPIObject { 7 | attributes: T; 8 | relationships?: R; 9 | } 10 | -------------------------------------------------------------------------------- /src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | IAPIObject, 3 | ISimpleAPIObject, 4 | } from './common'; 5 | 6 | export { 7 | IAsset, 8 | IAssetAttributes, 9 | IMatch, 10 | IParticipant, 11 | IParticipantAttributes, 12 | IRoster, 13 | IRosterAttributes, 14 | IRosterRelationships, 15 | } from './match'; 16 | 17 | export { 18 | IGameModeStats, 19 | IPlayer, 20 | IPlayerAttributes, 21 | IPlayerList, 22 | IPlayerObject, 23 | IPlayerRelationships, 24 | IPlayerSeason, 25 | } from './player'; 26 | 27 | export { 28 | ISample, 29 | } from './sample'; 30 | 31 | export { 32 | ISeason, 33 | ISeasonList, 34 | } from './season'; 35 | 36 | export { 37 | IStatus 38 | } from './status'; 39 | 40 | export * from './telemetry'; 41 | -------------------------------------------------------------------------------- /src/interfaces/match.ts: -------------------------------------------------------------------------------- 1 | import { IAPIObject, ISimpleAPIObject } from './common'; 2 | 3 | 4 | export interface IRosterAttributes { 5 | shardId: string; 6 | stats: { 7 | rank: number; 8 | teamId: number; 9 | }; 10 | won: string; 11 | } 12 | 13 | export interface IRosterRelationships { 14 | participants: { 15 | data: ISimpleAPIObject[]; 16 | }; 17 | team: { 18 | data: null; 19 | }; 20 | } 21 | 22 | /** 23 | * Rosters track the scores of each opposing group of participants. Rosters can have one or many 24 | * participants depending on the game mode. Roster objects are only meaningful within the context 25 | * of a match and are not exposed as a standalone resource. 26 | */ 27 | export interface IRoster extends IAPIObject { } 28 | 29 | 30 | export interface IParticipantAttributes { 31 | actor: string; 32 | shardId: string; 33 | stats: { 34 | DBNOs: number; 35 | assists: number; 36 | boosts: number; 37 | damageDealt: number; 38 | deathType: string; 39 | headshotKills: number; 40 | heals: number; 41 | killPlace: number; 42 | killPoints?: number; 43 | killPointsDelta?: number; 44 | killStreaks: number; 45 | kills: number; 46 | lastKillPoints: number; 47 | lastWinPoints: number; 48 | longestKill: number; 49 | mostDamage: number; 50 | name: string; 51 | playerId: string; 52 | revives: number; 53 | rideDistance: number; 54 | roadKills: number; 55 | swimDistance: number; 56 | teamKills: number; 57 | timeSurvived: number; 58 | vehicleDestroys: number; 59 | walkDistance: number; 60 | weaponsAcquired: number; 61 | winPlace: number; 62 | winPoints?: number; 63 | winPointsDelta?: number; 64 | }; 65 | } 66 | 67 | /** 68 | * Participant objects represent each player in the context of a match. 69 | * Participant objects are only meaningful within the context of a match and are not exposed as a 70 | * standalone resource. 71 | */ 72 | export interface IParticipant extends IAPIObject { } 73 | 74 | 75 | export interface IAssetAttributes { 76 | URL: string; 77 | createdAt: string; 78 | description: string; 79 | name: string; 80 | } 81 | 82 | /** 83 | * Asset objects contain a URL string that links to a telemetry.json file, which will contain 84 | * an array of event objects that provide further insight into a match. 85 | */ 86 | export interface IAsset extends IAPIObject { } 87 | 88 | /** 89 | * Match objects contain the results of a completed match such as the game mode played, duration, 90 | * and which players participated 91 | */ 92 | export interface IMatch { 93 | data: { 94 | type: string; 95 | id: string; 96 | attributes: { 97 | createdAt: string; 98 | duration: number; 99 | gameMode: string; 100 | isCustomMatch: boolean; 101 | mapName: string; // XXX: sometimes not returned? 102 | patchVersion?: ''; // XXX: sometimes not returned? 103 | seasonState: string; 104 | shardId: string; 105 | stats: null; 106 | tags: null; 107 | titleId: string; 108 | }; 109 | relationships: { 110 | assets: { 111 | data: ISimpleAPIObject[]; 112 | }; 113 | rosters: { 114 | data: ISimpleAPIObject[]; 115 | }; 116 | rounds?: {}; 117 | spectators?: {}; 118 | }; 119 | links: { 120 | schema: string; 121 | self: string; 122 | }; 123 | }; 124 | included: (IAsset | IParticipant | IRoster)[]; 125 | links: { 126 | self: string; 127 | }; 128 | meta: {}; 129 | } 130 | -------------------------------------------------------------------------------- /src/interfaces/player.ts: -------------------------------------------------------------------------------- 1 | import { IAPIObject, ISimpleAPIObject } from './common'; 2 | 3 | 4 | export interface IPlayerAttributes { 5 | name: string; 6 | shardId: string; 7 | stats: null; 8 | createdAt: string; 9 | patchVersion: string; 10 | titleId: string; 11 | updatedAt: string; 12 | } 13 | 14 | export interface IPlayerRelationships { 15 | assets: {}; 16 | matches: { 17 | data: ISimpleAPIObject[]; 18 | }; 19 | } 20 | 21 | export interface IPlayerObject extends IAPIObject { 22 | links: { 23 | schema: string; 24 | self: string; 25 | }; 26 | } 27 | 28 | export interface IGameModeStats { 29 | assists: number; 30 | bestRankPoint: number; 31 | boosts: number; 32 | dBNOs: number; 33 | dailyKills: number; 34 | dailyWins: number; 35 | damageDealt: number; 36 | days: number; 37 | headshotKills: number; 38 | heals: number; 39 | killPoints: number; // not in docs? 40 | kills: number; 41 | longestKill: number; 42 | longestTimeSurvived: number; 43 | losses: number; 44 | maxKillStreaks: number; 45 | mostSurvivalTime: number; 46 | rankPoints: number; 47 | revives: number; 48 | rideDistance: number; 49 | roadKills: number; 50 | roundMostKills: number; 51 | roundsPlayed: number; 52 | suicides: number; 53 | swimDistance: number; 54 | teamKills: number; 55 | timeSurvived: number; 56 | top10s: number; 57 | vehicleDestroys: number; 58 | walkDistance: number; 59 | weaponsAcquired: number; // weaponAcquired in docs? 60 | weeklyKills: number; 61 | weeklyWins: number; 62 | winPoints: number; 63 | // winRatio: number; // doesn't exist? 64 | wins: number; 65 | } 66 | 67 | export interface IPlayerSeason { 68 | data: { 69 | type: 'playerSeason'; 70 | attributes: { 71 | gameModeStats: { 72 | duo: IGameModeStats; 73 | 'duo-fpp': IGameModeStats; 74 | solo: IGameModeStats; 75 | 'solo-fpp': IGameModeStats; 76 | squad: IGameModeStats; 77 | 'squad-fpp': IGameModeStats; 78 | } 79 | }; 80 | relationships: { 81 | // these are Match IDs 82 | matchesDuo: { 83 | data: {type: 'match'; id: string}[]; 84 | }; 85 | matchesDuoFPP: { 86 | data: {type: 'match'; id: string}[]; 87 | }; 88 | matchesSolo: { 89 | data: {type: 'match'; id: string}[]; 90 | }; 91 | matchesSoloFPP: { 92 | data: {type: 'match'; id: string}[]; 93 | }; 94 | matchesSquad: { 95 | data: {type: 'match'; id: string}[]; 96 | }; 97 | matchesSquadFPP: { 98 | data: {type: 'match'; id: string}[]; 99 | }; 100 | player: { 101 | data: { 102 | type: 'player'; 103 | id: string; 104 | }; 105 | }; 106 | season: { 107 | data: { 108 | type: 'season'; 109 | id: string; 110 | }; 111 | }; 112 | }; 113 | }; 114 | links: { 115 | self: string; 116 | }; 117 | meta: {}; 118 | } 119 | 120 | /** 121 | * Player objects contain aggregated lifetime information about each player. 122 | */ 123 | export interface IPlayer { 124 | data: IPlayerObject; 125 | links: { 126 | self: string; 127 | }; 128 | meta: {}; 129 | } 130 | 131 | /** 132 | * Player objects contain aggregated lifetime information about each player. 133 | */ 134 | export interface IPlayerList { 135 | data: IPlayerObject[]; 136 | links: { 137 | self: string; 138 | }; 139 | meta: {}; 140 | } 141 | -------------------------------------------------------------------------------- /src/interfaces/sample.ts: -------------------------------------------------------------------------------- 1 | import { ISimpleAPIObject } from './common'; 2 | 3 | 4 | /** 5 | * A list of sampled Match IDs 6 | */ 7 | export interface ISample { 8 | data: { 9 | type: 'sample'; 10 | id: string; 11 | attributes: { 12 | createdAt: string; 13 | shardId: string; 14 | titleId: string; 15 | }; 16 | relationships: { 17 | matches: { 18 | data: ISimpleAPIObject[]; 19 | } 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/interfaces/season.ts: -------------------------------------------------------------------------------- 1 | export interface ISeason { 2 | type: 'season'; 3 | id: string; 4 | attributes: { 5 | isCurrentSeason: boolean; 6 | isOffseason: boolean; 7 | }; 8 | } 9 | 10 | export interface ISeasonList { 11 | data: ISeason[]; 12 | links: { 13 | self: string; 14 | }; 15 | meta: {}; 16 | } 17 | -------------------------------------------------------------------------------- /src/interfaces/status.ts: -------------------------------------------------------------------------------- 1 | export interface IStatus { 2 | data: { 3 | id: string; 4 | ping: number; 5 | type: string; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /src/interfaces/telemetry.ts: -------------------------------------------------------------------------------- 1 | // objects 2 | 3 | export interface IItem { 4 | itemId: string; 5 | stackCount: number; 6 | category: string; 7 | subCategory: string; 8 | attachedItems: string[]; 9 | } 10 | 11 | /** 12 | * The range for X and Y axes is 0 - 816,000 for 8km maps. 13 | * Location values are measured in centimeters. 14 | */ 15 | export interface ILocation { 16 | x: number; 17 | y: number; 18 | z: number; 19 | } 20 | 21 | export interface IItemPackage { 22 | itemPackageId: string; 23 | location: ILocation; 24 | items: IItem[]; 25 | } 26 | 27 | export interface ICharacter { 28 | name: string; 29 | teamId: number; 30 | health: number; 31 | location: ILocation; 32 | ranking: number; 33 | accountId: string; 34 | } 35 | 36 | export interface IVehicle { 37 | vehicleType: string; 38 | vehicleId: string; 39 | healthPercent: number; 40 | feulPercent: number; // XXX: typo included! 41 | } 42 | 43 | export interface IGameState { 44 | elapsedTime: number; 45 | numAliveTeams: number; 46 | numJoinPlayers: number; 47 | numStartPlayers: number; 48 | numAlivePlayers: number; 49 | safetyZonePosition: ILocation; 50 | safetyZoneRadius: number; 51 | poisonGasWarningPosition: ILocation; 52 | poisonGasWarningRadius: number; 53 | redZonePosition: ILocation; 54 | redZoneRadius: number; 55 | } 56 | 57 | // events 58 | 59 | // XXX: ICommon exists in PC only! 60 | export interface ICommon { 61 | isGame: number; 62 | } 63 | 64 | export interface IBaseTelemetryEvent { 65 | _D: string; // date string 66 | _T: string; // discriminant of the Union type 67 | } 68 | 69 | export interface ITelemetryEvent extends IBaseTelemetryEvent { 70 | common: ICommon; 71 | } 72 | 73 | export interface ILogPlayerLogin extends ITelemetryEvent { 74 | _T: 'LogPlayerLogin'; 75 | accountId: string; 76 | } 77 | 78 | export interface ILogPlayerCreate extends ITelemetryEvent { 79 | _T: 'LogPlayerCreate'; 80 | character: ICharacter; 81 | } 82 | 83 | export interface ILogPlayerPosition extends ITelemetryEvent { 84 | _T: 'LogPlayerPosition'; 85 | character: ICharacter; 86 | elapsedTime: number; 87 | numAlivePlayers: number; 88 | vehicle: IVehicle; 89 | } 90 | 91 | export interface ILogPlayerAttack extends ITelemetryEvent { 92 | _T: 'LogPlayerAttack'; 93 | attackId: number; 94 | attacker: ICharacter; 95 | attackType: string; 96 | fireWeaponStackCount: number; 97 | weapon: IItem; 98 | vehicle?: IVehicle; 99 | } 100 | 101 | export interface ILogItemPickup extends ITelemetryEvent { 102 | _T: 'LogItemPickup'; 103 | character: ICharacter; 104 | item: IItem; 105 | } 106 | 107 | export interface ILogItemEquip extends ITelemetryEvent { 108 | _T: 'LogItemEquip'; 109 | character: ICharacter; 110 | item: IItem; 111 | } 112 | 113 | export interface ILogItemUnequip extends ITelemetryEvent { 114 | _T: 'LogItemUnequip'; 115 | character: ICharacter; 116 | item: IItem; 117 | } 118 | 119 | export interface ILogVehicleRide extends ITelemetryEvent { 120 | _T: 'LogVehicleRide'; 121 | character: ICharacter; 122 | vehicle: IVehicle; 123 | seatIndex: number; 124 | } 125 | 126 | export interface ILogMatchDefinition extends IBaseTelemetryEvent { 127 | _T: 'LogMatchDefinition'; 128 | MatchId: string; 129 | PingQuality: string; // PC only 130 | SeasonState: string; 131 | } 132 | 133 | export interface ILogMatchStart extends ITelemetryEvent { 134 | _T: 'LogMatchStart'; 135 | // some of these fields are not documented but are found in response... 136 | mapName: string; 137 | weatherId: string; 138 | characters: ICharacter[]; 139 | cameraViewBehaviour: string; 140 | teamSize: number; 141 | isCustomGame: boolean; 142 | isEventMode: boolean; 143 | blueZoneCustomOptions: string; 144 | } 145 | 146 | export interface ILogGameStatePeriodic extends ITelemetryEvent { 147 | _T: 'LogGameStatePeriodic'; 148 | gameState: IGameState; 149 | } 150 | 151 | export interface ILogVehicleLeave extends ITelemetryEvent { 152 | _T: 'LogVehicleLeave'; 153 | character: ICharacter; 154 | vehicle: IVehicle; 155 | rideDistance: number; // PC only 156 | seatIndex: number; // PC only 157 | } 158 | 159 | export interface ILogPlayerTakeDamage extends ITelemetryEvent { 160 | _T: 'LogPlayerTakeDamage'; 161 | attackId: number; 162 | attacker?: ICharacter; 163 | victim: ICharacter; 164 | damageTypeCategory: string; 165 | damageReason: string; 166 | damage: number; 167 | damageCauserName: string; 168 | } 169 | 170 | export interface ILogPlayerLogout extends ITelemetryEvent { 171 | _T: 'LogPlayerLogout'; 172 | accountId: string; 173 | } 174 | 175 | export interface ILogItemAttach extends ITelemetryEvent { 176 | _T: 'LogItemAttach'; 177 | character: ICharacter; 178 | parentItem: IItem; 179 | childItem: IItem; 180 | } 181 | 182 | export interface ILogItemDrop extends ITelemetryEvent { 183 | _T: 'LogItemDrop'; 184 | character: ICharacter; 185 | item: IItem; 186 | } 187 | 188 | export interface ILogPlayerKill extends ITelemetryEvent { 189 | _T: 'LogPlayerKill'; 190 | attackId: number; 191 | killer: ICharacter; 192 | victim: ICharacter; 193 | damageReason: string; 194 | damageTypeCategory: string; 195 | damageCauserName: string; 196 | distance: number; 197 | } 198 | 199 | export interface ILogItemDetach extends ITelemetryEvent { 200 | _T: 'LogItemDetach'; 201 | character: ICharacter; 202 | parentItem: IItem; 203 | childItem: IItem; 204 | } 205 | 206 | export interface ILogItemUse extends ITelemetryEvent { 207 | _T: 'LogItemUse'; 208 | character: ICharacter; 209 | item: IItem; 210 | } 211 | 212 | export interface ILogCarePackageSpawn extends ITelemetryEvent { 213 | _T: 'LogCarePackageSpawn'; 214 | itemPackage: IItemPackage; 215 | } 216 | 217 | export interface ILogVehicleDestroy extends ITelemetryEvent { 218 | _T: 'LogVehicleDestroy'; 219 | attackId: number; 220 | attacker: ICharacter; 221 | vehicle: IVehicle; 222 | damageTypeCategory: string; 223 | damageCauserName: string; 224 | distance: number; 225 | } 226 | 227 | export interface ILogCarePackageLand extends ITelemetryEvent { 228 | _T: 'LogCarePackageLand'; 229 | itemPackage: IItemPackage; 230 | } 231 | 232 | export interface ILogMatchEnd extends ITelemetryEvent { 233 | _T: 'LogMatchEnd'; 234 | characters: ICharacter[]; 235 | } 236 | 237 | export interface ILogSwimStart extends ITelemetryEvent { 238 | _T: 'LogSwimStart'; 239 | character: ICharacter; 240 | } 241 | 242 | export interface ILogSwimEnd extends ITelemetryEvent { 243 | _T: 'LogSwimEnd'; 244 | character: ICharacter; 245 | swimDistance: number; 246 | } 247 | 248 | export interface ILogArmorDestroy extends ITelemetryEvent { 249 | _T: 'LogArmorDestroy'; 250 | attackId: number; 251 | attacker: ICharacter; 252 | victim: ICharacter; 253 | damageTypeCategory: string; 254 | damageReason: string; 255 | damageCauserName: string; 256 | item: IItem; 257 | distance: number; 258 | } 259 | 260 | export interface ILogWheelDestroy extends ITelemetryEvent { 261 | _T: 'LogWheelDestroy'; 262 | attackId: number; 263 | attacker: ICharacter; 264 | vehicle: IVehicle; 265 | damageTypeCategory: string; 266 | damageCauserName: string; 267 | } 268 | 269 | export interface ILogPlayerMakeGroggy extends ITelemetryEvent { 270 | _T: 'LogPlayerMakeGroggy'; 271 | attackId: number; 272 | attacker: ICharacter; 273 | victim: ICharacter; 274 | damageReason: string; // undocumented? 275 | damageTypeCategory: string; 276 | damageCauserName: string; 277 | distance: number; 278 | isAttackerInVehicle: boolean; 279 | dBNOId: number; 280 | } 281 | 282 | export interface ILogPlayerRevive extends ITelemetryEvent { 283 | _T: 'LogPlayerRevive'; 284 | reviver: ICharacter; 285 | victim: ICharacter; 286 | } 287 | 288 | export type ITelemetryElement = ( 289 | ILogPlayerLogin 290 | | ILogPlayerCreate 291 | | ILogPlayerPosition 292 | | ILogPlayerAttack 293 | | ILogItemPickup 294 | | ILogItemEquip 295 | | ILogItemUnequip 296 | | ILogVehicleRide 297 | | ILogMatchDefinition 298 | | ILogMatchStart 299 | | ILogGameStatePeriodic 300 | | ILogVehicleLeave 301 | | ILogPlayerTakeDamage 302 | | ILogPlayerLogout 303 | | ILogItemAttach 304 | | ILogItemDrop 305 | | ILogPlayerKill 306 | | ILogItemDetach 307 | | ILogItemUse 308 | | ILogCarePackageSpawn 309 | | ILogVehicleDestroy 310 | | ILogCarePackageLand 311 | | ILogMatchEnd 312 | | ILogSwimStart 313 | | ILogSwimEnd 314 | | ILogArmorDestroy 315 | | ILogWheelDestroy 316 | | ILogPlayerMakeGroggy 317 | | ILogPlayerRevive 318 | ); 319 | 320 | export type ITelemetry = ITelemetryElement[]; 321 | -------------------------------------------------------------------------------- /src/shared/constants.ts: -------------------------------------------------------------------------------- 1 | export enum DeathType { 2 | ALIVE = 'alive', 3 | BY_PLAYER = 'byplayer', 4 | SUICIDE = 'suicide', 5 | } 6 | 7 | export enum GameMode { 8 | DUO = 'duo', 9 | DUO_FPP = 'duo-fpp', 10 | SOLO = 'solo', 11 | SOLO_FPP = 'solo-fpp', 12 | SQUAD = 'squad', 13 | SQUAD_FPP = 'squad-fpp', 14 | } 15 | 16 | export enum MapName { 17 | DESERT_MAIN = 'Desert_Main', 18 | ERANGEL_MAIN = 'Erangel_Main', 19 | SANHOK_MAIN = 'Savage_Main' 20 | } 21 | 22 | export enum PlatformRegion { 23 | // PC Platforms 24 | STEAM = 'steam', 25 | KAKAO = 'kakao', 26 | PC_AS = 'pc-as', 27 | PC_EU = 'pc-eu', 28 | PC_JP = 'pc-jp', 29 | PC_KRJP = 'pc-krjp', 30 | PC_KAKAO = 'pc-kakao', 31 | PC_NA = 'pc-na', 32 | PC_OC = 'pc-oc', 33 | PC_RU = 'pc-ru', 34 | PC_SA = 'pc-sa', 35 | PC_SEA = 'pc-sea', 36 | // PSN Platforms 37 | PSN = 'psn', 38 | PSN_AS = 'psn-as', 39 | PSN_EU = 'psn-eu', 40 | PSN_NA = 'psn-na', 41 | PSN_OC = 'psn-oc', 42 | // XBOX Platforms 43 | XBOX = 'xbox', 44 | XBOX_AS = 'xbox-as', 45 | XBOX_EU = 'xbox-eu', 46 | XBOX_NA = 'xbox-na', 47 | XBOX_OC = 'xbox-oc', 48 | XBOX_SA = 'xbox-sa' 49 | } 50 | 51 | export enum SeasonState { 52 | CLOSED = 'closed', 53 | PREPARE = 'prepare', 54 | PROGRESS = 'progress' 55 | } 56 | 57 | export enum TelemetryEventType { 58 | LOGPLAYERLOGIN = 'LogPlayerLogin', 59 | LOGPLAYERCREATE = 'LogPlayerCreate', 60 | LOGPLAYERPOSITION = 'LogPlayerPosition', 61 | LOGPLAYERATTACK = 'LogPlayerAttack', 62 | LOGITEMPICKUP = 'LogItemPickup', 63 | LOGITEMEQUIP = 'LogItemEquip', 64 | LOGITEMUNEQUIP = 'LogItemUnequip', 65 | LOGVEHICLERIDE = 'LogVehicleRide', 66 | LOGMATCHDEFINITION = 'LogMatchDefinition', 67 | LOGMATCHSTART = 'LogMatchStart', 68 | LOGGAMESTATEPERIODIC = 'LogGameStatePeriodic', 69 | LOGVEHICLELEAVE = 'LogVehicleLeave', 70 | LOGPLAYERTAKEDAMAGE = 'LogPlayerTakeDamage', 71 | LOGPLAYERLOGOUT = 'LogPlayerLogout', 72 | LOGITEMATTACH = 'LogItemAttach', 73 | LOGITEMDROP = 'LogItemDrop', 74 | LOGPLAYERKILL = 'LogPlayerKill', 75 | LOGITEMDETACH = 'LogItemDetach', 76 | LOGITEMUSE = 'LogItemUse', 77 | LOGCAREPACKAGESPAWN = 'LogCarePackageSpawn', 78 | LOGVEHICLEDESTROY = 'LogVehicleDestroy', 79 | LOGCAREPACKAGELAND = 'LogCarePackageLand', 80 | LOGMATCHEND = 'LogMatchEnd', 81 | LOGSWIMSTART = 'LogSwimStart', 82 | LOGSWIMEND = 'LogSwimEnd', 83 | LOGARMORDESTROY = 'LogArmorDestroy', 84 | LOGWHEELDESTROY = 'LogWheelDestroy', 85 | LOGPLAYERMAKEGROGGY = 'LogPlayerMakeGroggy', 86 | LOGPLAYERREVIVE = 'LogPlayerRevive', 87 | } 88 | -------------------------------------------------------------------------------- /src/shared/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | DeathType, 3 | GameMode, 4 | MapName, 5 | PlatformRegion, 6 | SeasonState, 7 | TelemetryEventType, 8 | } from './constants'; 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "rootDir": "src", 7 | "declaration": true, 8 | "strict": true, 9 | "sourceMap": true 10 | }, 11 | "include": [ 12 | "./src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "node_modules", 16 | "dist" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "jsRules": {}, 4 | "rules": { 5 | "max-line-length": [true, 100], 6 | "no-inferrable-types": true, 7 | "class-name": true, 8 | "comment-format": [ 9 | true, 10 | "check-space" 11 | ], 12 | "indent": [ 13 | true, 14 | "spaces" 15 | ], 16 | "eofline": true, 17 | "no-duplicate-variable": true, 18 | "prefer-const": true, 19 | "no-eval": true, 20 | "no-arg": true, 21 | "no-internal-module": true, 22 | "no-trailing-whitespace": [true, "ignore-template-strings", "ignore-jsdoc"], 23 | "no-bitwise": true, 24 | "no-shadowed-variable": true, 25 | "no-unused-expression-chai": true, 26 | "no-unused-variable": [true, {"ignore-pattern": "^(_.*)$"}], 27 | "one-line": [ 28 | true, 29 | "check-catch", 30 | "check-else", 31 | "check-open-brace", 32 | "check-whitespace" 33 | ], 34 | "quotemark": [ 35 | true, 36 | "single", 37 | "avoid-escape" 38 | ], 39 | "semicolon": true, 40 | "typedef-whitespace": [ 41 | true, 42 | { 43 | "call-signature": "nospace", 44 | "index-signature": "nospace", 45 | "parameter": "nospace", 46 | "property-declaration": "nospace", 47 | "variable-declaration": "nospace" 48 | } 49 | ], 50 | "curly": true, 51 | "variable-name": [ 52 | true, 53 | "ban-keywords", 54 | "check-format", 55 | "allow-leading-underscore" 56 | ], 57 | "whitespace": [ 58 | true, 59 | "check-branch", 60 | "check-decl", 61 | "check-operator", 62 | "check-separator", 63 | "check-type" 64 | ], 65 | "ordered-imports": [ 66 | true, 67 | { 68 | "grouped-imports": true, 69 | "import-sources-order": "lowercase-last", 70 | "named-imports-order": "lowercase-last" 71 | } 72 | ] 73 | }, 74 | "rulesDirectory": [ 75 | "tslint-no-unused-expression-chai" 76 | ] 77 | } 78 | --------------------------------------------------------------------------------