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

feat: getProfileViewingData for players (#1258)

Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1258

3b16ff9b
Sainan <sainan@calamity.inc>
提交于

代码差异

9 个文件 +192 -6
Modified src/app.ts +1 -0
@@ -32,6 +32,7 @@ app.use(requestLogger);
32 32 app.use("/api", apiRouter);
33 33 app.use("/", cacheRouter);
34 34 app.use("/custom", customRouter);
35 app.use("/dynamic", dynamicController);
35 36 app.use("/:id/dynamic", dynamicController);
36 37 app.use("/pay", payRouter);
37 38 app.use("/stats", statsRouter);
Modified src/controllers/api/inventoryController.ts +1 -1
@@ -297,7 +297,7 @@ const resourceGetParent = (resourceName: string): string | undefined => {
297 297 };
298 298
299 299 // This is FNV1a-32 except operating under modulus 2^31 because JavaScript is stinky and likes producing negative integers out of nowhere.
300 const catBreadHash = (name: string): number => {
300 export const catBreadHash = (name: string): number => {
301 301 let hash = 2166136261;
302 302 for (let i = 0; i != name.length; ++i) {
303 303 hash = (hash ^ name.charCodeAt(i)) & 0x7fffffff;
Added src/controllers/dynamic/getProfileViewingDataController.ts +183 -0
@@ -0,0 +1,183 @@
1 import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
2 import { Guild } from "@/src/models/guildModel";
3 import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
4 import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
5 import { Account } from "@/src/models/loginModel";
6 import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
7 import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
8 import { IMongoDate, IOid } from "@/src/types/commonTypes";
9 import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
10 import {
11 IAffiliation,
12 IAlignment,
13 IChallengeProgress,
14 IDailyAffiliations,
15 ILoadoutConfigClient,
16 IMission,
17 IPlayerSkills,
18 ITypeXPItem
19 } from "@/src/types/inventoryTypes/inventoryTypes";
20 import { RequestHandler } from "express";
21 import { catBreadHash } from "../api/inventoryController";
22 import { ExportCustoms } from "warframe-public-export-plus";
23
24 export const getProfileViewingDataController: RequestHandler = async (req, res) => {
25 if (!req.query.playerId) {
26 res.status(400).end();
27 return;
28 }
29 const account = await Account.findOne({ _id: req.query.playerId as string }, "DisplayName");
30 if (!account) {
31 res.status(400).send("No account or guild ID specified");
32 return;
33 }
34 const inventory = (await Inventory.findOne({ accountOwnerId: account._id }))!;
35 const loadout = (await Loadout.findOne({ _id: inventory.LoadOutPresets }, "NORMAL"))!;
36
37 const result: IPlayerProfileViewingDataResult = {
38 AccountId: toOid(account._id),
39 DisplayName: account.DisplayName,
40 PlayerLevel: inventory.PlayerLevel,
41 LoadOutInventory: {
42 WeaponSkins: [],
43 XPInfo: inventory.XPInfo
44 },
45 PlayerSkills: inventory.PlayerSkills,
46 ChallengeProgress: inventory.ChallengeProgress,
47 DeathMarks: inventory.DeathMarks,
48 Harvestable: inventory.Harvestable,
49 DeathSquadable: inventory.DeathSquadable,
50 Created: toMongoDate(inventory.Created),
51 MigratedToConsole: false,
52 Missions: inventory.Missions,
53 Affiliations: inventory.Affiliations,
54 DailyFocus: inventory.DailyFocus,
55 Wishlist: inventory.Wishlist,
56 Alignment: inventory.Alignment
57 };
58 if (inventory.CurrentLoadOutIds.length) {
59 result.LoadOutPreset = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!.toJSON<ILoadoutConfigClient>();
60 result.LoadOutPreset.ItemId = undefined;
61 const skins = new Set<string>();
62 if (result.LoadOutPreset.s) {
63 result.LoadOutInventory.Suits = [
64 inventory.Suits.id(result.LoadOutPreset.s.ItemId.$oid)!.toJSON<IEquipmentClient>()
65 ];
66 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Suits[0]);
67 }
68 if (result.LoadOutPreset.p) {
69 result.LoadOutInventory.Pistols = [
70 inventory.Pistols.id(result.LoadOutPreset.p.ItemId.$oid)!.toJSON<IEquipmentClient>()
71 ];
72 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Pistols[0]);
73 }
74 if (result.LoadOutPreset.l) {
75 result.LoadOutInventory.LongGuns = [
76 inventory.LongGuns.id(result.LoadOutPreset.l.ItemId.$oid)!.toJSON<IEquipmentClient>()
77 ];
78 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.LongGuns[0]);
79 }
80 if (result.LoadOutPreset.m) {
81 result.LoadOutInventory.Melee = [
82 inventory.Melee.id(result.LoadOutPreset.m.ItemId.$oid)!.toJSON<IEquipmentClient>()
83 ];
84 resolveAndCollectSkins(inventory, skins, result.LoadOutInventory.Melee[0]);
85 }
86 for (const skin of skins) {
87 result.LoadOutInventory.WeaponSkins.push({ ItemType: skin });
88 }
89 }
90 if (inventory.GuildId) {
91 const guild = (await Guild.findOne({ _id: inventory.GuildId }, "Name Tier XP Class"))!;
92 result.GuildId = toOid(inventory.GuildId);
93 result.GuildName = guild.Name;
94 result.GuildTier = guild.Tier;
95 result.GuildXp = guild.XP;
96 result.GuildClass = guild.Class;
97 result.GuildEmblem = false;
98 }
99 for (const key of allDailyAffiliationKeys) {
100 result[key] = inventory[key];
101 }
102
103 const stats = (await Stats.findOne({ accountOwnerId: account._id }))!.toJSON<Partial<TStatsDatabaseDocument>>();
104 delete stats._id;
105 delete stats.__v;
106 delete stats.accountOwnerId;
107
108 res.json({
109 Results: [result],
110 TechProjects: [],
111 XpComponents: [],
112 //XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
113 Stats: stats
114 });
115 };
116
117 interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations> {
118 AccountId: IOid;
119 DisplayName: string;
120 PlayerLevel: number;
121 LoadOutPreset?: Omit<ILoadoutConfigClient, "ItemId"> & { ItemId?: IOid };
122 LoadOutInventory: {
123 WeaponSkins: { ItemType: string }[];
124 Suits?: IEquipmentClient[];
125 Pistols?: IEquipmentClient[];
126 LongGuns?: IEquipmentClient[];
127 Melee?: IEquipmentClient[];
128 XPInfo: ITypeXPItem[];
129 };
130 GuildId?: IOid;
131 GuildName?: string;
132 GuildTier?: number;
133 GuildXp?: number;
134 GuildClass?: number;
135 GuildEmblem?: boolean;
136 PlayerSkills: IPlayerSkills;
137 ChallengeProgress: IChallengeProgress[];
138 DeathMarks: string[];
139 Harvestable: boolean;
140 DeathSquadable: boolean;
141 Created: IMongoDate;
142 MigratedToConsole: boolean;
143 Missions: IMission[];
144 Affiliations: IAffiliation[];
145 DailyFocus: number;
146 Wishlist: string[];
147 Alignment?: IAlignment;
148 }
149
150 let skinLookupTable: Record<number, string> | undefined;
151
152 const resolveAndCollectSkins = (
153 inventory: TInventoryDatabaseDocument,
154 skins: Set<string>,
155 item: IEquipmentClient
156 ): void => {
157 for (const config of item.Configs) {
158 if (config.Skins) {
159 for (let i = 0; i != config.Skins.length; ++i) {
160 // Resolve oids to type names
161 if (config.Skins[i].length == 24) {
162 if (config.Skins[i].substring(0, 16) == "ca70ca70ca70ca70") {
163 if (!skinLookupTable) {
164 skinLookupTable = {};
165 for (const key of Object.keys(ExportCustoms)) {
166 skinLookupTable[catBreadHash(key)] = key;
167 }
168 }
169 config.Skins[i] = skinLookupTable[parseInt(config.Skins[i].substring(16), 16)];
170 } else {
171 const skinItem = inventory.WeaponSkins.id(config.Skins[i]);
172 config.Skins[i] = skinItem ? skinItem.ItemType : "";
173 }
174 }
175
176 // Collect type names
177 if (config.Skins[i]) {
178 skins.add(config.Skins[i]);
179 }
180 }
181 }
182 }
183 };
Modified src/models/guildModel.ts +1 -0
@@ -153,6 +153,7 @@ const guildSchema = new Schema<IGuildDatabase>(
153 153 LongMOTD: { type: longMOTDSchema, default: undefined },
154 154 Ranks: { type: [guildRankSchema], default: defaultRanks },
155 155 TradeTax: { type: Number, default: 0 },
156 Tier: { type: Number, default: 1 },
156 157 DojoComponents: { type: [dojoComponentSchema], default: [] },
157 158 DojoCapacity: { type: Number, default: 100 },
158 159 DojoEnergy: { type: Number, default: 5 },
Modified src/models/inventoryModels/inventoryModel.ts +0 -1
@@ -468,7 +468,6 @@ const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
468 468 //TODO: check whether this is complete
469 469 const playerSkillsSchema = new Schema<IPlayerSkills>(
470 470 {
471 LPP_NONE: { type: Number, default: 0 },
472 471 LPP_SPACE: { type: Number, default: 0 },
473 472 LPS_PILOTING: { type: Number, default: 0 },
474 473 LPS_GUNNERY: { type: Number, default: 0 },
Modified src/routes/dynamic.ts +4 -2
@@ -1,10 +1,12 @@
1 import express from "express";
1 2 import { aggregateSessionsController } from "@/src/controllers/dynamic/aggregateSessionsController";
3 import { getProfileViewingDataController } from "@/src/controllers/dynamic/getProfileViewingDataController";
2 4 import { worldStateController } from "@/src/controllers/dynamic/worldStateController";
3 import express from "express";
4 5
5 6 const dynamicController = express.Router();
6 7
7 dynamicController.get("/worldState.php", worldStateController);
8 8 dynamicController.get("/aggregateSessions.php", aggregateSessionsController);
9 dynamicController.get("/getProfileViewingData.php", getProfileViewingDataController);
10 dynamicController.get("/worldState.php", worldStateController);
9 11
10 12 export { dynamicController };
Modified src/services/guildService.ts +1 -1
@@ -91,7 +91,7 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
91 91 Members: members,
92 92 Ranks: guild.Ranks,
93 93 TradeTax: guild.TradeTax,
94 Tier: 1,
94 Tier: guild.Tier,
95 95 Vault: getGuildVault(guild),
96 96 ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
97 97 Class: guild.Class,
Modified src/types/guildTypes.ts +1 -0
@@ -27,6 +27,7 @@ export interface IGuildDatabase {
27 27 LongMOTD?: ILongMOTD;
28 28 Ranks: IGuildRank[];
29 29 TradeTax: number;
30 Tier: number;
30 31
31 32 DojoComponents: IDojoComponentDatabase[];
32 33 DojoCapacity: number;
Modified src/types/inventoryTypes/inventoryTypes.ts +0 -1
@@ -928,7 +928,6 @@ export interface IPersonalTechProject {
928 928 }
929 929
930 930 export interface IPlayerSkills {
931 LPP_NONE: number;
932 931 LPP_SPACE: number;
933 932 LPS_PILOTING: number;
934 933 LPS_GUNNERY: number;