XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

Mission rewards fix (#54)

67b73383
Nicat <52883148+holmityd@users.noreply.github.com>
提交于

代码差异

10 个文件 +135 -156
Modified src/controllers/api/artifactsController.ts +7 -8
@@ -1,19 +1,18 @@
1 import { parseString } from "@/src/helpers/general";
2 import { getJSONfromString } from "@/src/helpers/stringHelpers";
1 3 import { upgradeMod } from "@/src/services/inventoryService";
4 import { IArtifactsRequest } from "@/src/types/requestTypes";
2 5 import { RequestHandler } from "express";
3 6
4 7 // eslint-disable-next-line @typescript-eslint/no-misused-promises
5 8 const artifactsController: RequestHandler = async (req, res) => {
6 const [data] = String(req.body).split("\n");
7 const id = req.query.accountId as string;
8
9 // TODO - salt check
9 const accountId = parseString(req.query.accountId);
10 10
11 11 try {
12 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
13 const parsedData = JSON.parse(data);
14
12 // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
13 const artifactsData = getJSONfromString(req.body.toString()) as IArtifactsRequest;
15 14 // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
16 const upgradeModId = await upgradeMod(parsedData, id);
15 const upgradeModId = await upgradeMod(artifactsData, accountId);
17 16 res.send(upgradeModId);
18 17 } catch (err) {
19 18 console.error("Error parsing JSON data:", err);
Modified src/controllers/api/missionInventoryUpdateController.ts +10 -11
@@ -1,7 +1,9 @@
1 1 import { RequestHandler } from "express";
2 2 import { missionInventoryUpdate } from "@/src/services/inventoryService";
3 3 import { combineRewardAndLootInventory, getRewards } from "@/src/services/missionInventoryUpdateService ";
4 import { IMissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType";
4 import { getJSONfromString } from "@/src/helpers/stringHelpers";
5 import { parseString } from "@/src/helpers/general";
6 import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
5 7 /*
6 8 **** INPUT ****
7 9 - [ ] crossPlaySetting
@@ -20,7 +22,7 @@ import { IMissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType"
20 22 - [ ] CurrentLoadOutIds
21 23 - [ ] AliveTime
22 24 - [ ] MissionTime
23 - [ ] Missions
25 - [x] Missions
24 26 - [ ] CompletedAlerts
25 27 - [ ] LastRegionPlayed
26 28 - [ ] GameModeId
@@ -43,23 +45,20 @@ import { IMissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType"
43 45 */
44 46
45 47 // eslint-disable-next-line @typescript-eslint/no-misused-promises
46 const missionInventoryUpdateController: RequestHandler = async (req, res) => {
47 const [data] = String(req.body).split("\n");
48 const id = req.query.accountId as string;
48 const missionInventoryUpdateController: RequestHandler = async (req, res): Promise<void> => {
49 const accountId = parseString(req.query.accountId);
49 50
50 51 try {
51 const lootInventory = JSON.parse(data) as IMissionInventoryUpdate;
52 if (typeof lootInventory !== "object" || lootInventory === null) {
53 throw new Error("Invalid data format");
54 }
52 // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
53 const lootInventory = getJSONfromString(req.body.toString()) as IMissionInventoryUpdateRequest;
55 54
56 const { InventoryChanges, MissionRewards } = getRewards(lootInventory.RewardInfo);
55 const { InventoryChanges, MissionRewards } = getRewards(lootInventory);
57 56
58 57 const { combinedInventoryChanges, TotalCredits, CreditsBonus, MissionCredits, FusionPoints } =
59 58 combineRewardAndLootInventory(InventoryChanges, lootInventory);
60 59
61 60 // eslint-disable-next-line @typescript-eslint/no-unused-vars
62 const InventoryJson = JSON.stringify(await missionInventoryUpdate(combinedInventoryChanges, id));
61 const InventoryJson = JSON.stringify(await missionInventoryUpdate(combinedInventoryChanges, accountId));
63 62 res.json({
64 63 // InventoryJson, // this part will reset game data and missions will be locked
65 64 MissionRewards,
Modified src/helpers/stringHelpers.ts +1 -1
@@ -1,4 +1,4 @@
1 const getJSONfromString = (str: string): any => {
1 export const getJSONfromString = (str: string): any => {
2 2 const jsonSubstring = str.substring(0, str.lastIndexOf("}") + 1);
3 3 return JSON.parse(jsonSubstring);
4 4 };
Modified src/services/inventoryService.ts +25 -18
@@ -2,20 +2,20 @@ import { Inventory } from "@/src/models/inventoryModel";
2 2 import new_inventory from "@/static/fixed_responses/postTutorialInventory.json";
3 3 import config from "@/config.json";
4 4 import { Types } from "mongoose";
5 import { ISuitResponse } from "@/src/types/inventoryTypes/SuitTypes";
5 import { ISuitDatabase, ISuitResponse } from "@/src/types/inventoryTypes/SuitTypes";
6 6 import { SlotType } from "@/src/types/purchaseTypes";
7 import { IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes";
7 import { IWeaponDatabase, IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes";
8 8 import {
9 9 IChallengeProgress,
10 10 IConsumable,
11 ICrewShipSalvagedWeaponSkin,
12 11 IFlavourItem,
13 12 IInventoryDatabaseDocument,
14 13 IMiscItem,
14 IMission,
15 15 IRawUpgrade
16 16 } from "@/src/types/inventoryTypes/inventoryTypes";
17 import { IMissionInventoryUpdate, IMissionInventoryUpdateGear } from "../types/missionInventoryUpdateType";
18 17 import { IGenericUpdate } from "../types/genericUpdate";
18 import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
19 19
20 20 const createInventory = async (accountOwnerId: Types.ObjectId) => {
21 21 try {
@@ -139,17 +139,17 @@ export const addCustomization = async (customizatonName: string, accountId: stri
139 139
140 140 const addGearExpByCategory = (
141 141 inventory: IInventoryDatabaseDocument,
142 gearArray: IMissionInventoryUpdateGear[] | undefined,
142 gearArray: ISuitDatabase[] | IWeaponDatabase[] | undefined,
143 143 categoryName: "Pistols" | "LongGuns" | "Melee" | "Suits"
144 144 ) => {
145 145 const category = inventory[categoryName];
146 146
147 147 gearArray?.forEach(({ ItemId, XP }) => {
148 const itemIndex = category.findIndex(item => item._id?.equals(ItemId.$oid));
148 const itemIndex = ItemId ? category.findIndex(item => item._id?.equals(ItemId.$oid)) : -1;
149 149 const item = category[itemIndex];
150 150
151 151 if (itemIndex !== -1 && item.XP != undefined) {
152 item.XP += XP;
152 item.XP += XP || 0;
153 153 inventory.markModified(`${categoryName}.${itemIndex}.XP`);
154 154 }
155 155 });
@@ -229,11 +229,24 @@ const addChallenges = (inventory: IInventoryDatabaseDocument, itemsArray: IChall
229 229 });
230 230 };
231 231
232 const addMissionComplete = (inventory: IInventoryDatabaseDocument, { Tag, Completes }: IMission) => {
233 const { Missions } = inventory;
234 const itemIndex = Missions.findIndex(item => item.Tag === Tag);
235
236 if (itemIndex !== -1) {
237 Missions[itemIndex].Completes += Completes;
238 inventory.markModified(`Missions.${itemIndex}.Completes`);
239 } else {
240 Missions.push({ Tag, Completes });
241 }
242 };
243
232 244 const gearKeys = ["Suits", "Pistols", "LongGuns", "Melee"] as const;
233 245 type GearKeysType = (typeof gearKeys)[number];
234 246
235 export const missionInventoryUpdate = async (data: IMissionInventoryUpdate, accountId: string) => {
236 const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress, FusionPoints, Consumables, Recipes } = data;
247 export const missionInventoryUpdate = async (data: IMissionInventoryUpdateRequest, accountId: string) => {
248 const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress, FusionPoints, Consumables, Recipes, Missions } =
249 data;
237 250 const inventory = await getInventory(accountId);
238 251
239 252 // credits
@@ -251,6 +264,7 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdate, acco
251 264 addConsumables(inventory, Consumables);
252 265 addRecipes(inventory, Recipes);
253 266 addChallenges(inventory, ChallengeProgress);
267 addMissionComplete(inventory, Missions!);
254 268
255 269 const changedInventory = await inventory.save();
256 270 return changedInventory.toJSON();
@@ -275,15 +289,8 @@ export const addBooster = async (ItemType: string, time: number, accountId: stri
275 289 await inventory.save();
276 290 };
277 291
278 export const upgradeMod = async (
279 {
280 Upgrade,
281 LevelDiff,
282 Cost,
283 FusionPointCost
284 }: { Upgrade: ICrewShipSalvagedWeaponSkin; LevelDiff: number; Cost: number; FusionPointCost: number },
285 accountId: string
286 ): Promise<string | undefined> => {
292 export const upgradeMod = async (artifactsData: IArtifactsRequest, accountId: string): Promise<string | undefined> => {
293 const { Upgrade, LevelDiff, Cost, FusionPointCost } = artifactsData;
287 294 try {
288 295 const inventory = await getInventory(accountId);
289 296 const { Upgrades, RawUpgrades } = inventory;
Modified src/services/missionInventoryUpdateService .ts +20 -24
@@ -1,29 +1,26 @@
1 import {
2 IMissionInventoryUpdate,
3 IMissionInventoryUpdateRewardInfo,
4 IMissionRewardResponse,
5 IReward,
6 IInventoryFieldType,
7 inventoryFields
8 } from "@/src/types/missionInventoryUpdateType";
1 import { IMissionRewardResponse, IReward, IInventoryFieldType, inventoryFields } from "@/src/types/missionTypes";
9 2
10 3 import missionsDropTable from "@/static/json/missions-drop-table.json";
11 4 import { modNames, relicNames, miscNames, resourceNames, gearNames, blueprintNames } from "@/static/data/items";
5 import { IMissionInventoryUpdateRequest } from "../types/requestTypes";
12 6
13 7 // need reverse engineer rewardSeed, otherwise ingame displayed rotation reward will be different than added to db or displayed on mission end
14 const getRewards = (
15 rewardInfo: IMissionInventoryUpdateRewardInfo | undefined
16 ): { InventoryChanges: IMissionInventoryUpdate; MissionRewards: IMissionRewardResponse[] } => {
17 if (!rewardInfo) {
8 const getRewards = ({
9 RewardInfo
10 }: IMissionInventoryUpdateRequest): {
11 InventoryChanges: IMissionInventoryUpdateRequest;
12 MissionRewards: IMissionRewardResponse[];
13 } => {
14 if (!RewardInfo) {
18 15 return { InventoryChanges: {}, MissionRewards: [] };
19 16 }
20 17
21 const rewards = (missionsDropTable as { [key: string]: IReward[] })[rewardInfo.node];
18 const rewards = (missionsDropTable as { [key: string]: IReward[] })[RewardInfo.node];
22 19 if (!rewards) {
23 20 return { InventoryChanges: {}, MissionRewards: [] };
24 21 }
25 22
26 const rotationCount = rewardInfo.rewardQualifications?.length || 0;
23 const rotationCount = RewardInfo.rewardQualifications?.length || 0;
27 24 const rotations = getRotations(rotationCount);
28 25 const drops: IReward[] = [];
29 26 for (const rotation of rotations) {
@@ -54,6 +51,7 @@ const getRewards = (
54 51 // { chance: 10.82, name: "2X Orokin Cell", rotation: "C" },
55 52 // { chance: 10.82, name: "Arrow Mutation", rotation: "C" },
56 53 // { chance: 10.82, name: "200 Endo", rotation: "C" },
54 // { chance: 10.82, name: "200 Endo", rotation: "C" },
57 55 // { chance: 10.82, name: "2,000,000 Credits Cache", rotation: "C" },
58 56 // { chance: 7.69, name: "Health Restore (Large)", rotation: "C" },
59 57 // { chance: 7.69, name: "Vapor Specter Blueprint", rotation: "C" }
@@ -66,8 +64,8 @@ const getRewards = (
66 64 };
67 65
68 66 const combineRewardAndLootInventory = (
69 rewardInventory: IMissionInventoryUpdate,
70 lootInventory: IMissionInventoryUpdate
67 rewardInventory: IMissionInventoryUpdateRequest,
68 lootInventory: IMissionInventoryUpdateRequest
71 69 ) => {
72 70 const missionCredits = lootInventory.RegularCredits || 0;
73 71 const creditsBonus = rewardInventory.RegularCredits || 0;
@@ -98,12 +96,10 @@ const getRotations = (rotationCount: number): (string | undefined)[] => {
98 96 if (rotationCount === 0) return [undefined];
99 97
100 98 const rotationPattern = ["A", "A", "B", "C"];
101 let rotationIndex = 0;
102 99 const rotatedValues = [];
103 100
104 for (let i = 1; i <= rotationCount; i++) {
105 rotatedValues.push(rotationPattern[rotationIndex]);
106 rotationIndex = (rotationIndex + 1) % 3;
101 for (let i = 0; i < rotationCount; i++) {
102 rotatedValues.push(rotationPattern[i % rotationPattern.length]);
107 103 }
108 104
109 105 return rotatedValues;
@@ -128,8 +124,8 @@ const getRandomRewardByChance = (data: IReward[] | undefined): IReward | undefin
128 124
129 125 const formatRewardsToInventoryType = (
130 126 rewards: IReward[]
131 ): { InventoryChanges: IMissionInventoryUpdate; MissionRewards: IMissionRewardResponse[] } => {
132 const InventoryChanges: IMissionInventoryUpdate = {};
127 ): { InventoryChanges: IMissionInventoryUpdateRequest; MissionRewards: IMissionRewardResponse[] } => {
128 const InventoryChanges: IMissionInventoryUpdateRequest = {};
133 129 const MissionRewards: IMissionRewardResponse[] = [];
134 130 for (const reward of rewards) {
135 131 if (itemCheck(InventoryChanges, MissionRewards, reward.name)) {
@@ -152,7 +148,7 @@ const formatRewardsToInventoryType = (
152 148 };
153 149
154 150 const itemCheck = (
155 InventoryChanges: IMissionInventoryUpdate,
151 InventoryChanges: IMissionInventoryUpdateRequest,
156 152 MissionRewards: IMissionRewardResponse[],
157 153 name: string
158 154 ) => {
@@ -184,7 +180,7 @@ const getCountFromName = (name: string) => {
184 180 };
185 181
186 182 const addRewardResponse = (
187 InventoryChanges: IMissionInventoryUpdate,
183 InventoryChanges: IMissionInventoryUpdateRequest,
188 184 MissionRewards: IMissionRewardResponse[],
189 185 ItemName: string,
190 186 ItemType: string,
Modified src/types/inventoryTypes/SuitTypes.ts +1 -0
@@ -24,6 +24,7 @@ export interface ISuitDatabase {
24 24 FocusLens?: string;
25 25 UnlockLevel?: number;
26 26 _id: Types.ObjectId;
27 ItemId?: IOid;
27 28 }
28 29
29 30 export interface SuitConfig {
Modified src/types/inventoryTypes/weaponTypes.ts +1 -0
@@ -22,6 +22,7 @@ export interface IWeaponDatabase {
22 22 ModularParts?: string[];
23 23 UnlockLevel?: number;
24 24 _id?: Types.ObjectId;
25 ItemId?: IOid;
25 26 }
26 27
27 28 export interface WeaponConfig {
Deleted src/types/missionInventoryUpdateType.ts +0 -94
@@ -1,94 +0,0 @@
1 /* eslint-disable @typescript-eslint/no-explicit-any */
2 import { IOid } from "./commonTypes";
3 import { IDate } from "./inventoryTypes/inventoryTypes";
4
5 export const inventoryFields = ["RawUpgrades", "MiscItems", "Consumables", "Recipes"] as const;
6 export type IInventoryFieldType = (typeof inventoryFields)[number];
7 export interface IMissionInventoryUpdateGear {
8 ItemType: string;
9 ItemName: string;
10 ItemId: IOid;
11 XP: number;
12 UpgradeVer: number;
13 Features: number;
14 Polarized: number;
15 CustomizationSlotPurchases: number;
16 ModSlotPurchases: number;
17 FocusLens: string;
18 Expiry: IDate;
19 Polarity: any[];
20 Configs: any[];
21 ModularParts: any[];
22 SkillTree: string;
23 UpgradeType: string;
24 UpgradeFingerprint: string;
25 OffensiveUpgrade: string;
26 DefensiveUpgrade: string;
27 UpgradesExpiry: IDate;
28 ArchonCrystalUpgrades: any[];
29 }
30
31 export interface IMissionInventoryUpdateItem {
32 ItemCount: number;
33 ItemType: string;
34 }
35
36 export interface IMissionInventoryUpdateCard extends IMissionInventoryUpdateItem {
37 ItemId: IOid;
38 UpgradeFingerprint: string;
39 PendingRerollFingerprint: string;
40 LastAdded: IOid;
41 }
42
43 export interface IMissionInventoryUpdateChallange {
44 Name: string;
45 Progress: number;
46 Completed: any[];
47 }
48
49 export interface IMissionInventoryUpdateRewardInfo {
50 node: string;
51 rewardTier?: number;
52 nightmareMode?: boolean;
53 useVaultManifest?: boolean;
54 EnemyCachesFound?: number;
55 toxinOk?: boolean;
56 lostTargetWave?: number;
57 defenseTargetCount?: number;
58 EOM_AFK?: number;
59 rewardQualifications?: string;
60 PurgatoryRewardQualifications?: string;
61 rewardSeed?: number;
62 }
63
64 export interface IMissionInventoryUpdate {
65 rewardsMultiplier?: number;
66 ActiveBoosters?: any[];
67 LongGuns?: IMissionInventoryUpdateGear[];
68 Pistols?: IMissionInventoryUpdateGear[];
69 Suits?: IMissionInventoryUpdateGear[];
70 Melee?: IMissionInventoryUpdateGear[];
71 RawUpgrades?: IMissionInventoryUpdateItem[];
72 MiscItems?: IMissionInventoryUpdateItem[];
73 Consumables?: IMissionInventoryUpdateItem[];
74 Recipes?: IMissionInventoryUpdateItem[];
75 RegularCredits?: number;
76 ChallengeProgress?: IMissionInventoryUpdateChallange[];
77 RewardInfo?: IMissionInventoryUpdateRewardInfo;
78 FusionPoints?: number;
79 }
80
81 export interface IMissionRewardResponse {
82 StoreItem?: string;
83 TypeName: string;
84 UpgradeLevel?: number;
85 ItemCount: number;
86 TweetText: string;
87 ProductCategory: string;
88 }
89
90 export interface IReward {
91 name: string;
92 chance: number;
93 rotation?: string;
94 }
Added src/types/missionTypes.ts +17 -0
@@ -0,0 +1,17 @@
1 export const inventoryFields = ["RawUpgrades", "MiscItems", "Consumables", "Recipes"] as const;
2 export type IInventoryFieldType = (typeof inventoryFields)[number];
3
4 export interface IMissionRewardResponse {
5 StoreItem?: string;
6 TypeName: string;
7 UpgradeLevel?: number;
8 ItemCount: number;
9 TweetText: string;
10 ProductCategory: string;
11 }
12
13 export interface IReward {
14 name: string;
15 chance: number;
16 rotation?: string;
17 }
Added src/types/requestTypes.ts +53 -0
@@ -0,0 +1,53 @@
1 import {
2 IBooster,
3 IChallengeProgress,
4 IConsumable,
5 ICrewShipSalvagedWeaponSkin,
6 IMiscItem,
7 IMission,
8 IRawUpgrade
9 } from "./inventoryTypes/inventoryTypes";
10 import { IWeaponDatabase } from "./inventoryTypes/weaponTypes";
11 import { ISuitDatabase } from "./inventoryTypes/SuitTypes";
12
13 interface IArtifactsRequest {
14 Upgrade: ICrewShipSalvagedWeaponSkin;
15 LevelDiff: number;
16 Cost: number;
17 FusionPointCost: number;
18 }
19
20 interface IMissionInventoryUpdateRequest {
21 rewardsMultiplier?: number;
22 ActiveBoosters?: IBooster[];
23 LongGuns?: IWeaponDatabase[];
24 Pistols?: IWeaponDatabase[];
25 Suits?: ISuitDatabase[];
26 Melee?: IWeaponDatabase[];
27 RawUpgrades?: IRawUpgrade[];
28 MiscItems?: IMiscItem[];
29 Consumables?: IConsumable[];
30 Recipes?: IConsumable[];
31 RegularCredits?: number;
32 ChallengeProgress?: IChallengeProgress[];
33 RewardInfo?: IMissionInventoryUpdateRequestRewardInfo;
34 FusionPoints?: number;
35 Missions?: IMission;
36 }
37
38 interface IMissionInventoryUpdateRequestRewardInfo {
39 node: string;
40 rewardTier?: number;
41 nightmareMode?: boolean;
42 useVaultManifest?: boolean;
43 EnemyCachesFound?: number;
44 toxinOk?: boolean;
45 lostTargetWave?: number;
46 defenseTargetCount?: number;
47 EOM_AFK?: number;
48 rewardQualifications?: string;
49 PurgatoryRewardQualifications?: string;
50 rewardSeed?: number;
51 }
52
53 export { IArtifactsRequest, IMissionInventoryUpdateRequest };