返回提交历史
Modified
src/app.ts
+1
-0
Modified
src/controllers/api/inventoryController.ts
+1
-1
Added
src/controllers/dynamic/getProfileViewingDataController.ts
+183
-0
Modified
src/models/guildModel.ts
+1
-0
Modified
src/models/inventoryModels/inventoryModel.ts
+0
-1
Modified
src/routes/dynamic.ts
+4
-2
Modified
src/services/guildService.ts
+1
-1
Modified
src/types/guildTypes.ts
+1
-0
Modified
src/types/inventoryTypes/inventoryTypes.ts
+0
-1
XFEstudio/SpaceNinjaServer
feat: getProfileViewingData for players (#1258)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1258
3b16ff9b
代码差异
9 个文件
+192
-6
@@ -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);
@@ -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;
@@ -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
};
@@ -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 },
@@ -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 },
@@ -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 };
@@ -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,
@@ -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;
@@ -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;