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

Foundry 1 - Preliminary (#127)

8b50189f
OrdisPrime <134585663+OrdisPrime@users.noreply.github.com>
提交于

代码差异

17 个文件 +363 -125
Modified src/constants/timeConstants.ts +2 -0
@@ -3,11 +3,13 @@ const secondsPerMinute = 60;
3 3 const minutesPerHour = 60;
4 4 const hoursPerDay = 24;
5 5
6 const unixSecond = millisecondsPerSecond;
6 7 const unixMinute = secondsPerMinute * millisecondsPerSecond;
7 8 const unixHour = unixMinute * minutesPerHour;
8 9 const unixDay = hoursPerDay * unixHour;
9 10
10 11 export const unixTimesInMs = {
12 second: unixSecond,
11 13 minute: unixMinute,
12 14 hour: unixHour,
13 15 day: unixDay
Added src/controllers/api/claimCompletedRecipeController.ts +64 -0
@@ -0,0 +1,64 @@
1 //this is a controller for the claimCompletedRecipe route
2 //it will claim a recipe for the user
3
4 import { Request, RequestHandler, Response } from "express";
5 import { logger } from "@/src/utils/logger";
6 import { getItemByBlueprint, getItemCategoryByUniqueName } from "@/src/services/itemDataService";
7 import { IOid } from "@/src/types/commonTypes";
8 import { getJSONfromString } from "@/src/helpers/stringHelpers";
9 import { getInventory } from "@/src/services/inventoryService";
10 import { IInventoryDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
11
12 export interface IClaimCompletedRecipeRequest {
13 RecipeIds: IOid[];
14 }
15
16 // eslint-disable-next-line @typescript-eslint/no-misused-promises
17 export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
18 const claimCompletedRecipeRequest = getJSONfromString(req.body.toString()) as IClaimCompletedRecipeRequest;
19 const accountId = req.query.accountId as string;
20 if (!accountId) throw new Error("no account id");
21
22 console.log(claimCompletedRecipeRequest);
23 const inventory = await getInventory(accountId);
24 const pendingRecipe = inventory.PendingRecipes.find(
25 recipe => recipe._id?.toString() === claimCompletedRecipeRequest.RecipeIds[0].$oid
26 );
27 console.log(pendingRecipe);
28 if (!pendingRecipe) {
29 logger.error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
30 throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
31 }
32
33 //check recipe is indeed ready to be completed
34 // if (pendingRecipe.CompletionDate > new Date()) {
35 // logger.error(`recipe ${pendingRecipe._id} is not ready to be completed`);
36 // throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
37 // }
38
39 //get completed Items
40 const completedItemName = getItemByBlueprint(pendingRecipe.ItemType)?.uniqueName;
41
42 if (!completedItemName) {
43 logger.error(`no completed item found for recipe ${pendingRecipe._id}`);
44 throw new Error(`no completed item found for recipe ${pendingRecipe._id}`);
45 }
46 const itemCategory = getItemCategoryByUniqueName(completedItemName) as keyof typeof inventory;
47 console.log(itemCategory);
48 //TODO: remove all Schema.Mixed for inventory[itemCategory] not to be any
49 //add item
50 //inventory[itemCategory].
51
52 //add additional item components like mods or weapons for a sentinel.
53 //const additionalItemComponents = itemComponents[uniqueName]
54 //add these items to inventory
55 //return changes as InventoryChanges
56
57 //remove pending recipe
58 inventory.PendingRecipes.pull(pendingRecipe._id);
59 // await inventory.save();
60
61 logger.debug("Claiming Completed Recipe", { completedItemName });
62
63 res.json({ InventoryChanges: {} });
64 };
Modified src/controllers/api/inventoryController.ts +1 -0
@@ -24,6 +24,7 @@ const inventoryController: RequestHandler = async (request: Request, response: R
24 24 return;
25 25 }
26 26
27 //TODO: make a function that converts from database representation to client
27 28 const inventoryJSON = inventory.toJSON();
28 29
29 30 const inventoryResponse = toInventoryResponse(inventoryJSON);
Added src/controllers/api/startRecipeController.ts +21 -0
@@ -0,0 +1,21 @@
1 import { parseString } from "@/src/helpers/general";
2 import { getJSONfromString } from "@/src/helpers/stringHelpers";
3 import { startRecipe } from "@/src/services/recipeService";
4 import { logger } from "@/src/utils/logger";
5 import { RequestHandler } from "express";
6
7 interface IStartRecipeRequest {
8 RecipeName: string;
9 Ids: string[];
10 }
11
12 // eslint-disable-next-line @typescript-eslint/no-misused-promises
13 export const startRecipeController: RequestHandler = async (req, res) => {
14 const startRecipeRequest = getJSONfromString(req.body.toString()) as IStartRecipeRequest;
15 logger.debug("StartRecipe Request", { startRecipeRequest });
16
17 const accountId = parseString(req.query.accountId);
18
19 const newRecipeId = await startRecipe(startRecipeRequest.RecipeName, accountId);
20 res.json(newRecipeId);
21 };
Modified src/controllers/custom/addItemController.ts +1 -1
@@ -1,5 +1,5 @@
1 1 import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers";
2 import { getWeaponType } from "@/src/helpers/purchaseHelpers";
2 import { getWeaponType } from "@/src/services/itemDataService";
3 3 import { addPowerSuit, addWeapon } from "@/src/services/inventoryService";
4 4 import { RequestHandler } from "express";
5 5
Modified src/helpers/customHelpers/addItemHelpers.ts +6 -8
@@ -1,5 +1,5 @@
1 1 import { isString, parseString } from "@/src/helpers/general";
2 import { items } from "@/static/data/items";
2 import { items } from "@/src/services/itemDataService";
3 3
4 4 export enum ItemType {
5 5 Powersuit = "Powersuit",
@@ -23,20 +23,20 @@ interface IAddItemRequest {
23 23 InternalName: string;
24 24 accountId: string;
25 25 }
26 export const isInternalName = (internalName: string): boolean => {
26 export const isInternalItemName = (internalName: string): boolean => {
27 27 const item = items.find(i => i.uniqueName === internalName);
28 28 return Boolean(item);
29 29 };
30 30
31 const parseInternalName = (internalName: unknown): string => {
32 if (!isString(internalName) || !isInternalName(internalName)) {
31 const parseInternalItemName = (internalName: unknown): string => {
32 if (!isString(internalName) || !isInternalItemName(internalName)) {
33 33 throw new Error("incorrect internal name");
34 34 }
35 35
36 36 return internalName;
37 37 };
38 38
39 const toAddItemRequest = (body: unknown): IAddItemRequest => {
39 export const toAddItemRequest = (body: unknown): IAddItemRequest => {
40 40 if (!body || typeof body !== "object") {
41 41 throw new Error("incorrect or missing add item request data");
42 42 }
@@ -44,12 +44,10 @@ const toAddItemRequest = (body: unknown): IAddItemRequest => {
44 44 if ("type" in body && "internalName" in body && "accountId" in body) {
45 45 return {
46 46 type: parseItemType(body.type),
47 InternalName: parseInternalName(body.internalName),
47 InternalName: parseInternalItemName(body.internalName),
48 48 accountId: parseString(body.accountId)
49 49 };
50 50 }
51 51
52 52 throw new Error("malformed add item request");
53 53 };
54
55 export { toAddItemRequest };
Modified src/helpers/purchaseHelpers.ts +1 -18
@@ -1,8 +1,7 @@
1 1 import { parseBoolean, parseNumber, parseString } from "@/src/helpers/general";
2 import { WeaponTypeInternal } from "@/src/services/inventoryService";
2 import { weapons } from "@/src/services/itemDataService";
3 3 import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService";
4 4 import { IPurchaseRequest, SlotPurchaseName } from "@/src/types/purchaseTypes";
5 import { weapons } from "@/static/data/items";
6 5
7 6 export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => {
8 7 if (!purchaseRequest || typeof purchaseRequest !== "object") {
@@ -41,22 +40,6 @@ export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest =>
41 40 throw new Error("invalid purchaseRequest");
42 41 };
43 42
44 export const getWeaponType = (weaponName: string) => {
45 const weaponInfo = weapons.find(i => i.uniqueName === weaponName);
46
47 if (!weaponInfo) {
48 throw new Error(`unknown weapon ${weaponName}`);
49 }
50
51 const weaponType = weaponInfo.productCategory as WeaponTypeInternal;
52
53 if (!weaponType) {
54 throw new Error(`unknown weapon category for item ${weaponName}`);
55 }
56
57 return weaponType;
58 };
59
60 43 export const isSlotPurchaseName = (slotPurchaseName: string): slotPurchaseName is SlotPurchaseName => {
61 44 return slotPurchaseName in slotPurchaseNameToSlotName;
62 45 };
Modified src/helpers/stringHelpers.ts +9 -1
@@ -1,4 +1,4 @@
1 export const getJSONfromString = (str: string): any => {
1 export const getJSONfromString = (str: string) => {
2 2 const jsonSubstring = str.substring(0, str.lastIndexOf("}") + 1);
3 3 return JSON.parse(jsonSubstring);
4 4 };
@@ -16,3 +16,11 @@ export const getSubstringFromKeywordToKeyword = (str: string, keywordBegin: stri
16 16 const endIndex = str.indexOf(keywordEnd);
17 17 return str.substring(beginIndex, endIndex + 1);
18 18 };
19
20 export const getIndexAfter = (str: string, searchWord: string) => {
21 const index = str.indexOf(searchWord);
22 if (index === -1) {
23 return -1;
24 }
25 return index + searchWord.length;
26 };
Modified src/models/inventoryModels/inventoryModel.ts +41 -30
@@ -1,4 +1,4 @@
1 import { Model, Schema, Types, model } from "mongoose";
1 import { HydratedDocument, Model, Schema, Types, model } from "mongoose";
2 2 import {
3 3 IFlavourItem,
4 4 IRawUpgrade,
@@ -10,7 +10,9 @@ import {
10 10 ISlots,
11 11 IGenericItem,
12 12 IMailbox,
13 IDuviriInfo
13 IDuviriInfo,
14 IPendingRecipe as IPendingRecipeDatabase,
15 IPendingRecipeResponse
14 16 } from "../../types/inventoryTypes/inventoryTypes";
15 17 import { IMongoDate, IOid } from "../../types/commonTypes";
16 18 import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
@@ -25,6 +27,29 @@ import {
25 27 } from "@/src/types/inventoryTypes/commonInventoryTypes";
26 28 import { toOid } from "@/src/helpers/inventoryHelpers";
27 29
30 const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
31 {
32 ItemType: String,
33 CompletionDate: Date
34 },
35 { id: false }
36 );
37
38 pendingRecipeSchema.virtual("ItemId").get(function () {
39 return { $oid: this._id.toString() };
40 });
41
42 pendingRecipeSchema.set("toJSON", {
43 virtuals: true,
44 transform(_document, returnedObject) {
45 delete returnedObject._id;
46 delete returnedObject.__v;
47 (returnedObject as IPendingRecipeResponse).CompletionDate = {
48 $date: { $numberLong: (returnedObject as IPendingRecipeDatabase).CompletionDate.getTime().toString() }
49 };
50 }
51 });
52
28 53 const polaritySchema = new Schema<IPolarity>({
29 54 Slot: Number,
30 55 Value: String
@@ -296,7 +321,6 @@ DuviriInfoSchema.set("toJSON", {
296 321 });
297 322
298 323 const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
299
300 324 accountOwnerId: Schema.Types.ObjectId,
301 325 SubscribedToEmails: Number,
302 326 Created: Schema.Types.Mixed,
@@ -325,7 +349,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
325 349 MechBin: slotsBinSchema,
326 350 CrewMemberBin: slotsBinSchema,
327 351
328
329 352 //How many trades do you have left
330 353 TradesRemaining: Number,
331 354 //How many Gift do you have left*(gift spends the trade)
@@ -351,10 +374,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
351 374 DailyAffiliationZariman: Number,
352 375 DailyAffiliationKahl: Number,
353 376
354
355 377 //Daily Focus limit
356 378 DailyFocus: Number,
357 //you not used Focus
379 //you not used Focus
358 380 FocusXP: Schema.Types.Mixed,
359 381 //Curent active like Active school focuses is = "Zenurik"
360 382 FocusAbility: String,
@@ -441,24 +463,21 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
441 463 //Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
442 464 CrewShipRawSalvage: [Schema.Types.Mixed],
443 465
444
445 466 //Default RailJack
446 467 CrewShips: [Schema.Types.Mixed],
447 468 CrewShipAmmo: [Schema.Types.Mixed],
448 469 CrewShipWeapons: [Schema.Types.Mixed],
449 470 CrewShipWeaponSkins: [Schema.Types.Mixed],
450 471
451
452 472 //NPC Crew and weapon
453 473 CrewMembers: [Schema.Types.Mixed],
454 474 CrewShipSalvagedWeaponSkins: [Schema.Types.Mixed],
455 475 CrewShipSalvagedWeapons: [Schema.Types.Mixed],
456 476
457
458 477 //Complete Mission\Quests
459 478 Missions: [Schema.Types.Mixed],
460 479 QuestKeys: [Schema.Types.Mixed],
461 //item like DojoKey or Boss missions key
480 //item like DojoKey or Boss missions key
462 481 LevelKeys: [Schema.Types.Mixed],
463 482 //Active quests
464 483 Quests: [Schema.Types.Mixed],
@@ -478,25 +497,22 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
478 497 //Retries rank up(3 time)
479 498 TrainingRetriesLeft: Number,
480 499
481
482 500 //you saw last played Region when you opened the star map
483 501 LastRegionPlayed: String,
484 502
485 503 //Blueprint
486 504 Recipes: [Schema.Types.Mixed],
487 505 //Crafting Blueprint(Item Name + CompletionDate)
488 PendingRecipes: [Schema.Types.Mixed],
506 PendingRecipes: [pendingRecipeSchema],
489 507
490 508 //warframe\Weapon skins
491 509 WeaponSkins: [Schema.Types.Mixed],
492 510
493
494 511 //Ayatan Item
495 512 FusionTreasures: [Schema.Types.Mixed],
496 513 //"node": "TreasureTutorial", "state": "TS_COMPLETED"
497 514 TauntHistory: [Schema.Types.Mixed],
498 515
499
500 516 //noShow2FA,VisitPrimeVault etc
501 517 WebFlags: Schema.Types.Mixed,
502 518 //Id CompletedAlerts
@@ -508,7 +524,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
508 524 //Alert->Kuva Siphon
509 525 PeriodicMissionCompletions: [Schema.Types.Mixed],
510 526
511
512 527 //Codex->LoreFragment
513 528 LoreFragmentScans: [Schema.Types.Mixed],
514 529
@@ -520,7 +535,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
520 535 ActiveDojoColorResearch: String,
521 536
522 537 SentientSpawnChanceBoosters: Schema.Types.Mixed,
523
538
524 539 QualifyingInvasions: [Schema.Types.Mixed],
525 540 FactionScores: [Number],
526 541
@@ -530,11 +545,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
530 545 //If you want change Spectre Gear id
531 546 PendingSpectreLoadouts: [Schema.Types.Mixed],
532 547
533
534 548 //New quest Email spam
535 549 //example:"ItemType": "/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestEmailItem",
536 550 EmailItems: [Schema.Types.Mixed],
537
538 551
539 552 //Profile->Wishlist
540 553 Wishlist: [String],
@@ -561,7 +574,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
561 574
562 575 //Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
563 576 PersonalGoalProgress: [Schema.Types.Mixed],
564
577
565 578 //Setting interface Style
566 579 ThemeStyle: String,
567 580 ThemeBackground: String,
@@ -579,7 +592,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
579 592 //Night Wave Challenge
580 593 SeasonChallengeHistory: [Schema.Types.Mixed],
581 594
582
583 595 //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
584 596 LibraryPersonalProgress: [Schema.Types.Mixed],
585 597 //Cephalon Simaris Daily Task
@@ -587,23 +599,23 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
587 599
588 600 //https://warframe.fandom.com/wiki/Invasion
589 601 InvasionChainProgress: [Schema.Types.Mixed],
590
602
591 603 //https://warframe.fandom.com/wiki/Parazon
592 604 DataKnives: [GenericItemSchema],
593
605
594 606 //CorpusLich or GrineerLich
595 607 NemesisAbandonedRewards: [String],
596 //CorpusLich\KuvaLich
608 //CorpusLich\KuvaLich
597 609 NemesisHistory: [Schema.Types.Mixed],
598 610 LastNemesisAllySpawnTime: Schema.Types.Mixed,
599
611
600 612 //TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
601 613 Settings: Schema.Types.Mixed,
602 614
603 //Railjack craft
615 //Railjack craft
604 616 //https://warframe.fandom.com/wiki/Rising_Tide
605 617 PersonalTechProjects: [Schema.Types.Mixed],
606
618
607 619 //Modulars lvl and exp(Railjack|Duviri)
608 620 //https://warframe.fandom.com/wiki/Intrinsics
609 621 PlayerSkills: Schema.Types.Mixed,
@@ -611,7 +623,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
611 623 //TradeBannedUntil data
612 624 TradeBannedUntil: Schema.Types.Mixed,
613 625
614
615 626 //https://warframe.fandom.com/wiki/Helminth
616 627 InfestedFoundry: Schema.Types.Mixed,
617 628 NextRefill: Schema.Types.Mixed,
@@ -624,7 +635,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
624 635 //https://warframe.fandom.com/wiki/Incarnon
625 636 EvolutionProgress: [Schema.Types.Mixed],
626 637
627
628 638 //Unknown and system
629 639 DuviriInfo: DuviriInfoSchema,
630 640 Mailbox: MailboxSchema,
@@ -650,7 +660,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
650 660 CollectibleSeries: [Schema.Types.Mixed],
651 661 HasResetAccount: Boolean,
652 662
653 //Discount Coupon
663 //Discount Coupon
654 664 PendingCoupon: Schema.Types.Mixed,
655 665 //Like BossAladV,BossCaptainVor come for you on missions % chance
656 666 DeathMarks: [String],
@@ -685,13 +695,14 @@ type InventoryDocumentProps = {
685 695 MiscItems: Types.DocumentArray<IMiscItem>;
686 696 Boosters: Types.DocumentArray<IBooster>;
687 697 OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
688 AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
698 AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>; //TODO: this should still contain _id
689 699 MechSuits: Types.DocumentArray<ISuitDatabase>;
690 700 Scoops: Types.DocumentArray<IGenericItem>;
691 701 DataKnives: Types.DocumentArray<IGenericItem>;
692 702 DrifterMelee: Types.DocumentArray<IGenericItem>;
693 703 Sentinels: Types.DocumentArray<IWeaponDatabase>;
694 704 Horses: Types.DocumentArray<IGenericItem>;
705 PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
695 706 };
696 707
697 708 type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
Modified src/routes/api.ts +5 -0
@@ -35,6 +35,8 @@ import express from "express";
35 35 import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
36 36 import { focusController } from "@/src/controllers/api/focusController";
37 37 import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController";
38 import { startRecipeController } from "@/src/controllers/api/startRecipeController";
39 import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
38 40
39 41 const apiRouter = express.Router();
40 42
@@ -62,6 +64,9 @@ apiRouter.get("/logout.php", logoutController);
62 64 apiRouter.get("/setBootLocation.php", setBootLocationController);
63 65
64 66 // post
67 // eslint-disable-next-line @typescript-eslint/no-misused-promises
68 apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
69 apiRouter.post("/startRecipe.php", startRecipeController);
65 70 apiRouter.post("/inventorySlots.php", inventorySlotsController);
66 71 apiRouter.post("/focus.php", focusController);
67 72 apiRouter.post("/artifacts.php", artifactsController);
Modified src/services/inventoryService.ts +1 -2
@@ -17,6 +17,7 @@ import {
17 17 import { IGenericUpdate } from "../types/genericUpdate";
18 18 import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
19 19 import { logger } from "@/src/utils/logger";
20 import { WeaponTypeInternal } from "@/src/services/itemDataService";
20 21
21 22 export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPresetId: Types.ObjectId) => {
22 23 try {
@@ -145,8 +146,6 @@ export const updateGeneric = async (data: IGenericUpdate, accountId: string) =>
145 146 return data;
146 147 };
147 148
148 export type WeaponTypeInternal = "LongGuns" | "Pistols" | "Melee";
149
150 149 export const addWeapon = async (
151 150 weaponType: WeaponTypeInternal,
152 151 weaponName: string,
Added src/services/itemDataService.ts +117 -0
@@ -0,0 +1,117 @@
1 import { getIndexAfter } from "@/src/helpers/stringHelpers";
2 import { logger } from "@/src/utils/logger";
3 import Items, { Buildable, Category, Item, Warframe, Weapon } from "warframe-items";
4
5 type MinWeapon = Omit<Weapon, "patchlogs">;
6 type MinItem = Omit<Item, "patchlogs">;
7
8 export const weapons: MinWeapon[] = (new Items({ category: ["Primary", "Secondary", "Melee"] }) as Weapon[]).map(
9 item => {
10 const next = { ...item };
11 delete next.patchlogs;
12 return next;
13 }
14 );
15
16 export type WeaponTypeInternal = "LongGuns" | "Pistols" | "Melee";
17
18 export const items: MinItem[] = new Items({ category: ["All"] }).map(item => {
19 const next = { ...item };
20 delete next.patchlogs;
21 return next;
22 });
23
24 export const getWeaponType = (weaponName: string) => {
25 const weaponInfo = weapons.find(i => i.uniqueName === weaponName);
26
27 if (!weaponInfo) {
28 throw new Error(`unknown weapon ${weaponName}`);
29 }
30
31 const weaponType = weaponInfo.productCategory as WeaponTypeInternal;
32
33 if (!weaponType) {
34 logger.error(`unknown weapon category for item ${weaponName}`);
35 throw new Error(`unknown weapon category for item ${weaponName}`);
36 }
37
38 return weaponType;
39 };
40
41 const getNamesObj = (category: Category) =>
42 new Items({ category: [category] }).reduce<{ [index: string]: string }>((acc, item) => {
43 acc[item.name!.replace("'S", "'s")] = item.uniqueName!;
44 return acc;
45 }, {});
46
47 export const modNames = getNamesObj("Mods");
48 export const resourceNames = getNamesObj("Resources");
49 export const miscNames = getNamesObj("Misc");
50 export const relicNames = getNamesObj("Relics");
51 export const skinNames = getNamesObj("Skins");
52 export const arcaneNames = getNamesObj("Arcanes");
53 export const gearNames = getNamesObj("Gear");
54 //logger.debug(`gear names`, { gearNames });
55
56 export const craftNames = Object.fromEntries(
57 (
58 new Items({
59 category: [
60 "Warframes",
61 "Gear",
62 "Melee",
63 "Primary",
64 "Secondary",
65 "Sentinels",
66 "Misc",
67 "Arch-Gun",
68 "Arch-Melee"
69 ]
70 }) as Warframe[]
71 )
72 .flatMap(item => item.components || [])
73 .filter(item => item.drops && item.drops[0])
74 .map(item => [item.drops![0].type, item.uniqueName])
75 );
76
77 export const blueprintNames = Object.fromEntries(
78 Object.keys(craftNames)
79 .filter(name => name.includes("Blueprint"))
80 .map(name => [name, craftNames[name]])
81 );
82
83 const buildables = items.filter(item => !!(item as Buildable).components);
84
85 export const getItemByBlueprint = (uniqueName: string): (MinItem & Buildable) | undefined => {
86 const item = buildables.find(
87 item => (item as Buildable).components?.find(component => component.uniqueName === uniqueName)
88 );
89 return item;
90 };
91
92 export const getItemCategoryByUniqueName = (uniqueName: string) => {
93 //Lotus/Types/Items/MiscItems/PolymerBundle
94
95 let splitWord = "Items/";
96 if (!uniqueName.includes("/Items/")) {
97 splitWord = "/Types/";
98 }
99
100 const index = getIndexAfter(uniqueName, splitWord);
101 if (index === -1) {
102 logger.error(`error parsing item category ${uniqueName}`);
103 throw new Error(`error parsing item category ${uniqueName}`);
104 }
105 const category = uniqueName.substring(index).split("/")[0];
106 return category;
107 };
108
109 export const getItemByUniqueName = (uniqueName: string) => {
110 const item = items.find(item => item.uniqueName === uniqueName);
111 return item;
112 };
113
114 export const getItemByName = (name: string) => {
115 const item = items.find(item => item.name === name);
116 return item;
117 };
Modified src/services/missionInventoryUpdateService .ts +8 -1
Modified src/services/purchaseService.ts +2 -1
Added src/services/recipeService.ts +74 -0
Modified src/types/inventoryTypes/inventoryTypes.ts +10 -3
Modified static/data/items.ts +0 -60