返回提交历史
Added
src/controllers/api/getVaultController.ts
+27
-0
Modified
src/controllers/api/guildTechController.ts
+25
-21
Modified
src/models/guildModel.ts
+1
-0
Modified
src/routes/api.ts
+3
-1
Modified
src/services/guildService.ts
+14
-3
Modified
src/types/guildTypes.ts
+11
-2
XFEstudio/XFESpaceNinjaServer
feat(clan): solar rail research (#3583)
idk how alliance is supposed to acquire solar rail bp Closes #3560 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3583 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
2ea6148b
代码差异
6 个文件
+81
-27
@@ -0,0 +1,27 @@
1
import type { RequestHandler } from "express";
2
import { getAccountForRequest } from "../../services/loginService.ts";
3
import { getInventory } from "../../services/inventoryService.ts";
4
import { getAllianceVault, getGuildForRequestEx, getGuildVault } from "../../services/guildService.ts";
5
import { Alliance } from "../../models/guildModel.ts";
6
7
export const getVaultController: RequestHandler = async (req, res) => {
8
const account = await getAccountForRequest(req);
9
const inventory = await getInventory(account._id, "GuildId");
10
const guild = await getGuildForRequestEx(req, inventory);
11
12
const allianceId = req.query.allianceId as string;
13
if (!allianceId) {
14
res.json({ Vault: getGuildVault(guild) });
15
return;
16
}
17
18
if (guild.AllianceId?.toString() === allianceId) {
19
const alliance = await Alliance.findById(allianceId);
20
if (alliance) {
21
res.json({ AllianceVault: getAllianceVault(alliance) });
22
return;
23
}
24
}
25
26
res.end();
27
};
@@ -13,7 +13,7 @@ import {
13
13
setGuildTechLogState
14
14
} from "../../services/guildService.ts";
15
15
import { ExportDojoRecipes, ExportRailjackWeapons } from "warframe-public-export-plus";
16
import { getAccountIdForRequest } from "../../services/loginService.ts";
16
import { getAccountForRequest } from "../../services/loginService.ts";
17
17
import {
18
18
addCrewShipWeaponSkin,
19
19
addEquipment,
@@ -31,12 +31,13 @@ import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
31
31
import type { ITechProjectClient } from "../../types/guildTypes.ts";
32
32
import { GuildPermission } from "../../types/guildTypes.ts";
33
33
import { GuildMember } from "../../models/guildModel.ts";
34
import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
34
import { toMongoDate, toMongoDate2, toOid } from "../../helpers/inventoryHelpers.ts";
35
35
import { logger } from "../../utils/logger.ts";
36
36
import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
37
37
38
38
export const guildTechController: RequestHandler = async (req, res) => {
39
const accountId = await getAccountIdForRequest(req);
39
const account = await getAccountForRequest(req);
40
const accountId = account._id.toString();
40
41
const inventory = await getInventory(accountId);
41
42
const data = JSON.parse(String(req.body)) as TGuildTechRequest;
42
43
if (data.Action == "Sync") {
@@ -52,7 +53,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
52
53
State: project.State
53
54
};
54
55
if (project.CompletionDate) {
55
techProject.CompletionDate = toMongoDate(project.CompletionDate);
56
techProject.CompletionDate = toMongoDate2(project.CompletionDate, account.BuildLabel);
56
57
if (
57
58
Date.now() >= project.CompletionDate.getTime() &&
58
59
setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate)
@@ -69,19 +70,20 @@ export const guildTechController: RequestHandler = async (req, res) => {
69
70
}
70
71
res.json({ TechProjects: techProjects });
71
72
} else if (data.Action == "Start") {
72
if (data.Mode == "Guild") {
73
if (data.Mode != "Personal") {
73
74
const guild = await getGuildForRequestEx(req, inventory);
74
75
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
75
76
res.status(400).send("-1").end();
76
77
return;
77
78
}
78
const recipe = ExportDojoRecipes.research[data.RecipeType];
79
const recipeType: string = (data.RecipeType || data.ResearchId)!;
80
const recipe = ExportDojoRecipes.research[recipeType];
79
81
guild.TechProjects ??= [];
80
if (!guild.TechProjects.find(x => x.ItemType == data.RecipeType)) {
82
if (!guild.TechProjects.find(x => x.ItemType == recipeType)) {
81
83
const techProject =
82
84
guild.TechProjects[
83
85
guild.TechProjects.push({
84
ItemType: data.RecipeType,
86
ItemType: recipeType,
85
87
ReqCredits: guild.noDojoResearchCosts ? 0 : scaleRequiredCount(guild.Tier, recipe.price),
86
88
ReqItems: recipe.ingredients.map(x => ({
87
89
ItemType: x.ItemType,
@@ -94,15 +96,15 @@ export const guildTechController: RequestHandler = async (req, res) => {
94
96
if (guild.noDojoResearchCosts) {
95
97
processFundedGuildTechProject(guild, techProject, recipe);
96
98
} else {
97
if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
98
guild.ActiveDojoColorResearch = data.RecipeType;
99
if (recipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
100
guild.ActiveDojoColorResearch = recipeType;
99
101
}
100
102
}
101
103
}
102
104
await guild.save();
103
105
res.end();
104
106
} else {
105
const recipe = ExportDojoRecipes.research[data.RecipeType];
107
const recipe = ExportDojoRecipes.research[data.RecipeType!];
106
108
if (data.TechProductCategory) {
107
109
if (
108
110
data.TechProductCategory != "CrewShipWeapons" &&
@@ -183,8 +185,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
183
185
{ accountId, guildId: guild._id },
184
186
"RegularCreditsContributed MiscItemsContributed"
185
187
))!;
186
187
const techProject = guild.TechProjects!.find(x => x.ItemType == data.RecipeType)!;
188
const recipeType = data.RecipeType || data.ResearchId;
189
const techProject = guild.TechProjects!.find(x => x.ItemType == recipeType)!;
188
190
189
191
if (data.VaultCredits) {
190
192
if (data.VaultCredits > techProject.ReqCredits) {
@@ -248,7 +250,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
248
250
}
249
251
} else if (data.Action.split(",")[0] == "Buy") {
250
252
const purchase = data as IGuildTechBuyRequest;
251
if (purchase.Mode == "Guild") {
253
if (purchase.Mode != "Personal") {
254
const recipeType: string = (purchase.RecipeType || purchase.ResearchId)!;
252
255
const guild = await getGuildForRequestEx(req, inventory);
253
256
if (
254
257
!hasAccessToDojo(inventory) ||
@@ -257,17 +260,17 @@ export const guildTechController: RequestHandler = async (req, res) => {
257
260
res.status(400).send("-1").end();
258
261
return;
259
262
}
260
const quantity = parseInt(data.Action.split(",")[1]);
263
const quantity = parseInt(data.Action.split(",")[1]) || 1;
261
264
const recipeChanges = [
262
265
{
263
ItemType: purchase.RecipeType,
266
ItemType: recipeType,
264
267
ItemCount: quantity
265
268
}
266
269
];
267
270
addRecipes(inventory, recipeChanges);
268
271
const currencyChanges = updateCurrency(
269
272
inventory,
270
ExportDojoRecipes.research[purchase.RecipeType].replicatePrice,
273
ExportDojoRecipes.research[recipeType].replicatePrice,
271
274
false
272
275
);
273
276
await inventory.save();
@@ -291,7 +294,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
291
294
res.status(400).send("-1").end();
292
295
return;
293
296
}
294
const recipe = ExportDojoRecipes.fabrications[data.RecipeType];
297
const recipe = ExportDojoRecipes.fabrications[data.RecipeType!];
295
298
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, recipe.price, false);
296
299
inventoryChanges.MiscItems = recipe.ingredients.map(x => ({
297
300
ItemType: x.ItemType,
@@ -322,7 +325,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
322
325
}
323
326
const project = guild.TechProjects!.find(x => x.ItemType == data.RecipeType)!;
324
327
project.State = 0;
325
guild.ActiveDojoColorResearch = data.RecipeType;
328
guild.ActiveDojoColorResearch = data.RecipeType!;
326
329
await guild.save();
327
330
res.end();
328
331
} else if (data.Action == "Cancel" && data.CategoryItemId) {
@@ -396,7 +399,8 @@ type TGuildTechRequest =
396
399
interface IGuildTechBasicRequest {
397
400
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush" | "InstantFinish";
398
401
Mode: "Guild" | "Personal";
399
RecipeType: string;
402
ResearchId?: string; // U18.0.6 uses that instead RecipeType
403
RecipeType?: string;
400
404
TechProductCategory?: string;
401
405
CategoryItemId?: string;
402
406
}
@@ -408,7 +412,7 @@ interface IGuildTechBuyRequest extends Omit<IGuildTechBasicRequest, "Action"> {
408
412
interface IGuildTechContributeRequest {
409
413
Action: "Contribute";
410
414
ResearchId: string;
411
RecipeType: string;
415
RecipeType?: string;
412
416
RegularCredits: number;
413
417
MiscItems: IMiscItem[];
414
418
VaultCredits: number;
@@ -229,6 +229,7 @@ const guildSchema = new Schema<IGuildDatabase>(
229
229
VaultShipDecorations: { type: [typeCountSchema], default: undefined },
230
230
VaultFusionTreasures: { type: [fusionTreasuresSchema], default: undefined },
231
231
VaultDecoRecipes: { type: [typeCountSchema], default: undefined },
232
VaultRecipes: { type: [typeCountSchema], default: undefined },
232
233
MaxBattlePayReserve: Number,
233
234
MaxMissionBattlePay: Number,
234
235
MinMissionBattlePay: Number,
@@ -79,6 +79,7 @@ import { getPastWeeklyChallengesController } from "../controllers/api/getPastWee
79
79
import { getProfileViewingDataPostController } from "../controllers/dynamic/getProfileViewingDataController.ts";
80
80
import { getRecentPlayersController } from "../controllers/api/getRecentPlayersController.ts";
81
81
import { getShipController } from "../controllers/api/getShipController.ts";
82
import { getVaultController } from "../controllers/api/getVaultController.ts";
82
83
import { getVendorInfoController } from "../controllers/api/getVendorInfoController.ts";
83
84
import { getVoidProjectionRewardsController } from "../controllers/api/getVoidProjectionRewardsController.ts";
84
85
import { giftingController } from "../controllers/api/giftingController.ts";
@@ -223,9 +224,10 @@ apiRouter.get("/getGuildLog.php", getGuildLogController);
223
224
apiRouter.get("/getIgnoredUsers.php", getIgnoredUsersController);
224
225
apiRouter.get("/getMessages.php", inboxController); // unsure if this is correct, but needed for U17
225
226
apiRouter.get("/getNewRewardSeed.php", getNewRewardSeedController);
226
apiRouter.get("/getPastWeeklyChallenges.php", getPastWeeklyChallengesController)
227
apiRouter.get("/getPastWeeklyChallenges.php", getPastWeeklyChallengesController);
227
228
apiRouter.get("/getShip.php", getShipController);
228
229
apiRouter.get("/getShipDecos.php", (_req, res) => { res.end(); }); // needed to log in on U22.8
230
apiRouter.get("/getVault.php", getVaultController);
229
231
apiRouter.get("/getVendorInfo.php", getVendorInfoController);
230
232
apiRouter.get("/giveStartingGear.php", giveStartingGearGetController);
231
233
apiRouter.get("/inbox.php", inboxController);
@@ -153,6 +153,7 @@ export const getGuildVault = (guild: TGuildDatabaseDocument): IGuildVault => {
153
153
ShipDecorations: guild.VaultShipDecorations,
154
154
FusionTreasures: guild.VaultFusionTreasures,
155
155
DecoRecipes: guild.VaultDecoRecipes,
156
Recipes: guild.VaultRecipes, // Solar Rail
156
157
157
158
MaxBattlePayReserve: guild.MaxBattlePayReserve,
158
159
MaxMissionBattlePay: guild.MaxMissionBattlePay,
@@ -160,6 +161,12 @@ export const getGuildVault = (guild: TGuildDatabaseDocument): IGuildVault => {
160
161
};
161
162
};
162
163
164
export const getAllianceVault = (alliance: IAllianceDatabase): IGuildVault => {
165
return {
166
DojoRefundRegularCredits: alliance.VaultRegularCredits
167
};
168
};
169
163
170
export const getDojoClient = async (
164
171
guild: TGuildDatabaseDocument,
165
172
status: number,
@@ -621,6 +628,12 @@ export const processCompletedGuildTechProject = (guild: TGuildDatabaseDocument,
621
628
ItemType: type,
622
629
ItemCount: 1
623
630
});
631
} else if (type == "/Lotus/Types/Game/SolarRails/BasicSolarRailBlueprint") {
632
guild.VaultRecipes ??= [];
633
guild.VaultRecipes.push({
634
ItemType: type,
635
ItemCount: 1
636
});
624
637
}
625
638
};
626
639
@@ -856,9 +869,7 @@ export const getAllianceClient = async (
856
869
MOTD: alliance.MOTD,
857
870
LongMOTD: alliance.LongMOTD,
858
871
Clans: clans,
859
AllianceVault: {
860
DojoRefundRegularCredits: alliance.VaultRegularCredits
861
}
872
AllianceVault: getAllianceVault(alliance)
862
873
};
863
874
};
864
875
@@ -1,5 +1,11 @@
1
1
import type { Types } from "mongoose";
2
import type { IOid, IMongoDate, IOidWithLegacySupport, ITypeCount } from "./commonTypes.ts";
2
import type {
3
IOid,
4
IMongoDate,
5
IOidWithLegacySupport,
6
ITypeCount,
7
IMongoDateWithLegacySupport
8
} from "./commonTypes.ts";
3
9
import type {
4
10
IFusionTreasure,
5
11
IMiscItem,
@@ -65,6 +71,7 @@ export interface IGuildDatabase extends IGuildCheats {
65
71
VaultShipDecorations?: ITypeCount[];
66
72
VaultFusionTreasures?: IFusionTreasure[];
67
73
VaultDecoRecipes?: ITypeCount[];
74
VaultRecipes?: ITypeCount[];
68
75
69
76
MaxBattlePayReserve?: number;
70
77
MaxMissionBattlePay?: number;
@@ -148,10 +155,12 @@ export interface IGuildVault {
148
155
ShipDecorations?: ITypeCount[];
149
156
FusionTreasures?: IFusionTreasure[];
150
157
DecoRecipes?: ITypeCount[]; // Event Trophies
158
Recipes?: ITypeCount[]; // Solar Rail
151
159
152
160
MaxBattlePayReserve?: number;
153
161
MaxMissionBattlePay?: number;
154
162
MinMissionBattlePay?: number;
163
// InventoryItems?: Record<"SolarRails", ITypeCount[]>;
155
164
}
156
165
157
166
export interface IDojoClient {
@@ -256,7 +265,7 @@ export interface ITechProjectClient {
256
265
ReqCredits: number;
257
266
ReqItems: IMiscItem[];
258
267
State: number; // 0 = pending, 1 = complete
259
CompletionDate?: IMongoDate;
268
CompletionDate?: IMongoDateWithLegacySupport;
260
269
}
261
270
262
271
export interface ITechProjectDatabase extends Omit<ITechProjectClient, "CompletionDate"> {