feat: stats saving

This commit is contained in:
AMelonInsideLemon 2024-07-29 14:03:27 +02:00
parent eff364cfc2
commit eab71eac7c
11 changed files with 532 additions and 25 deletions

View File

@ -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

View File

@ -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 };

View File

@ -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();
};

View File

@ -4,24 +4,37 @@ 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) {
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;
}

89
src/models/statsModel.ts Normal file
View File

@ -0,0 +1,89 @@
import { Schema, model } from "mongoose";
import { IEnemy, IMission, IScan, ITutorial, IAbility, IWeapon, IStatsView } from "@/src/types/statTypes";
const abilitySchema = new Schema<IAbility>(
{
used: Number,
type: { type: String, required: true }
},
{ _id: false }
);
const enemySchema = new Schema<IEnemy>(
{
executions: Number,
headshots: Number,
kills: Number,
type: { type: String, required: true },
assists: Number,
deaths: Number
},
{ _id: false }
);
const missionSchema = new Schema<IMission>(
{
highScore: Number,
type: { type: String, required: true }
},
{ _id: false }
);
const scanSchema = new Schema<IScan>(
{
scans: Number,
type: { type: String, required: true }
},
{ _id: false }
);
const tutorialSchema = new Schema<ITutorial>(
{
stage: Number
},
{ _id: false }
);
const weaponSchema = new Schema<IWeapon>(
{
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<IStatsView>({
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<IStatsView>("Stats", statsSchema);
export default Stats;

View File

@ -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();
@ -137,5 +138,6 @@ apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController
apiRouter.post("/updateSession.php", updateSessionPostController);
apiRouter.post("/updateTheme.php", updateThemeController);
apiRouter.post("/upgrades.php", upgradesController);
apiRouter.post("/updateNodeIntros.php", updateNodeIntrosController);
export { apiRouter };

View File

@ -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();

View File

@ -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<void> => {
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();
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}