返回提交历史
Modified
.gitignore
+1
-0
Modified
src/controllers/api/missionInventoryUpdateController.ts
+56
-1
Added
src/controllers/stats/viewController.ts
+7
-0
Modified
src/models/inventoryModel.ts
+10
-2
Modified
src/routes/stats.ts
+4
-0
Modified
src/services/inventoryService.ts
+100
-1
Modified
src/services/purchaseService.ts
+31
-8
Modified
src/types/inventoryTypes/SuitTypes.ts
+6
-2
Modified
src/types/inventoryTypes/inventoryTypes.ts
+11
-1
Modified
src/types/inventoryTypes/weaponTypes.ts
+2
-0
Added
src/types/missionInventoryUpdateType.ts
+64
-0
XFEstudio/SpaceNinjaServer
Mission rewards save (#46)
db0aaffb
代码差异
11 个文件
+292
-15
@@ -4,3 +4,4 @@
4
4
/.env
5
5
/static/data/*.bin
6
6
yarn.lock
7
/tmp
@@ -1,6 +1,61 @@
1
1
import { RequestHandler } from "express";
2
import { missionInventoryUpdate } from "@/src/services/inventoryService";
3
import { MissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType";
4
/*
5
- [ ] crossPlaySetting
6
- [ ] rewardsMultiplier
7
- [ ] ActiveBoosters
8
- [x] LongGuns
9
- [x] Pistols
10
- [x] Suits
11
- [x] Melee
12
- [x] RawUpgrades
13
- [x] MiscItems
14
- [x] RegularCredits
15
- [ ] RandomUpgradesIdentified
16
- [ ] MissionFailed
17
- [ ] MissionStatus
18
- [ ] CurrentLoadOutIds
19
- [ ] AliveTime
20
- [ ] MissionTime
21
- [ ] Missions
22
- [ ] CompletedAlerts
23
- [ ] LastRegionPlayed
24
- [ ] GameModeId
25
- [ ] hosts
26
- [x] ChallengeProgress
27
- [ ] SeasonChallengeHistory
28
- [ ] PS
29
- [ ] ActiveDojoColorResearch
30
- [ ] RewardInfo
31
- [ ] ReceivedCeremonyMsg
32
- [ ] LastCeremonyResetDate
33
- [ ] MissionPTS
34
- [ ] RepHash
35
- [ ] EndOfMatchUpload
36
- [ ] ObjectiveReached
37
- [ ] FpsAvg
38
- [ ] FpsMin
39
- [ ] FpsMax
40
- [ ] FpsSamples
41
*/
2
42
3
const missionInventoryUpdateController: RequestHandler = (_req, res) => {
43
// eslint-disable-next-line @typescript-eslint/no-misused-promises
44
const missionInventoryUpdateController: RequestHandler = async (req, res) => {
45
const [data] = String(req.body).split("\n");
46
const id = req.query.accountId as string;
47
48
// TODO - salt check
49
50
try {
51
const parsedData = JSON.parse(data) as MissionInventoryUpdate;
52
if (typeof parsedData !== "object" || parsedData === null) throw new Error("Invalid data format");
53
await missionInventoryUpdate(parsedData, id);
54
} catch (err) {
55
console.error("Error parsing JSON data:", err);
56
}
57
58
// TODO - get original response
4
59
res.json({});
5
60
};
6
61
@@ -0,0 +1,7 @@
1
import { RequestHandler } from "express";
2
3
const viewController: RequestHandler = (_req, res) => {
4
res.json({});
5
};
6
7
export { viewController };
@@ -1,5 +1,5 @@
1
1
import { Model, Schema, Types, model } from "mongoose";
2
import { FlavourItem, IInventoryDatabase } from "../types/inventoryTypes/inventoryTypes";
2
import { FlavourItem, RawUpgrade, MiscItem, IInventoryDatabase, Booster } from "../types/inventoryTypes/inventoryTypes";
3
3
import { Oid } from "../types/commonTypes";
4
4
import { ISuitDatabase, ISuitDocument } from "@/src/types/inventoryTypes/SuitTypes";
5
5
import { IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
@@ -66,6 +66,11 @@ const WeaponSchema = new Schema({
66
66
UnlockLevel: Number
67
67
});
68
68
69
const BoosterSchema = new Schema({
70
ExpiryDate: Number,
71
ItemType: String
72
});
73
69
74
WeaponSchema.set("toJSON", {
70
75
transform(_document, returnedObject) {
71
76
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
@@ -213,7 +218,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
213
218
LoreFragmentScans: [Schema.Types.Mixed],
214
219
EquippedEmotes: [String],
215
220
PendingTrades: [Schema.Types.Mixed],
216
Boosters: [Schema.Types.Mixed],
221
Boosters: [BoosterSchema],
217
222
ActiveDojoColorResearch: String,
218
223
SentientSpawnChanceBoosters: Schema.Types.Mixed,
219
224
Affiliations: [Schema.Types.Mixed],
@@ -334,6 +339,9 @@ type InventoryDocumentProps = {
334
339
Pistols: Types.DocumentArray<IWeaponDatabase>;
335
340
Melee: Types.DocumentArray<IWeaponDatabase>;
336
341
FlavourItems: Types.DocumentArray<FlavourItem>;
342
RawUpgrades: Types.DocumentArray<RawUpgrade>;
343
MiscItems: Types.DocumentArray<MiscItem>;
344
Boosters: Types.DocumentArray<Booster>;
337
345
};
338
346
339
347
type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
@@ -1,7 +1,11 @@
1
import { viewController } from "../controllers/api/viewController";
1
2
import { uploadController } from "@/src/controllers/stats/uploadController";
3
2
4
import express from "express";
3
5
4
6
const statsRouter = express.Router();
5
7
8
statsRouter.get("/view.php", viewController);
6
9
statsRouter.post("/upload.php", uploadController);
10
7
11
export { statsRouter };
@@ -5,7 +5,13 @@ import { Types } from "mongoose";
5
5
import { ISuitResponse } from "@/src/types/inventoryTypes/SuitTypes";
6
6
import { SlotType } from "@/src/types/purchaseTypes";
7
7
import { IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes";
8
import { FlavourItem } from "@/src/types/inventoryTypes/inventoryTypes";
8
import { ChallengeProgress, FlavourItem, IInventoryDatabaseDocument } from "@/src/types/inventoryTypes/inventoryTypes";
9
import {
10
MissionInventoryUpdate,
11
MissionInventoryUpdateCard,
12
MissionInventoryUpdateGear,
13
MissionInventoryUpdateItem
14
} from "../types/missionInventoryUpdateType";
9
15
10
16
const createInventory = async (accountOwnerId: Types.ObjectId) => {
11
17
try {
@@ -106,4 +112,97 @@ export const addCustomization = async (customizatonName: string, accountId: stri
106
112
return changedInventory.FlavourItems[flavourItemIndex].toJSON(); //mongoose bug forces as FlavourItem
107
113
};
108
114
115
const addGearExpByCategory = (
116
inventory: IInventoryDatabaseDocument,
117
gearArray: MissionInventoryUpdateGear[] | undefined,
118
categoryName: "Pistols" | "LongGuns" | "Melee" | "Suits"
119
) => {
120
const category = inventory[categoryName];
121
122
gearArray?.forEach(({ ItemId, XP }) => {
123
const itemIndex = category.findIndex(i => i._id?.equals(ItemId.$oid));
124
const item = category[itemIndex];
125
126
if (itemIndex !== -1 && item.XP != undefined) {
127
item.XP += XP;
128
inventory.markModified(`${categoryName}.${itemIndex}.XP`);
129
}
130
});
131
};
132
133
const addItemsByCategory = (
134
inventory: IInventoryDatabaseDocument,
135
itemsArray: (MissionInventoryUpdateItem | MissionInventoryUpdateCard)[] | undefined,
136
categoryName: "RawUpgrades" | "MiscItems"
137
) => {
138
const category = inventory[categoryName];
139
140
itemsArray?.forEach(({ ItemCount, ItemType }) => {
141
const itemIndex = category.findIndex(i => i.ItemType === ItemType);
142
143
if (itemIndex !== -1) {
144
category[itemIndex].ItemCount += ItemCount;
145
inventory.markModified(`${categoryName}.${itemIndex}.ItemCount`);
146
} else {
147
category.push({ ItemCount, ItemType });
148
}
149
});
150
};
151
152
const addChallenges = (inventory: IInventoryDatabaseDocument, itemsArray: ChallengeProgress[] | undefined) => {
153
const category = inventory.ChallengeProgress;
154
155
itemsArray?.forEach(({ Name, Progress }) => {
156
const itemIndex = category.findIndex(i => i.Name === Name);
157
158
if (itemIndex !== -1) {
159
category[itemIndex].Progress += Progress;
160
inventory.markModified(`ChallengeProgress.${itemIndex}.ItemCount`);
161
} else {
162
category.push({ Name, Progress });
163
}
164
});
165
};
166
167
const gearKeys = ["Suits", "Pistols", "LongGuns", "Melee"] as const;
168
type GearKeysType = (typeof gearKeys)[number];
169
170
export const missionInventoryUpdate = async (data: MissionInventoryUpdate, accountId: string): Promise<void> => {
171
const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress } = data;
172
const inventory = await getInventory(accountId);
173
174
// TODO - multipliers logic
175
// credits
176
inventory.RegularCredits += RegularCredits || 0;
177
178
// gear exp
179
gearKeys.forEach((key: GearKeysType) => addGearExpByCategory(inventory, data[key], key));
180
181
// other
182
addItemsByCategory(inventory, RawUpgrades, "RawUpgrades"); // TODO - check mods fusion level
183
addItemsByCategory(inventory, MiscItems, "MiscItems");
184
addChallenges(inventory, ChallengeProgress);
185
186
await inventory.save();
187
};
188
189
export const addBooster = async (ItemType: string, time: number, accountId: string): Promise<void> => {
190
const currentTime = Math.floor(Date.now() / 1000) - 129600; // booster time getting more without 129600, probably defence logic, idk
191
192
const inventory = await getInventory(accountId);
193
const { Boosters } = inventory;
194
195
const itemIndex = Boosters.findIndex(i => i.ItemType === ItemType);
196
197
if (itemIndex !== -1) {
198
const existingBooster = Boosters[itemIndex];
199
existingBooster.ExpiryDate = Math.max(existingBooster.ExpiryDate, currentTime) + time;
200
inventory.markModified(`Boosters.${itemIndex}.ExpiryDate`);
201
} else {
202
Boosters.push({ ItemType, ExpiryDate: currentTime + time }) - 1;
203
}
204
205
await inventory.save();
206
};
207
109
208
export { createInventory, addPowerSuit };
@@ -1,13 +1,7 @@
1
1
import { getWeaponType } from "@/src/helpers/purchaseHelpers";
2
2
import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
3
import {
4
addCustomization,
5
addPowerSuit,
6
addWeapon,
7
updateCurrency,
8
updateSlots
9
} from "@/src/services/inventoryService";
10
import { IPurchaseRequest, IPurchaseResponse, SlotType } from "@/src/types/purchaseTypes";
3
import { addBooster, addCustomization, addPowerSuit, addWeapon, updateSlots } from "@/src/services/inventoryService";
4
import { IPurchaseRequest, SlotType } from "@/src/types/purchaseTypes";
11
5
12
6
export const getStoreItemCategory = (storeItem: string) => {
13
7
const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/");
@@ -41,6 +35,9 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI
41
35
case "Types":
42
36
purchaseResponse = await handleTypesPurchase(internalName, accountId);
43
37
break;
38
case "Boosters":
39
purchaseResponse = await handleBoostersPurchase(internalName, accountId);
40
break;
44
41
45
42
default:
46
43
throw new Error(`unknown store category: ${storeCategory} not implemented or new`);
@@ -114,3 +111,29 @@ const handleSuitCustomizationsPurchase = async (customizationName: string, accou
114
111
}
115
112
};
116
113
};
114
115
const boosterCollection = [
116
"/Lotus/Types/Boosters/ResourceAmountBooster",
117
"/Lotus/Types/Boosters/AffinityBooster",
118
"/Lotus/Types/Boosters/ResourceDropChanceBooster",
119
"/Lotus/Types/Boosters/CreditBooster"
120
];
121
122
const handleBoostersPurchase = async (boosterStoreName: string, accountId: string) => {
123
const match = boosterStoreName.match(/(\d+)Day/);
124
if (!match) return;
125
126
const extractedDigit = Number(match[1]);
127
const ItemType = boosterCollection.find(i =>
128
boosterStoreName.includes(i.split("/").pop()!.replace("Booster", ""))
129
)!;
130
const ExpiryDate = extractedDigit * 86400;
131
132
await addBooster(ItemType, ExpiryDate, accountId);
133
134
return {
135
InventoryChanges: {
136
Boosters: [{ ItemType, ExpiryDate }]
137
}
138
};
139
};
@@ -1,8 +1,11 @@
1
1
import { Oid } from "@/src/types/commonTypes";
2
2
import { AbilityOverride, Color, Polarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
3
import { Document } from "mongoose";
3
import { Document, Types } from "mongoose";
4
4
5
export interface ISuitDocument extends ISuitResponse, Document {}
5
// export interface ISuitDocument extends ISuitResponse, Document {}
6
export interface ISuitDocument extends Document, ISuitResponse {
7
_id: Types.ObjectId;
8
}
6
9
7
10
export interface ISuitResponse extends ISuitDatabase {
8
11
ItemId: Oid;
@@ -20,6 +23,7 @@ export interface ISuitDatabase {
20
23
ModSlotPurchases?: number;
21
24
FocusLens?: string;
22
25
UnlockLevel?: number;
26
_id: Types.ObjectId;
23
27
}
24
28
25
29
export interface SuitConfig {
@@ -377,6 +377,16 @@ export interface FlavourItem {
377
377
ItemType: string;
378
378
}
379
379
380
export interface RawUpgrade {
381
ItemCount: number;
382
ItemType: string;
383
}
384
385
export interface MiscItem {
386
ItemCount: number;
387
ItemType: string;
388
}
389
380
390
export interface CrewshipWeapon {
381
391
PILOT: Pilot;
382
392
PORT_GUNS: PortGuns;
@@ -919,7 +929,7 @@ export interface Progress {
919
929
920
930
export interface RawUpgrade {
921
931
ItemCount: number;
922
LastAdded: Oid;
932
LastAdded?: Oid;
923
933
ItemType: string;
924
934
}
925
935
@@ -1,5 +1,6 @@
1
1
import { Oid } from "@/src/types/commonTypes";
2
2
import { Color, Polarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
3
import { Types } from "mongoose";
3
4
4
5
export interface IWeaponResponse extends IWeaponDatabase {
5
6
ItemId: Oid;
@@ -20,6 +21,7 @@ export interface IWeaponDatabase {
20
21
ItemName?: string;
21
22
ModularParts?: string[];
22
23
UnlockLevel?: number;
24
_id?: Types.ObjectId;
23
25
}
24
26
25
27
export interface WeaponConfig {
@@ -0,0 +1,64 @@
1
interface MongooseId{
2
$oid: string;
3
}
4
5
interface ExpireDate{
6
$date: {
7
$numberLong: string;
8
}
9
}
10
11
export interface MissionInventoryUpdateGear{
12
ItemType: string;
13
ItemName: string;
14
ItemId: MongooseId;
15
XP: number;
16
UpgradeVer: number;
17
Features: number;
18
Polarized: number;
19
CustomizationSlotPurchases: number;
20
ModSlotPurchases: number;
21
FocusLens: string;
22
Expiry: ExpireDate;
23
Polarity: any[];
24
Configs: any[];
25
ModularParts: any[];
26
SkillTree: string;
27
UpgradeType: string;
28
UpgradeFingerprint: string;
29
OffensiveUpgrade: string;
30
DefensiveUpgrade: string;
31
UpgradesExpiry: ExpireDate;
32
ArchonCrystalUpgrades: any[];
33
}
34
35
export interface MissionInventoryUpdateItem{
36
ItemCount: number;
37
ItemType: string;
38
}
39
40
export interface MissionInventoryUpdateCard extends MissionInventoryUpdateItem{
41
ItemId: MongooseId;
42
UpgradeFingerprint: string;
43
PendingRerollFingerprint: string;
44
LastAdded: MongooseId;
45
}
46
47
interface MissionInventoryUpdateChallange{
48
Name: string;
49
Progress: number;
50
Completed: any[];
51
}
52
53
export interface MissionInventoryUpdate{
54
rewardsMultiplier?: number;
55
ActiveBoosters?: any[];
56
LongGuns?: MissionInventoryUpdateGear[];
57
Pistols?: MissionInventoryUpdateGear[];
58
Suits?: MissionInventoryUpdateGear[];
59
Melee?: MissionInventoryUpdateGear[];
60
RawUpgrades?: MissionInventoryUpdateCard[];
61
MiscItems?: MissionInventoryUpdateItem[];
62
RegularCredits?: number;
63
ChallengeProgress?: MissionInventoryUpdateChallange[];
64
}