返回提交历史
Modified
src/controllers/api/inventoryController.ts
+4
-0
Modified
src/controllers/api/inventorySlotsController.ts
+5
-0
Modified
src/controllers/api/startRecipeController.ts
+11
-3
Modified
src/controllers/custom/addItemsController.ts
+13
-3
Modified
src/models/inventoryModels/inventoryModel.ts
+1
-0
Modified
src/routes/api.ts
+1
-0
Modified
src/services/inventoryService.ts
+17
-7
Modified
src/services/purchaseService.ts
+2
-1
Modified
src/types/inventoryTypes/inventoryTypes.ts
+8
-14
Modified
src/types/purchaseTypes.ts
+2
-1
XFEstudio/XFESpaceNinjaServer
feat: partial preU28 pets support (#3081)
At least, this allows to complete Howl of the Kubrow Closes #3074 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3081 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>
fab6b5c5
代码差异
10 个文件
+64
-29
@@ -276,6 +276,10 @@ export const inventoryController: RequestHandler = async (request, response) =>
276
276
}
277
277
}
278
278
inventory.LastInventorySync = new Types.ObjectId();
279
280
if (inventory.QuestKeys.some(x => x.ItemType.endsWith("KubrowQuestKeyChain") && x.Completed)) {
281
inventory.KubrowPets.forEach(item => item.Details && (item.Details.HasCollar = true));
282
}
279
283
await inventory.save();
280
284
281
285
response.json(
@@ -52,6 +52,11 @@ export const inventorySlotsController: RequestHandler = async (req, res) => {
52
52
amount = 3;
53
53
break;
54
54
55
case InventorySlot.PETS:
56
price = 10;
57
amount = 1;
58
break;
59
55
60
default:
56
61
exhaustive(body.Bin);
57
62
throw new Error(`unexpected slot purchase of type ${body.Bin as string}`);
@@ -1,4 +1,4 @@
1
import { getAccountIdForRequest } from "../../services/loginService.ts";
1
import { getAccountForRequest } from "../../services/loginService.ts";
2
2
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
3
3
import { logger } from "../../utils/logger.ts";
4
4
import type { RequestHandler } from "express";
@@ -22,7 +22,8 @@ export const startRecipeController: RequestHandler = async (req, res) => {
22
22
const startRecipeRequest = getJSONfromString<IStartRecipeRequest>(String(req.body));
23
23
logger.debug("StartRecipe Request", { startRecipeRequest });
24
24
25
const accountId = await getAccountIdForRequest(req);
25
const account = await getAccountForRequest(req);
26
const accountId = account._id.toString();
26
27
27
28
let recipeName = startRecipeRequest.RecipeName;
28
29
if (req.query.recipeName) recipeName = String(req.query.recipeName); // U8
@@ -77,7 +78,14 @@ export const startRecipeController: RequestHandler = async (req, res) => {
77
78
78
79
let inventoryChanges: IInventoryChanges | undefined;
79
80
if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
80
inventoryChanges = addKubrowPet(inventory, getRandomElement(recipe.secretIngredients!)!.ItemType);
81
inventoryChanges = addKubrowPet(
82
inventory,
83
getRandomElement(recipe.secretIngredients!)!.ItemType,
84
undefined,
85
false,
86
{},
87
account.BuildLabel
88
);
81
89
pr.KubrowPet = new Types.ObjectId(fromOid(inventoryChanges.KubrowPets![0].ItemId));
82
90
} else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
83
91
pr.KubrowPet = new Types.ObjectId(startRecipeRequest.Ids[recipe.ingredients.length]);
@@ -1,14 +1,24 @@
1
import { getAccountIdForRequest } from "../../services/loginService.ts";
1
import { getAccountForRequest } from "../../services/loginService.ts";
2
2
import { getInventory, addItem } from "../../services/inventoryService.ts";
3
3
import type { RequestHandler } from "express";
4
4
import { broadcastInventoryUpdate } from "../../services/wsService.ts";
5
5
6
6
export const addItemsController: RequestHandler = async (req, res) => {
7
const accountId = await getAccountIdForRequest(req);
7
const account = await getAccountForRequest(req);
8
const accountId = account._id.toString();
8
9
const requests = req.body as IAddItemRequest[];
9
10
const inventory = await getInventory(accountId);
10
11
for (const request of requests) {
11
await addItem(inventory, request.ItemType, request.ItemCount, true, undefined, request.Fingerprint, true);
12
await addItem(
13
inventory,
14
request.ItemType,
15
request.ItemCount,
16
true,
17
undefined,
18
request.Fingerprint,
19
true,
20
account.BuildLabel
21
);
12
22
}
13
23
if (inventory.isModified()) {
14
24
await inventory.save();
@@ -1527,6 +1527,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1527
1527
CrewShipSalvageBin: { type: slotsBinSchema, default: { Slots: 8 } },
1528
1528
MechBin: { type: slotsBinSchema, default: { Slots: 4 } },
1529
1529
CrewMemberBin: { type: slotsBinSchema, default: { Slots: 3 } },
1530
PetBin: { type: slotsBinSchema, default: { Slots: 2 } },
1530
1531
1531
1532
...equipmentFields,
1532
1533
@@ -341,6 +341,7 @@ apiRouter.post("/saveSettings.php", saveSettingsController);
341
341
apiRouter.post("/saveVaultAutoContribute.php", saveVaultAutoContributeController);
342
342
apiRouter.post("/sell.php", sellController);
343
343
apiRouter.post("/sendMsgToInBox.php", sendMsgToInBoxController);
344
apiRouter.post("/sendPetToStasis.php", retrievePetFromStasisController);
344
345
apiRouter.post("/setDojoComponentColors.php", setDojoComponentColorsController);
345
346
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
346
347
apiRouter.post("/setDojoComponentSettings.php", setDojoComponentSettingsController);
@@ -68,7 +68,8 @@ import {
68
68
kubrowDetails,
69
69
kubrowFurPatternsWeights,
70
70
kubrowWeights,
71
toOid
71
toOid,
72
version_compare
72
73
} from "../helpers/inventoryHelpers.ts";
73
74
import { addQuestKey, completeQuest } from "./questService.ts";
74
75
import { handleBundleAcqusition } from "./purchaseService.ts";
@@ -353,7 +354,8 @@ export const addItem = async (
353
354
premiumPurchase: boolean = false,
354
355
seed?: bigint,
355
356
targetFingerprint?: string,
356
exactQuantity: boolean = false
357
exactQuantity: boolean = false,
358
buildLabel?: string
357
359
): Promise<IInventoryChanges> => {
358
360
// Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
359
361
if (typeName in ExportBundles) {
@@ -873,7 +875,7 @@ export const addItem = async (
873
875
`unexpected acquisition quantity of KubrowPet: got ${quantity}, expected 1`
874
876
);
875
877
}
876
return addKubrowPet(inventory, typeName, undefined, premiumPurchase);
878
return addKubrowPet(inventory, typeName, undefined, premiumPurchase, {}, buildLabel);
877
879
}
878
880
} else if (typeName.startsWith("/Lotus/Types/Game/CrewShip/CrewMember/")) {
879
881
if (quantity != 1) {
@@ -1213,9 +1215,17 @@ export const addKubrowPet = (
1213
1215
kubrowPetName: string,
1214
1216
details?: IKubrowPetDetailsDatabase,
1215
1217
premiumPurchase: boolean = false,
1216
inventoryChanges: IInventoryChanges = {}
1218
inventoryChanges: IInventoryChanges = {},
1219
buildLabel?: string
1217
1220
): IInventoryChanges => {
1218
combineInventoryChanges(inventoryChanges, occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase));
1221
const isPreU28 = buildLabel && version_compare(buildLabel, "2020.06.12.16.46") < 0;
1222
const isPreU26 = buildLabel && version_compare(buildLabel, "2019.10.31.22.42") < 0;
1223
const questCompleted = inventory.QuestKeys.some(x => x.ItemType.endsWith("KubrowQuestKeyChain") && x.Completed);
1224
1225
combineInventoryChanges(
1226
inventoryChanges,
1227
occupySlot(inventory, isPreU28 ? InventorySlot.PETS : InventorySlot.SENTINELS, premiumPurchase)
1228
);
1219
1229
1220
1230
// TODO: When incubating, this should only be given when claiming the recipe.
1221
1231
const kubrowPet = ExportSentinels[kubrowPetName] as ISentinel | undefined;
@@ -1283,8 +1293,8 @@ export const addKubrowPet = (
1283
1293
details = {
1284
1294
Name: "",
1285
1295
IsPuppy: !premiumPurchase,
1286
HasCollar: true,
1287
PrintsRemaining: isCatbrow ? 3 : 2,
1296
HasCollar: isCatbrow || questCompleted,
1297
PrintsRemaining: !isPreU26 && isCatbrow ? 3 : 2,
1288
1298
Status: premiumPurchase ? Status.StatusStasis : Status.StatusIncubating,
1289
1299
HatchDate: premiumPurchase ? new Date() : new Date(Date.now() + 10 * unixTimesInMs.hour), // On live, this seems to be somewhat randomised so that the pet hatches 9~11 hours after start.
1290
1300
IsMale: !!getRandomInt(0, 1),
@@ -500,7 +500,8 @@ const slotPurchaseNameToSlotName: Record<string, { name: SlotNames; purchaseQuan
500
500
RandomModSlotItem: { name: "RandomModBin", purchaseQuantity: 3 },
501
501
TwoCrewShipSalvageSlotItem: { name: "CrewShipSalvageBin", purchaseQuantity: 2 },
502
502
CrewMemberSlotItem: { name: "CrewMemberBin", purchaseQuantity: 1 },
503
PvPLoadoutSlotItem: { name: "PvpBonusLoadoutBin", purchaseQuantity: 1 }
503
PvPLoadoutSlotItem: { name: "PvpBonusLoadoutBin", purchaseQuantity: 1 },
504
KubrowSlotItem: { name: "PetBin", purchaseQuantity: 1 }
504
505
};
505
506
506
507
// // extra = everything above the base +2 slots (depending on slot type)
@@ -15,6 +15,7 @@ import type { ICountedStoreItem } from "warframe-public-export-plus";
15
15
import type { IEquipmentClient, IEquipmentDatabase, ITraits } from "../equipmentTypes.ts";
16
16
import type { ILoadoutConfigClientLegacy, ILoadOutPresets } from "../saveLoadoutTypes.ts";
17
17
import type { CalendarSeasonType } from "../worldStateTypes.ts";
18
import type { SlotNames } from "../purchaseTypes.ts";
18
19
19
20
export type InventoryDatabaseEquipment = {
20
21
[_ in TEquipmentKey]: IEquipmentDatabase[];
@@ -259,7 +260,11 @@ export type InventoryClientEquipment = {
259
260
[_ in TEquipmentKey]: IEquipmentClient[];
260
261
};
261
262
262
export interface IInventoryClient extends IDailyAffiliations, InventoryClientEquipment {
263
export type InventorySlots = {
264
[_ in SlotNames]: ISlots;
265
};
266
267
export interface IInventoryClient extends IDailyAffiliations, InventoryClientEquipment, InventorySlots {
263
268
AdultOperatorLoadOuts: IOperatorConfigClient[];
264
269
OperatorLoadOuts: IOperatorConfigClient[];
265
270
KahlLoadOuts: IOperatorConfigClient[];
@@ -275,18 +280,6 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
275
280
FusionPoints: number;
276
281
CrewShipFusionPoints: number; //Dirac (pre-rework Railjack)
277
282
PrimeTokens: number;
278
SuitBin: ISlots;
279
WeaponBin: ISlots;
280
SentinelBin: ISlots;
281
SpaceSuitBin: ISlots;
282
SpaceWeaponBin: ISlots;
283
PvpBonusLoadoutBin: ISlots;
284
PveBonusLoadoutBin: ISlots;
285
RandomModBin: ISlots;
286
MechBin: ISlots;
287
CrewMemberBin: ISlots;
288
OperatorAmpBin: ISlots;
289
CrewShipSalvageBin: ISlots;
290
283
TradesRemaining: number;
291
284
DailyFocus: number;
292
285
GiftsRemaining: number;
@@ -584,7 +577,8 @@ export enum InventorySlot {
584
577
AMPS = "OperatorAmpBin",
585
578
RJ_COMPONENT_AND_ARMAMENTS = "CrewShipSalvageBin",
586
579
CREWMEMBERS = "CrewMemberBin",
587
RIVENS = "RandomModBin"
580
RIVENS = "RandomModBin",
581
PETS = "PetBin"
588
582
}
589
583
590
584
export interface ISlots {
@@ -134,7 +134,8 @@ export const slotNames = [
134
134
"OperatorAmpBin",
135
135
"RandomModBin",
136
136
"CrewShipSalvageBin",
137
"CrewMemberBin"
137
"CrewMemberBin",
138
"PetBin"
138
139
] as const;
139
140
140
141
export type SlotNames = (typeof slotNames)[number];