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

XFESpaceNinjaServer

A simple server for a small space ninja game

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

XFEstudio/XFESpaceNinjaServer

chore: convert dates & oids in profile viewing data for pre-U19.5 (#3921)

Closes #3915 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3921 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

74e06da5
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

2 个文件 +80 -44
Modified src/controllers/api/inventoryController.ts +8 -16
@@ -889,25 +889,17 @@ export const getInventoryResponse = async (
889 889 if (category in inventoryResponse.LoadOutPresets) {
890 890 for (const item of inventoryResponse.LoadOutPresets[category]) {
891 891 toLegacyOid(item.ItemId);
892 if (item.s) {
893 if (item.s.ItemId) {
894 toLegacyOid(item.s.ItemId);
895 }
892 if (item.s?.ItemId) {
893 toLegacyOid(item.s.ItemId);
896 894 }
897 if (item.l) {
898 if (item.l.ItemId) {
899 toLegacyOid(item.l.ItemId);
900 }
895 if (item.l?.ItemId) {
896 toLegacyOid(item.l.ItemId);
901 897 }
902 if (item.p) {
903 if (item.p.ItemId) {
904 toLegacyOid(item.p.ItemId);
905 }
898 if (item.p?.ItemId) {
899 toLegacyOid(item.p.ItemId);
906 900 }
907 if (item.m) {
908 if (item.m.ItemId) {
909 toLegacyOid(item.m.ItemId);
910 }
901 if (item.m?.ItemId) {
902 toLegacyOid(item.m.ItemId);
911 903 }
912 904 }
913 905 }
Modified src/controllers/dynamic/getProfileViewingDataController.ts +72 -28
@@ -1,4 +1,4 @@
1 import { fromOid, toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
1 import { fromOid, toLegacyOid, toMongoDate2, toOid2, version_compare } from "../../helpers/inventoryHelpers.ts";
2 2 import type { TGuildDatabaseDocument } from "../../models/guildModel.ts";
3 3 import { Guild, GuildMember } from "../../models/guildModel.ts";
4 4 import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
@@ -7,7 +7,7 @@ import { Loadout } from "../../models/inventoryModels/loadoutModel.ts";
7 7 import { Account } from "../../models/loginModel.ts";
8 8 import { Stats } from "../../models/statsModel.ts";
9 9 import { allDailyAffiliationKeys } from "../../services/inventoryService.ts";
10 import type { IMongoDate, IOid } from "../../types/commonTypes.ts";
10 import type { IMongoDateWithLegacySupport, IOid, IOidWithLegacySupport } from "../../types/commonTypes.ts";
11 11 import type {
12 12 IAffiliation,
13 13 IAlignment,
@@ -28,6 +28,8 @@ import type { IEquipmentClient } from "../../types/equipmentTypes.ts";
28 28 import type { ILoadoutConfigClient } from "../../types/saveLoadoutTypes.ts";
29 29 import { skinLookupTable } from "../../helpers/skinLookupTable.ts";
30 30 import type { ITechProjectClient } from "../../types/guildTypes.ts";
31 import { getAccountForRequest } from "../../services/loginService.ts";
32 import gameToBuildVersion from "../../constants/gameToBuildVersion.ts";
31 33
32 34 export const getProfileViewingDataGetController: RequestHandler = async (req, res) => {
33 35 if (req.query.playerId) {
@@ -53,8 +55,17 @@ export const getProfileViewingDataGetController: RequestHandler = async (req, re
53 55 type IGetProfileViewingDataRequest = { AccountId: string } | { GuildId: string };
54 56 export const getProfileViewingDataPostController: RequestHandler = async (req, res) => {
55 57 const payload = getJSONfromString<IGetProfileViewingDataRequest>(String(req.body));
56 if ("GuildId" in payload) {
57 const data = await getProfileViewingDataByGuildId(payload.GuildId);
58 if ("AccountId" in payload) {
59 const account = await getAccountForRequest(req);
60 const data = await getProfileViewingDataByPlayerId(payload.AccountId, account.BuildLabel);
61 if (data) {
62 res.json(data);
63 } else {
64 res.status(409).send("Could not find requested account");
65 }
66 } else if ("GuildId" in payload) {
67 const account = await getAccountForRequest(req);
68 const data = await getProfileViewingDataByGuildId(payload.GuildId, account.BuildLabel);
58 69 if (data) {
59 70 res.json(data);
60 71 } else {
@@ -62,7 +73,7 @@ export const getProfileViewingDataPostController: RequestHandler = async (req, r
62 73 }
63 74 } else {
64 75 const playerId = req.query.playerId as string; // companion app sends a POST request should be handled like a GET request
65 const data = await getProfileViewingDataByPlayerId(playerId ? playerId : payload.AccountId);
76 const data = await getProfileViewingDataByPlayerId(playerId);
66 77 if (data) {
67 78 res.json(data);
68 79 } else {
@@ -71,7 +82,10 @@ export const getProfileViewingDataPostController: RequestHandler = async (req, r
71 82 }
72 83 };
73 84
74 export const getProfileViewingDataByPlayerId = async (playerId: string): Promise<IProfileViewingData | undefined> => {
85 const getProfileViewingDataByPlayerId = async (
86 playerId: string,
87 buildLabel?: string
88 ): Promise<IProfileViewingData | undefined> => {
75 89 const account = await Account.findById(playerId, "DisplayName");
76 90 if (!account) {
77 91 return;
@@ -79,7 +93,7 @@ export const getProfileViewingDataByPlayerId = async (playerId: string): Promise
79 93 const inventory = (await Inventory.findOne({ accountOwnerId: account._id }))!;
80 94
81 95 const result: IPlayerProfileViewingDataResult = {
82 AccountId: toOid(account._id),
96 AccountId: toOid2(account._id, buildLabel),
83 97 DisplayName: account.DisplayName,
84 98 PlayerLevel: (inventory.spoofMasteryRank ?? -1) !== -1 ? inventory.spoofMasteryRank! : inventory.PlayerLevel,
85 99 LoadOutInventory: {
@@ -91,7 +105,7 @@ export const getProfileViewingDataByPlayerId = async (playerId: string): Promise
91 105 DeathMarks: inventory.DeathMarks,
92 106 Harvestable: inventory.Harvestable,
93 107 DeathSquadable: inventory.DeathSquadable,
94 Created: toMongoDate(inventory.Created),
108 Created: toMongoDate2(inventory.Created, buildLabel),
95 109 TitleType: inventory.TitleType,
96 110 MigratedToConsole: false,
97 111 Missions: inventory.Missions,
@@ -106,10 +120,10 @@ export const getProfileViewingDataByPlayerId = async (playerId: string): Promise
106 120 Partner: inventory.Partner,
107 121 Accolades: inventory.Accolades
108 122 };
109 await populateLoadout(inventory, result);
123 await populateLoadout(inventory, result, buildLabel);
110 124 if (inventory.GuildId) {
111 125 const guild = (await Guild.findById(inventory.GuildId, "Name Tier XP Class Emblem"))!;
112 populateGuild(guild, result);
126 populateGuild(guild, result, buildLabel);
113 127 }
114 128 for (const key of allDailyAffiliationKeys) {
115 129 result[key] = inventory[key];
@@ -124,7 +138,10 @@ export const getProfileViewingDataByPlayerId = async (playerId: string): Promise
124 138 };
125 139 };
126 140
127 export const getProfileViewingDataByGuildId = async (guildId: string): Promise<IProfileViewingData | undefined> => {
141 export const getProfileViewingDataByGuildId = async (
142 guildId: string,
143 buildLabel?: string
144 ): Promise<IProfileViewingData | undefined> => {
128 145 const guild = await Guild.findById(guildId, "Name Tier XP Class Emblem TechProjects ClaimedXP");
129 146 if (!guild) {
130 147 return;
@@ -141,7 +158,7 @@ export const getProfileViewingDataByGuildId = async (guildId: string): Promise<I
141 158 )
142 159 ]);
143 160 const result: IPlayerProfileViewingDataResult = {
144 AccountId: toOid(account!._id),
161 AccountId: toOid2(account!._id, buildLabel),
145 162 DisplayName: account!.DisplayName,
146 163 PlayerLevel:
147 164 (inventory!.spoofMasteryRank ?? -1) !== -1 ? inventory!.spoofMasteryRank! : inventory!.PlayerLevel,
@@ -150,10 +167,10 @@ export const getProfileViewingDataByGuildId = async (guildId: string): Promise<I
150 167 XPInfo: inventory!.XPInfo
151 168 }
152 169 };
153 await populateLoadout(inventory!, result);
170 await populateLoadout(inventory!, result, buildLabel);
154 171 results.push(result);
155 172 }
156 populateGuild(guild, results[0]);
173 populateGuild(guild, results[0], buildLabel);
157 174
158 175 const combinedStats: IStatsClient = {};
159 176 const statsArr = await Stats.find({ accountOwnerId: { $in: members.map(x => x.accountId) } }).lean(); // need this as POJO so Object.entries works as expected
@@ -212,7 +229,7 @@ export const getProfileViewingDataByGuildId = async (guildId: string): Promise<I
212 229 TechProjects:
213 230 guild.TechProjects?.map(x => ({
214 231 ...x,
215 CompletionDate: x.CompletionDate ? toMongoDate(x.CompletionDate) : undefined
232 CompletionDate: x.CompletionDate ? toMongoDate2(x.CompletionDate, buildLabel) : undefined
216 233 })) ?? [],
217 234 XpComponents: xpComponents,
218 235 //XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
@@ -229,7 +246,7 @@ interface IProfileViewingData {
229 246 }
230 247
231 248 interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations>, IInventoryAccolades {
232 AccountId: IOid;
249 AccountId: IOidWithLegacySupport;
233 250 DisplayName: string;
234 251 PlayerLevel: number;
235 252 LoadOutPreset?: Omit<ILoadoutConfigClient, "ItemId"> & { ItemId?: IOid };
@@ -241,7 +258,7 @@ interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations>, I
241 258 Melee?: IEquipmentClient[];
242 259 XPInfo: ITypeXPItem[];
243 260 };
244 GuildId?: IOid;
261 GuildId?: IOidWithLegacySupport;
245 262 GuildName?: string;
246 263 GuildTier?: number;
247 264 GuildXp?: number;
@@ -252,7 +269,7 @@ interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations>, I
252 269 DeathMarks?: string[];
253 270 Harvestable?: boolean;
254 271 DeathSquadable?: boolean;
255 Created?: IMongoDate;
272 Created?: IMongoDateWithLegacySupport;
256 273 TitleType?: string;
257 274 MigratedToConsole?: boolean;
258 275 Missions?: IMission[];
@@ -263,7 +280,7 @@ interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations>, I
263 280 }
264 281
265 282 interface IXPComponentClient {
266 _id?: IOid;
283 _id?: IOidWithLegacySupport;
267 284 StoreTypeName: string;
268 285 TypeName?: string;
269 286 PurchaseQuantity?: number;
@@ -282,11 +299,13 @@ interface IXPComponentClient {
282 299 locTags?: Record<string, string>;
283 300 }
284 301
285 const resolveAndCollectSkins = (
302 const processLoadoutEquipment = (
286 303 inventory: TInventoryDatabaseDocument,
287 304 skins: Set<string>,
288 item: IEquipmentClient
305 item: IEquipmentClient,
306 buildLabel: string | undefined
289 307 ): void => {
308 // Resolve and collect skins
290 309 for (const config of item.Configs) {
291 310 if (config.Skins) {
292 311 for (let i = 0; i != config.Skins.length; ++i) {
@@ -307,42 +326,63 @@ const resolveAndCollectSkins = (
307 326 }
308 327 }
309 328 }
329
330 if (buildLabel && version_compare(buildLabel, gameToBuildVersion["19.5.0"]) <= 0) {
331 toLegacyOid(item.ItemId);
332 }
310 333 };
311 334
312 335 const populateLoadout = async (
313 336 inventory: TInventoryDatabaseDocument,
314 result: IPlayerProfileViewingDataResult
337 result: IPlayerProfileViewingDataResult,
338 buildLabel: string | undefined
315 339 ): Promise<void> => {
316 340 if (inventory.CurrentLoadOutIds.length) {
317 341 const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
342
318 343 result.LoadOutPreset = loadout.NORMAL.id(
319 344 inventory.CurrentLoadOutIds[LoadoutIndex.NORMAL]
320 345 )!.toJSON<ILoadoutConfigClient>();
321 346 result.LoadOutPreset.ItemId = undefined;
347 if (buildLabel && version_compare(buildLabel, gameToBuildVersion["19.5.0"]) <= 0) {
348 if (result.LoadOutPreset.s?.ItemId) {
349 toLegacyOid(result.LoadOutPreset.s.ItemId);
350 }
351 if (result.LoadOutPreset.l?.ItemId) {
352 toLegacyOid(result.LoadOutPreset.l.ItemId);
353 }
354 if (result.LoadOutPreset.p?.ItemId) {
355 toLegacyOid(result.LoadOutPreset.p.ItemId);
356 }
357 if (result.LoadOutPreset.m?.ItemId) {
358 toLegacyOid(result.LoadOutPreset.m.ItemId);
359 }
360 }
361
322 362 const skins = new Set<string>();
323 363 if (result.LoadOutPreset.s?.ItemId) {
324 364 result.LoadOutInventory.Suits = [
325 365 inventory.Suits.id(fromOid(result.LoadOutPreset.s.ItemId))!.toJSON<IEquipmentClient>()
326 366 ];
327 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Suits[0]);
367 processLoadoutEquipment(inventory, skins, result.LoadOutInventory.Suits[0], buildLabel);
328 368 }
329 369 if (result.LoadOutPreset.p?.ItemId) {
330 370 result.LoadOutInventory.Pistols = [
331 371 inventory.Pistols.id(fromOid(result.LoadOutPreset.p.ItemId))!.toJSON<IEquipmentClient>()
332 372 ];
333 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Pistols[0]);
373 processLoadoutEquipment(inventory, skins, result.LoadOutInventory.Pistols[0], buildLabel);
334 374 }
335 375 if (result.LoadOutPreset.l?.ItemId) {
336 376 result.LoadOutInventory.LongGuns = [
337 377 inventory.LongGuns.id(fromOid(result.LoadOutPreset.l.ItemId))!.toJSON<IEquipmentClient>()
338 378 ];
339 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.LongGuns[0]);
379 processLoadoutEquipment(inventory, skins, result.LoadOutInventory.LongGuns[0], buildLabel);
340 380 }
341 381 if (result.LoadOutPreset.m?.ItemId) {
342 382 result.LoadOutInventory.Melee = [
343 383 inventory.Melee.id(fromOid(result.LoadOutPreset.m.ItemId))!.toJSON<IEquipmentClient>()
344 384 ];
345 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Melee[0]);
385 processLoadoutEquipment(inventory, skins, result.LoadOutInventory.Melee[0], buildLabel);
346 386 }
347 387 for (const skin of skins) {
348 388 result.LoadOutInventory.WeaponSkins.push({ ItemType: skin });
@@ -350,8 +390,12 @@ const populateLoadout = async (
350 390 }
351 391 };
352 392
353 const populateGuild = (guild: TGuildDatabaseDocument, result: IPlayerProfileViewingDataResult): void => {
354 result.GuildId = toOid(guild._id);
393 const populateGuild = (
394 guild: TGuildDatabaseDocument,
395 result: IPlayerProfileViewingDataResult,
396 buildLabel: string | undefined
397 ): void => {
398 result.GuildId = toOid2(guild._id, buildLabel);
355 399 result.GuildName = guild.Name;
356 400 result.GuildTier = guild.Tier;
357 401 result.GuildXp = guild.XP;