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

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
AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
提交于

代码差异

10 个文件 +64 -29
Modified src/controllers/api/inventoryController.ts +4 -0
@@ -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(
Modified src/controllers/api/inventorySlotsController.ts +5 -0
@@ -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}`);
Modified src/controllers/api/startRecipeController.ts +11 -3
@@ -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]);
Modified src/controllers/custom/addItemsController.ts +13 -3
@@ -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();
Modified src/models/inventoryModels/inventoryModel.ts +1 -0
@@ -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
Modified src/routes/api.ts +1 -0
@@ -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);
Modified src/services/inventoryService.ts +17 -7
@@ -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),
Modified src/services/purchaseService.ts +2 -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)
Modified src/types/inventoryTypes/inventoryTypes.ts +8 -14
@@ -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 {
Modified src/types/purchaseTypes.ts +2 -1
@@ -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];