diff --git a/src/controllers/api/missionInventoryUpdateController.ts b/src/controllers/api/missionInventoryUpdateController.ts index e2723a51..2d99d10f 100644 --- a/src/controllers/api/missionInventoryUpdateController.ts +++ b/src/controllers/api/missionInventoryUpdateController.ts @@ -25,11 +25,11 @@ import { logger } from "@/src/utils/logger"; - [ ] MissionTime - [x] Missions - [ ] CompletedAlerts -- [ ] LastRegionPlayed +- [x] LastRegionPlayed - [ ] GameModeId - [ ] hosts - [x] ChallengeProgress -- [ ] SeasonChallengeHistory +- [x] SeasonChallengeHistory - [ ] PS (Passive anti-cheat data which includes your username, module list, process list, and system name.) - [ ] ActiveDojoColorResearch - [x] RewardInfo diff --git a/src/controllers/api/updateNodeIntrosController.ts b/src/controllers/api/updateNodeIntrosController.ts new file mode 100644 index 00000000..697d690e --- /dev/null +++ b/src/controllers/api/updateNodeIntrosController.ts @@ -0,0 +1,22 @@ +import { RequestHandler } from "express"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { getJSONfromString } from "@/src/helpers/stringHelpers"; +import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; +import { IUpdateNodeIntro } from "@/src/types/requestTypes"; + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +const updateNodeIntrosController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const payload = getJSONfromString(String(req.body)) as IUpdateNodeIntro; + + // Update inventory + const inventory = await Inventory.findOne({ accountOwnerId: accountId }); + if (inventory) { + inventory.NodeIntrosCompleted.push(payload.NodeIntrosCompleted); + await inventory.save(); + } + + res.status(200).end(); +}; + +export { updateNodeIntrosController }; diff --git a/src/controllers/stats/uploadController.ts b/src/controllers/stats/uploadController.ts index 2763354a..f8b81b2e 100644 --- a/src/controllers/stats/uploadController.ts +++ b/src/controllers/stats/uploadController.ts @@ -1,6 +1,14 @@ +import { getJSONfromString } from "@/src/helpers/stringHelpers"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { uploadStats } from "@/src/services/statsService"; +import { IStatsUpload } from "@/src/types/statTypes"; import { RequestHandler } from "express"; -const uploadController: RequestHandler = (_req, res) => { +// eslint-disable-next-line @typescript-eslint/no-misused-promises +const uploadController: RequestHandler = async (req, res) => { + const payload = getJSONfromString(String(req.body)) as IStatsUpload; + const accountId = await getAccountIdForRequest(req); + await uploadStats(accountId, payload); res.status(200).end(); }; diff --git a/src/controllers/stats/viewController.ts b/src/controllers/stats/viewController.ts index cae180ce..b44b426c 100644 --- a/src/controllers/stats/viewController.ts +++ b/src/controllers/stats/viewController.ts @@ -4,23 +4,36 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { IStatsView } from "@/src/types/statTypes"; import { config } from "@/src/services/configService"; import allScans from "@/static/fixed_responses/allScans.json"; +import Stat from "@/src/models/statsModel"; // eslint-disable-next-line @typescript-eslint/no-misused-promises const viewController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); const inventory = await Inventory.findOne({ accountOwnerId: accountId }); + let playerStats = await Stat.findOne({ accountOwnerId: accountId }); + if (!inventory) { res.status(400).json({ error: "inventory was undefined" }); return; } - const responseJson: IStatsView = {}; - responseJson.Weapons = []; + if (!playerStats) { + playerStats = new Stat({ accountOwnerId: accountId }); + await playerStats.save(); + } + + const responseJson: IStatsView = playerStats; + responseJson.Weapons ??= []; for (const item of inventory.XPInfo) { - responseJson.Weapons.push({ - type: item.ItemType, - xp: item.XP - }); + const weaponIndex = responseJson.Weapons.findIndex(element => element.type == item.ItemType); + if (weaponIndex !== -1) { + responseJson.Weapons[weaponIndex].xp == item.XP; + } else { + responseJson.Weapons.push({ + type: item.ItemType, + xp: item.XP + }); + } } if (config.unlockAllScans) { responseJson.Scans = allScans; diff --git a/src/models/statsModel.ts b/src/models/statsModel.ts new file mode 100644 index 00000000..6a2d32e9 --- /dev/null +++ b/src/models/statsModel.ts @@ -0,0 +1,89 @@ +import { Schema, model } from "mongoose"; +import { IEnemy, IMission, IScan, ITutorial, IAbility, IWeapon, IStatsDatabase } from "@/src/types/statTypes"; + +const abilitySchema = new Schema( + { + used: Number, + type: { type: String, required: true } + }, + { _id: false } +); + +const enemySchema = new Schema( + { + executions: Number, + headshots: Number, + kills: Number, + type: { type: String, required: true }, + assists: Number, + deaths: Number + }, + { _id: false } +); + +const missionSchema = new Schema( + { + highScore: Number, + type: { type: String, required: true } + }, + { _id: false } +); + +const scanSchema = new Schema( + { + scans: Number, + type: { type: String, required: true } + }, + { _id: false } +); + +const tutorialSchema = new Schema( + { + stage: Number + }, + { _id: false } +); + +const weaponSchema = new Schema( + { + equipTime: Number, + hits: Number, + kills: Number, + xp: Number, + assists: Number, + type: { type: String, required: true }, + headshots: Number, + fired: Number + }, + { _id: false } +); + +const statsSchema = new Schema({ + accountOwnerId: Schema.Types.ObjectId, + CiphersSolved: Number, + CiphersFailed: Number, + CipherTime: Number, + Weapons: [weaponSchema], + Enemies: [enemySchema], + MeleeKills: Number, + MissionsCompleted: Number, + MissionsQuit: Number, + MissionsFailed: Number, + TimePlayedSec: Number, + PickupCount: Number, + Tutorial: { type: Map, of: tutorialSchema }, + Abilities: [abilitySchema], + Rating: Number, + Income: Number, + Rank: Number, + PlayerLevel: Number, + Scans: [scanSchema], + Missions: [missionSchema], + Deaths: Number, + HealCount: Number, + ReviveCount: Number +}); + +const Stats = model("Stats", statsSchema); + +export default Stats; diff --git a/src/routes/api.ts b/src/routes/api.ts index d4a0ebe0..f64bcd12 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -1,6 +1,6 @@ import express from "express"; import { addFriendImageController } from "@/src/controllers/api/addFriendImageController"; -import { artifactsController } from "../controllers/api/artifactsController"; +import { artifactsController } from "@/src/controllers/api/artifactsController"; import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController"; import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController"; import { createGuildController } from "@/src/controllers/api/createGuildController"; @@ -17,13 +17,13 @@ import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDail import { getFriendsController } from "@/src/controllers/api/getFriendsController"; import { getGuildController } from "@/src/controllers/api/getGuildController"; import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoController"; -import { getGuildLogController } from "../controllers/api/getGuildLogController"; +import { getGuildLogController } from "@/src/controllers/api/getGuildLogController"; import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController"; import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController"; import { getShipController } from "@/src/controllers/api/getShipController"; import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController"; import { gildWeaponController } from "@/src/controllers/api/gildWeaponController"; -import { guildTechController } from "../controllers/api/guildTechController"; +import { guildTechController } from "@/src/controllers/api/guildTechController"; import { hostSessionController } from "@/src/controllers/api/hostSessionController"; import { hubController } from "@/src/controllers/api/hubController"; import { hubInstancesController } from "@/src/controllers/api/hubInstancesController"; @@ -40,7 +40,7 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController"; import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController"; import { nameWeaponController } from "@/src/controllers/api/nameWeaponController"; -import { projectionManagerController } from "../controllers/api/projectionManagerController"; +import { projectionManagerController } from "@/src/controllers/api/projectionManagerController"; import { purchaseController } from "@/src/controllers/api/purchaseController"; import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController"; import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController"; @@ -51,19 +51,20 @@ import { setActiveShipController } from "@/src/controllers/api/setActiveShipCont import { setBootLocationController } from "@/src/controllers/api/setBootLocationController"; import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController"; import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController"; -import { setWeaponSkillTreeController } from "../controllers/api/setWeaponSkillTreeController"; +import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController"; import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController"; import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipeController"; import { startRecipeController } from "@/src/controllers/api/startRecipeController"; import { stepSequencersController } from "@/src/controllers/api/stepSequencersController"; import { surveysController } from "@/src/controllers/api/surveysController"; -import { syndicateSacrificeController } from "../controllers/api/syndicateSacrificeController"; +import { syndicateSacrificeController } from "@/src/controllers/api/syndicateSacrificeController"; import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController"; import { trainingResultController } from "@/src/controllers/api/trainingResultController"; import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController"; import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController"; -import { updateThemeController } from "../controllers/api/updateThemeController"; +import { updateThemeController } from "@/src/controllers/api/updateThemeController"; import { upgradesController } from "@/src/controllers/api/upgradesController"; +import { updateNodeIntrosController } from "@/src/controllers/api/updateNodeIntrosController"; const apiRouter = express.Router(); @@ -138,5 +139,6 @@ apiRouter.post("/updateNodeIntros.php", genericUpdateController); apiRouter.post("/updateSession.php", updateSessionPostController); apiRouter.post("/updateTheme.php", updateThemeController); apiRouter.post("/upgrades.php", upgradesController); +apiRouter.post("/updateNodeIntros.php", updateNodeIntrosController); export { apiRouter }; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index c32a8af1..5edafb21 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -675,7 +675,7 @@ export const updateChallengeProgress = async (challenges: IUpdateChallengeProgre const inventory = await getInventory(accountId); addChallenges(inventory, challenges.ChallengeProgress); - addSeasonalChallengeHistory(inventory, challenges.SeasonChallengeHistory); + addSeasonalChallengeHistory(inventory, challenges.SeasonChallengeCompletions); await inventory.save(); }; @@ -700,14 +700,15 @@ export const addSeasonalChallengeHistory = ( export const addChallenges = (inventory: IInventoryDatabaseDocument, itemsArray: IChallengeProgress[] | undefined) => { const category = inventory.ChallengeProgress; - itemsArray?.forEach(({ Name, Progress }) => { + itemsArray?.forEach(({ Name, Progress, Completed }) => { const itemIndex = category.findIndex(i => i.Name === Name); if (itemIndex !== -1) { - category[itemIndex].Progress += Progress; - inventory.markModified(`ChallengeProgress.${itemIndex}.ItemCount`); + category[itemIndex].Progress = Progress; + category[itemIndex].Completed = Completed; + inventory.markModified(`ChallengeProgress.${itemIndex}.Progress`); } else { - category.push({ Name, Progress }); + category.push({ Name, Progress, Completed }); } }); }; @@ -724,6 +725,13 @@ const addMissionComplete = (inventory: IInventoryDatabaseDocument, { Tag, Comple } }; +const addDeathMarks = (inventory: IInventoryDatabaseDocument, marks: string[] | undefined) => { + const { DeathMarks } = inventory; + marks?.forEach(mark => { + if (!DeathMarks.find(element => element === mark)) DeathMarks.push(mark); + }); +}; + export const missionInventoryUpdate = async (data: IMissionInventoryUpdateRequest, accountId: string) => { const { RawUpgrades, @@ -734,7 +742,8 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdateReques Consumables, Recipes, Missions, - FusionTreasures + FusionTreasures, + DeathMarks } = data; const inventory = await getInventory(accountId); @@ -796,6 +805,7 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdateReques if (Missions) { addMissionComplete(inventory, Missions); } + addDeathMarks(inventory, DeathMarks); const changedInventory = await inventory.save(); return changedInventory.toJSON(); diff --git a/src/services/statsService.ts b/src/services/statsService.ts new file mode 100644 index 00000000..5d8c45b4 --- /dev/null +++ b/src/services/statsService.ts @@ -0,0 +1,273 @@ +import Stats from "@/src/models/statsModel"; +import { IStatsUpload } from "@/src/types/statTypes"; + +/* + Missing in stats update + + Weapons?: IWeapon[]; // assists + Enemies?: IEnemy[]; // assists + Tutorial?: { [key: string]: ITutorial }; + Missions?: IMission[]; + HealCount?: number; + ReviveCount?: number; +*/ + +export const uploadStats = async (accountId: string, payload: IStatsUpload): Promise => { + let playerStats = await Stats.findOne({ accountOwnerId: accountId }); + if (!playerStats) { + playerStats = new Stats({ accountOwnerId: accountId }); + } + + if (payload.add) { + const { + MISSION_COMPLETE, + PICKUP_ITEM, + SCAN, + USE_ABILITY, + FIRE_WEAPON, + HIT_ENTITY_ITEM, + HEADSHOT_ITEM, + KILL_ENEMY_ITEM, + KILL_ENEMY, + EXECUTE_ENEMY, + HEADSHOT, + DIE, + MELEE_KILL, + INCOME, + CIPHER + } = payload.add; + + if (MISSION_COMPLETE) { + for (const [key, value] of Object.entries(MISSION_COMPLETE)) { + switch (key) { + case "GS_SUCCESS": + playerStats.MissionsCompleted ??= 0; + playerStats.MissionsCompleted += value; + break; + case "GS_QUIT": + playerStats.MissionsQuit ??= 0; + playerStats.MissionsQuit += value; + break; + case "GS_FAILURE": + playerStats.MissionsFailed ??= 0; + playerStats.MissionsFailed += value; + break; + } + } + } + + if (PICKUP_ITEM) { + for (const value of Object.values(PICKUP_ITEM)) { + playerStats.PickupCount ??= 0; + playerStats.PickupCount += value; + } + } + + if (SCAN) { + for (const [key, scans] of Object.entries(SCAN)) { + playerStats.Scans ??= []; + const scan = playerStats.Scans.find(element => element.type === key); + if (scan) { + scan.scans ??= 0; + scan.scans += scans; + } else { + playerStats.Scans.push({ type: key, scans }); + } + } + } + + if (USE_ABILITY) { + for (const [key, used] of Object.entries(USE_ABILITY)) { + playerStats.Abilities ??= []; + const ability = playerStats.Abilities.find(element => element.type === key); + if (ability) { + ability.used ??= 0; + ability.used += used; + } else { + playerStats.Abilities.push({ type: key, used }); + } + } + } + + if (FIRE_WEAPON) { + for (const [key, fired] of Object.entries(FIRE_WEAPON)) { + playerStats.Weapons ??= []; + const weapon = playerStats.Weapons.find(element => element.type === key); + if (weapon) { + weapon.fired ??= 0; + weapon.fired += fired; + } else { + playerStats.Weapons.push({ type: key, fired }); + } + } + } + + if (HIT_ENTITY_ITEM) { + for (const [key, hits] of Object.entries(HIT_ENTITY_ITEM)) { + playerStats.Weapons ??= []; + const weapon = playerStats.Weapons.find(element => element.type === key); + if (weapon) { + weapon.hits ??= 0; + weapon.hits += hits; + } else { + playerStats.Weapons.push({ type: key, hits }); + } + } + } + + if (HEADSHOT_ITEM) { + for (const [key, headshots] of Object.entries(HEADSHOT_ITEM)) { + playerStats.Weapons ??= []; + const weapon = playerStats.Weapons.find(element => element.type === key); + if (weapon) { + weapon.headshots ??= 0; + weapon.headshots += headshots; + } else { + playerStats.Weapons.push({ type: key, headshots }); + } + } + } + + if (KILL_ENEMY_ITEM) { + for (const [key, kills] of Object.entries(KILL_ENEMY_ITEM)) { + playerStats.Weapons ??= []; + const weapon = playerStats.Weapons.find(element => element.type === key); + if (weapon) { + weapon.kills ??= 0; + weapon.kills += kills; + } else { + playerStats.Weapons.push({ type: key, kills }); + } + } + } + + if (KILL_ENEMY) { + for (const [key, kills] of Object.entries(KILL_ENEMY)) { + playerStats.Enemies ??= []; + const enemy = playerStats.Enemies.find(element => element.type === key); + if (enemy) { + enemy.kills ??= 0; + enemy.kills += kills; + } else { + playerStats.Enemies.push({ type: key, kills }); + } + } + } + + if (EXECUTE_ENEMY) { + for (const [key, executions] of Object.entries(EXECUTE_ENEMY)) { + playerStats.Enemies ??= []; + const enemy = playerStats.Enemies.find(element => element.type === key); + if (enemy) { + enemy.executions ??= 0; + enemy.executions += executions; + } else { + playerStats.Enemies.push({ type: key, executions }); + } + } + } + + if (HEADSHOT) { + for (const [key, headshots] of Object.entries(HEADSHOT)) { + playerStats.Enemies ??= []; + const enemy = playerStats.Enemies.find(element => element.type === key); + if (enemy) { + enemy.headshots ??= 0; + enemy.headshots += headshots; + } else { + playerStats.Enemies.push({ type: key, headshots }); + } + } + } + + if (DIE) { + for (const [key, deaths] of Object.entries(DIE)) { + playerStats.Deaths ??= 0; + playerStats.Deaths += deaths; + playerStats.Enemies ??= []; + const enemy = playerStats.Enemies.find(element => element.type === key); + if (enemy) { + enemy.deaths ??= 0; + enemy.deaths += deaths; + } else { + playerStats.Enemies.push({ type: key, deaths }); + } + } + } + + if (MELEE_KILL) { + playerStats.MeleeKills ??= 0; + for (const kills of Object.values(MELEE_KILL)) { + playerStats.MeleeKills += kills; + } + } + + if (INCOME) { + playerStats.Income ??= 0; + playerStats.Income += INCOME; + } + + if (CIPHER) { + if (CIPHER["0"] > 0) { + playerStats.CiphersFailed ??= 0; + playerStats.CiphersFailed += CIPHER["0"]; + } + if (CIPHER["1"] > 0) { + playerStats.CiphersSolved ??= 0; + playerStats.CiphersSolved += CIPHER["1"]; + } + } + } + + if (payload.timers) { + const { EQUIP_WEAPON, CURRENT_MISSION_TIME, CIPHER_TIME } = payload.timers; + + if (EQUIP_WEAPON) { + for (const [key, equipTime] of Object.entries(EQUIP_WEAPON)) { + playerStats.Weapons ??= []; + const weapon = playerStats.Weapons.find(element => element.type === key); + if (weapon) { + weapon.equipTime ??= 0; + weapon.equipTime += equipTime; + } else { + playerStats.Weapons.push({ type: key, equipTime }); + } + } + } + + if (CURRENT_MISSION_TIME) { + playerStats.TimePlayedSec ??= 0; + playerStats.TimePlayedSec += CURRENT_MISSION_TIME; + } + + if (CIPHER_TIME) { + playerStats.CipherTime ??= 0; + playerStats.CipherTime += CIPHER_TIME; + } + } + + if (payload.max) { + const { WEAPON_XP } = payload.max; + if (WEAPON_XP) { + for (const [key, xp] of Object.entries(WEAPON_XP)) { + playerStats.Weapons ??= []; + const weapon = playerStats.Weapons.find(element => element.type === key); + if (weapon) { + weapon.xp ??= 0; + weapon.xp += xp; + } else { + playerStats.Weapons.push({ type: key, xp }); + } + } + } + } + + if (payload.set) { + const { ELO_RATING, RANK, PLAYER_LEVEL } = payload.set; + if (ELO_RATING) playerStats.Rating = ELO_RATING; + if (RANK) playerStats.Rank = RANK; + if (PLAYER_LEVEL) playerStats.PlayerLevel = PLAYER_LEVEL; + } + + await playerStats.save(); +}; diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 3c55823e..f3093f7b 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -284,7 +284,7 @@ export interface IInventoryResponse { Robotics: any[]; UsedDailyDeals: any[]; LibraryPersonalProgress: ILibraryPersonalProgress[]; - CollectibleSeries: ICollectibleSery[]; + CollectibleSeries: ICollectibleSeries[]; LibraryAvailableDailyTaskInfo: ILibraryAvailableDailyTaskInfo; HasResetAccount: boolean; PendingCoupon: IPendingCoupon; @@ -326,10 +326,10 @@ export interface IParam { export interface IChallengeProgress { Progress: number; Name: string; - Completed?: string[]; + Completed: string[]; } -export interface ICollectibleSery { +export interface ICollectibleSeries { CollectibleType: string; Count: number; Tracking: string; diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index 288bb99c..98ff2bf7 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -70,6 +70,7 @@ export interface IMissionInventoryUpdateRequest { Missions?: IMission; EvolutionProgress?: IEvolutionProgress[]; LastRegionPlayed?: TSolarMapRegion; + DeathMarks?: string[]; FusionPoints?: number; // Not a part of the request, but we put it in this struct as an intermediate storage. } @@ -114,3 +115,8 @@ export interface IUpgradeOperation { PolarizeValue: ArtifactPolarity; PolarityRemap: IPolarity[]; } + +export interface IUpdateNodeIntro { + NodeIntrosCompleted: string; + crossPlaySetting?: string; +} diff --git a/src/types/statTypes.ts b/src/types/statTypes.ts index cd5b19d9..36934803 100644 --- a/src/types/statTypes.ts +++ b/src/types/statTypes.ts @@ -1,3 +1,5 @@ +import { Types } from "mongoose"; + export interface IStatsView { CiphersSolved?: number; CiphersFailed?: number; @@ -23,6 +25,10 @@ export interface IStatsView { ReviveCount?: number; } +export interface IStatsDatabase extends IStatsView { + accountOwnerId: Types.ObjectId; +} + export interface IAbility { used: number; type: string; @@ -61,3 +67,81 @@ export interface IWeapon { headshots?: number; fired?: number; } + +export interface IStatsUpload { + displayName: string; + guildId?: string; + PS?: string; + add?: IStatsAdd; + set?: IStatsSet; + max?: IStatsMax; + timers?: IStatsTimers; +} + +export interface IStatsAdd { + GEAR_USED?: IUploadEntry; + SCAN?: IUploadEntry; + MISSION_COMPLETE?: IUploadEntry; + HEADSHOT_ITEM?: IUploadEntry; + HEADSHOT?: IUploadEntry; + PLAYER_COUNT?: IUploadEntry; + HOST_MIGRATION?: IUploadEntry; + PICKUP_ITEM?: IUploadEntry; + FIRE_WEAPON?: IUploadEntry; + HIT_ENTITY_ITEM?: IUploadEntry; + DESTROY_DECORATION?: IUploadEntry; + KILL_ENEMY?: IUploadEntry; + TAKE_DAMAGE?: IUploadEntry; + SQUAD_KILL_ENEMY?: IUploadEntry; + RECEIVE_UPGRADE?: IUploadEntry; + USE_ABILITY?: IUploadEntry; + SQUAD_VIP_KILL?: IUploadEntry; + HEAL_BUDDY?: IUploadEntry; + INCOME?: number; + CIPHER?: IUploadEntry; + EQUIP_COSMETIC?: IUploadEntry; + EQUIP_UPGRADE?: IUploadEntry; + KILL_BOSS?: IUploadEntry; + MISSION_TYPE?: IUploadEntry; + MISSION_FACTION?: IUploadEntry; + MISSION_PLAYED?: IUploadEntry; + MISSION_PLAYED_TIME?: IUploadEntry; + MEDALS_TOP?: IUploadEntry; + INPUT_ACTIVITY_TIME?: IUploadEntry; + KILL_ENEMY_ITEM?: IUploadEntry; + TAKE_DAMAGE_ITEM?: IUploadEntry; + SQUAD_KILL_ENEMY_ITEM?: IUploadEntry; + MELEE_KILL?: IUploadEntry; + SQUAD_MELEE_KILL?: IUploadEntry; + MELEE_KILL_ITEM?: IUploadEntry; + SQUAD_MELEE_KILL_ITEM?: IUploadEntry; + DIE?: IUploadEntry; + DIE_ITEM?: IUploadEntry; + EXECUTE_ENEMY?: IUploadEntry; + EXECUTE_ENEMY_ITEM?: IUploadEntry; +} + +export interface IUploadEntry { + [key: string]: number; +} + +export interface IStatsMax { + WEAPON_XP?: IUploadEntry; +} + +export interface IStatsSet { + ELO_RATING?: number; + RANK?: number; + PLAYER_LEVEL?: number; +} + +export interface IStatsTimers { + IN_SHIP_TIME?: number; + IN_SHIP_VIEW_TIME?: IUploadEntry; + EQUIP_WEAPON?: IUploadEntry; + MISSION_TIME?: IUploadEntry; + REGION_TIME?: IUploadEntry; + PLATFORM_TIME?: IUploadEntry; + CURRENT_MISSION_TIME?: number; + CIPHER_TIME?: number; +}