返回提交历史
Modified
package-lock.json
+4
-4
Modified
package.json
+1
-1
Modified
src/controllers/api/giveKeyChainTriggeredItemsController.ts
+7
-25
Added
src/controllers/api/giveKeyChainTriggeredMessageController.ts
+36
-0
Added
src/controllers/api/giveQuestKey.ts
+45
-0
Modified
src/controllers/api/updateQuestController.ts
+15
-10
Modified
src/models/inboxModel.ts
+7
-4
Modified
src/models/inventoryModels/inventoryModel.ts
+10
-7
Modified
src/routes/api.ts
+4
-0
Modified
src/services/inboxService.ts
+0
-1
Modified
src/services/inventoryService.ts
+11
-4
Modified
src/services/itemDataService.ts
+26
-3
Modified
src/services/questService.ts
+40
-9
Modified
src/types/inventoryTypes/inventoryTypes.ts
+1
-1
Modified
src/types/requestTypes.ts
+3
-3
XFEstudio/XFESpaceNinjaServer
feat: Quests 2 (#878)
edc3171e
代码差异
15 个文件
+210
-72
@@ -12,7 +12,7 @@
12
12
"copyfiles": "^2.4.1",
13
13
"express": "^5",
14
14
"mongoose": "^8.9.4",
15
"warframe-public-export-plus": "^0.5.24",
15
"warframe-public-export-plus": "^0.5.26",
16
16
"warframe-riven-info": "^0.1.2",
17
17
"winston": "^3.17.0",
18
18
"winston-daily-rotate-file": "^5.0.0"
@@ -4092,9 +4092,9 @@
4092
4092
}
4093
4093
},
4094
4094
"node_modules/warframe-public-export-plus": {
4095
"version": "0.5.25",
4096
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.25.tgz",
4097
"integrity": "sha512-vYEm6q7zECk+2xi9pb6KEksoNNEqSqcrbEtwuEDCySAzZJwbE8iErFtTA2ZAK81LOG42i8yDMevvldyke/Sr3A=="
4095
"version": "0.5.26",
4096
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.26.tgz",
4097
"integrity": "sha512-oRcz14nBHcwx5CgCbxw5bhesiJtVlspuHyqzjOwRu63c2Vs+1TgfqbVGdqc9sm3AZL9eJhtay+khc1h7r3BM/A=="
4098
4098
},
4099
4099
"node_modules/warframe-riven-info": {
4100
4100
"version": "0.1.2",
@@ -16,7 +16,7 @@
16
16
"copyfiles": "^2.4.1",
17
17
"express": "^5",
18
18
"mongoose": "^8.9.4",
19
"warframe-public-export-plus": "^0.5.24",
19
"warframe-public-export-plus": "^0.5.26",
20
20
"warframe-riven-info": "^0.1.2",
21
21
"winston": "^3.17.0",
22
22
"winston-daily-rotate-file": "^5.0.0"
@@ -2,40 +2,21 @@ import { RequestHandler } from "express";
2
2
import { isEmptyObject, parseString } from "@/src/helpers/general";
3
3
import { getJSONfromString } from "@/src/helpers/stringHelpers";
4
4
import { addKeyChainItems, getInventory } from "@/src/services/inventoryService";
5
import { IGroup } from "@/src/types/loginTypes";
6
import { updateQuestStage } from "@/src/services/questService";
5
7
6
8
export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
7
9
const accountId = parseString(req.query.accountId);
8
const keyChainTriggeredItemsRequest = getJSONfromString<IGiveKeyChainTriggeredItemsRequest>(
9
(req.body as string).toString()
10
);
10
const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
11
11
12
12
const inventory = await getInventory(accountId);
13
const inventoryChanges = await addKeyChainItems(inventory, keyChainTriggeredItemsRequest);
13
const inventoryChanges = await addKeyChainItems(inventory, keyChainInfo);
14
14
15
15
if (isEmptyObject(inventoryChanges)) {
16
16
throw new Error("inventory changes was empty after getting keychain items: should not happen");
17
17
}
18
18
// items were added: update quest stage's i (item was given)
19
const quest = inventory.QuestKeys.find(quest => quest.ItemType === keyChainTriggeredItemsRequest.KeyChain);
20
21
if (!quest) {
22
throw new Error(`Quest ${keyChainTriggeredItemsRequest.KeyChain} not found in QuestKeys`);
23
}
24
if (!quest.Progress) {
25
throw new Error(`Progress should always exist when giving keychain triggered items`);
26
}
27
28
const questStage = quest.Progress[keyChainTriggeredItemsRequest.ChainStage];
29
if (questStage) {
30
questStage.i = true;
31
} else {
32
const questStageIndex = quest.Progress.push({ i: true }) - 1;
33
if (questStageIndex !== keyChainTriggeredItemsRequest.ChainStage) {
34
throw new Error(
35
`Quest stage index mismatch: ${questStageIndex} !== ${keyChainTriggeredItemsRequest.ChainStage}`
36
);
37
}
38
}
19
updateQuestStage(inventory, keyChainInfo, { i: true });
39
20
40
21
await inventory.save();
41
22
res.send(inventoryChanges);
@@ -50,7 +31,8 @@ export const giveKeyChainTriggeredItemsController: RequestHandler = async (req,
50
31
//{"WishlistChanges":["/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem"],"MiscItems":[{"ItemType":"/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem","ItemCount":1}]}
51
32
};
52
33
53
export interface IGiveKeyChainTriggeredItemsRequest {
34
export interface IKeyChainRequest {
54
35
KeyChain: string;
55
36
ChainStage: number;
37
Groups?: IGroup[];
56
38
}
@@ -0,0 +1,36 @@
1
import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
2
import { IMessage } from "@/src/models/inboxModel";
3
import { createMessage } from "@/src/services/inboxService";
4
import { getInventory } from "@/src/services/inventoryService";
5
import { getKeyChainMessage } from "@/src/services/itemDataService";
6
import { getAccountIdForRequest } from "@/src/services/loginService";
7
import { updateQuestStage } from "@/src/services/questService";
8
import { RequestHandler } from "express";
9
10
export const giveKeyChainTriggeredMessageController: RequestHandler = async (req, res) => {
11
const accountId = await getAccountIdForRequest(req);
12
const keyChainInfo = JSON.parse((req.body as Buffer).toString()) as IKeyChainRequest;
13
console.log(keyChainInfo);
14
15
const keyChainMessage = getKeyChainMessage(keyChainInfo);
16
17
const message = {
18
sndr: keyChainMessage.sender,
19
msg: keyChainMessage.body,
20
sub: keyChainMessage.title,
21
att: keyChainMessage.attachments.length > 0 ? keyChainMessage.attachments : undefined,
22
icon: keyChainMessage.icon ?? "",
23
transmission: keyChainMessage.transmission ?? "",
24
highPriority: keyChainMessage.highPriority ?? false,
25
r: false
26
} satisfies IMessage;
27
28
const savedMessages = await createMessage(accountId, [message]);
29
console.log("savedMessages", savedMessages);
30
31
const inventory = await getInventory(accountId, "QuestKeys");
32
updateQuestStage(inventory, keyChainInfo, { m: true });
33
await inventory.save();
34
35
res.send(1);
36
};
@@ -0,0 +1,45 @@
1
import { getJSONfromString } from "@/src/helpers/stringHelpers";
2
import { addItem, getInventory } from "@/src/services/inventoryService";
3
import { getAccountIdForRequest } from "@/src/services/loginService";
4
import { IOid } from "@/src/types/commonTypes";
5
import { RequestHandler } from "express";
6
7
export const giveQuestKeyRewardController: RequestHandler = async (req, res) => {
8
const accountId = await getAccountIdForRequest(req);
9
const rewardRequest = getJSONfromString<IQuestKeyRewardRequest>((req.body as Buffer).toString());
10
11
if (Array.isArray(rewardRequest.reward)) {
12
throw new Error("Multiple rewards not expected");
13
}
14
15
const reward = rewardRequest.reward;
16
const inventory = await getInventory(accountId);
17
const inventoryChanges = await addItem(inventory, reward.ItemType, reward.Amount);
18
await inventory.save();
19
res.json(inventoryChanges.InventoryChanges);
20
//TODO: consider whishlist changes
21
};
22
23
export interface IQuestKeyRewardRequest {
24
reward: IQuestKeyReward;
25
}
26
27
export interface IQuestKeyReward {
28
RewardType: string;
29
CouponType: string;
30
Icon: string;
31
ItemType: string;
32
StoreItemType: string;
33
ProductCategory: string;
34
Amount: number;
35
ScalingMultiplier: number;
36
Durability: string;
37
DisplayName: string;
38
Duration: number;
39
CouponSku: number;
40
Syndicate: string;
41
Milestones: any[];
42
ChooseSetIndex: number;
43
NewSystemReward: boolean;
44
_id: IOid;
45
}
@@ -4,7 +4,8 @@ import { logger } from "@/src/utils/logger";
4
4
import { getJSONfromString } from "@/src/helpers/stringHelpers";
5
5
import { updateQuestKey, IUpdateQuestRequest } from "@/src/services/questService";
6
6
import { getQuestCompletionItems } from "@/src/services/itemDataService";
7
import { addItem, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
7
import { addItems, getInventory } from "@/src/services/inventoryService";
8
import { IInventoryChanges } from "@/src/types/purchaseTypes";
8
9
9
10
// eslint-disable-next-line @typescript-eslint/no-misused-promises
10
11
export const updateQuestController: RequestHandler = async (req, res) => {
@@ -18,24 +19,28 @@ export const updateQuestController: RequestHandler = async (req, res) => {
18
19
19
20
const inventory = await getInventory(accountId);
20
21
22
const updateQuestResponse: { CustomData?: string; InventoryChanges?: IInventoryChanges; MissionRewards: [] } = {
23
MissionRewards: []
24
};
21
25
updateQuestKey(inventory, updateQuestRequest.QuestKeys);
22
26
23
27
if (updateQuestRequest.QuestKeys[0].Completed) {
24
28
logger.debug(`completed quest ${updateQuestRequest.QuestKeys[0].ItemType} `);
25
29
const questKeyName = updateQuestRequest.QuestKeys[0].ItemType;
26
30
const questCompletionItems = getQuestCompletionItems(questKeyName);
31
logger.debug(`quest completion items`, questCompletionItems);
27
32
28
logger.debug(`quest completion items { ${questCompletionItems.map(item => item.ItemType).join(", ")} }`);
33
const inventoryChanges = await addItems(inventory, questCompletionItems);
34
inventory.ActiveQuest = "";
29
35
30
const inventoryChanges = {};
31
for (const item of questCompletionItems) {
32
const inventoryDelta = await addItem(inventory, item.ItemType, item.ItemCount);
33
combineInventoryChanges(inventoryChanges, inventoryDelta.InventoryChanges);
34
}
35
res.json({ MissionRewards: [], inventoryChanges });
36
return;
36
updateQuestResponse.InventoryChanges = inventoryChanges;
37
}
38
39
//TODO: might need to parse the custom data and add the associated items to inventory
40
if (updateQuestRequest.QuestKeys[0].CustomData) {
41
updateQuestResponse.CustomData = updateQuestRequest.QuestKeys[0].CustomData;
37
42
}
38
43
39
44
await inventory.save();
40
res.send({ MissionRewards: [] });
45
res.send(updateQuestResponse);
41
46
};
@@ -12,23 +12,26 @@ export interface IMessageClient extends Omit<IMessageDatabase, "_id" | "date" |
12
12
messageId: IOid;
13
13
}
14
14
15
export interface IMessageDatabase {
15
export interface IMessageDatabase extends IMessage {
16
16
ownerId: Types.ObjectId;
17
date: Date;
17
date: Date; //created at
18
18
_id: Types.ObjectId;
19
}
20
21
export interface IMessage {
19
22
sndr: string;
20
23
msg: string;
21
24
sub: string;
22
icon: string;
25
icon?: string;
23
26
highPriority?: boolean;
24
27
lowPrioNewPlayers?: boolean;
25
28
startDate?: Date;
26
29
endDate?: Date;
27
r?: boolean;
28
30
att?: string[];
29
31
countedAtt?: ITypeCount[];
30
32
transmission?: string;
31
33
arg?: Arg[];
34
r?: boolean;
32
35
}
33
36
34
37
export interface Arg {
@@ -479,19 +479,22 @@ const helminthResourceSchema = new Schema<IHelminthResource>(
479
479
{ _id: false }
480
480
);
481
481
482
const questProgressSchema = new Schema<IQuestStage>({
483
c: Number,
484
i: Boolean,
485
m: Boolean,
486
b: []
487
});
482
const questProgressSchema = new Schema<IQuestStage>(
483
{
484
c: Number,
485
i: Boolean,
486
m: Boolean,
487
b: []
488
},
489
{ _id: false }
490
);
488
491
489
492
const questKeysSchema = new Schema<IQuestKeyDatabase>(
490
493
{
491
494
Progress: { type: [questProgressSchema], default: undefined },
492
495
unlock: Boolean,
493
496
Completed: Boolean,
494
//CustomData: Schema.Types.Mixed,
497
CustomData: String,
495
498
CompletionDate: Date,
496
499
ItemType: String
497
500
},
@@ -82,6 +82,8 @@ import { updateQuestController } from "@/src/controllers/api/updateQuestControll
82
82
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
83
83
import { updateThemeController } from "../controllers/api/updateThemeController";
84
84
import { upgradesController } from "@/src/controllers/api/upgradesController";
85
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
86
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
85
87
86
88
const apiRouter = express.Router();
87
89
@@ -138,6 +140,8 @@ apiRouter.post("/getAlliance.php", getAllianceController);
138
140
apiRouter.post("/getVoidProjectionRewards.php", getVoidProjectionRewardsController);
139
141
apiRouter.post("/gildWeapon.php", gildWeaponController);
140
142
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
143
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
144
apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
141
145
apiRouter.post("/guildTech.php", guildTechController);
142
146
apiRouter.post("/hostSession.php", hostSessionController);
143
147
apiRouter.post("/infestedFoundry.php", infestedFoundryController);
@@ -46,7 +46,6 @@ export const createNewEventMessages = async (req: Request) => {
46
46
prev.eventMessageDate > current.eventMessageDate ? prev : current
47
47
);
48
48
49
console.log("latestEventMessage", latestEventMessage);
50
49
account.LatestEventMessageDate = new Date(latestEventMessage.eventMessageDate);
51
50
await account.save();
52
51
};
@@ -47,7 +47,7 @@ import {
47
47
} from "warframe-public-export-plus";
48
48
import { createShip } from "./shipService";
49
49
import { creditBundles, fusionBundles } from "@/src/services/missionInventoryUpdateService";
50
import { IGiveKeyChainTriggeredItemsRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
50
import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
51
51
import { toOid } from "../helpers/inventoryHelpers";
52
52
53
53
export const createInventory = async (
@@ -499,11 +499,16 @@ export const addItem = async (
499
499
500
500
export const addItems = async (
501
501
inventory: TInventoryDatabaseDocument,
502
items: ITypeCount[],
502
items: ITypeCount[] | string[],
503
503
inventoryChanges: IInventoryChanges = {}
504
504
): Promise<IInventoryChanges> => {
505
let inventoryDelta;
505
506
for (const item of items) {
506
const inventoryDelta = await addItem(inventory, item.ItemType, item.ItemCount);
507
if (typeof item === "string") {
508
inventoryDelta = await addItem(inventory, item);
509
} else {
510
inventoryDelta = await addItem(inventory, item.ItemType, item.ItemCount);
511
}
507
512
combineInventoryChanges(inventoryChanges, inventoryDelta.InventoryChanges);
508
513
}
509
514
return inventoryChanges;
@@ -1074,7 +1079,7 @@ export const updateSyndicate = (
1074
1079
*/
1075
1080
export const addKeyChainItems = async (
1076
1081
inventory: TInventoryDatabaseDocument,
1077
keyChainData: IGiveKeyChainTriggeredItemsRequest
1082
keyChainData: IKeyChainRequest
1078
1083
): Promise<IInventoryChanges> => {
1079
1084
const keyChainItems = getKeyChainItems(keyChainData);
1080
1085
@@ -1092,5 +1097,7 @@ export const addKeyChainItems = async (
1092
1097
combineInventoryChanges(inventoryChanges, inventoryChangesDelta.InventoryChanges);
1093
1098
}
1094
1099
1100
await addItems(inventory, nonStoreItems);
1101
1095
1102
return inventoryChanges;
1096
1103
};
@@ -1,4 +1,4 @@
1
import { IGiveKeyChainTriggeredItemsRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
1
import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
2
2
import { getIndexAfter } from "@/src/helpers/stringHelpers";
3
3
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
4
4
import { logger } from "@/src/utils/logger";
@@ -142,7 +142,7 @@ export const getString = (key: string, dict: Record<string, string>): string =>
142
142
return dict[key] ?? key;
143
143
};
144
144
145
export const getKeyChainItems = ({ KeyChain, ChainStage }: IGiveKeyChainTriggeredItemsRequest): string[] => {
145
export const getKeyChainItems = ({ KeyChain, ChainStage }: IKeyChainRequest): string[] => {
146
146
const chainStages = ExportKeys[KeyChain].chainStages;
147
147
if (!chainStages) {
148
148
throw new Error(`KeyChain ${KeyChain} does not contain chain stages`);
@@ -154,7 +154,9 @@ export const getKeyChainItems = ({ KeyChain, ChainStage }: IGiveKeyChainTriggere
154
154
}
155
155
156
156
if (keyChainStage.itemsToGiveWhenTriggered.length === 0) {
157
throw new Error(`No items to give for KeyChain ${KeyChain} at stage ${ChainStage}`);
157
throw new Error(
158
`client requested key chain items in KeyChain ${KeyChain} at stage ${ChainStage}, but they did not exist`
159
);
158
160
}
159
161
160
162
return keyChainStage.itemsToGiveWhenTriggered;
@@ -194,3 +196,24 @@ export const getQuestCompletionItems = (questKey: string) => {
194
196
195
197
return items;
196
198
};
199
200
export const getKeyChainMessage = ({ KeyChain, ChainStage }: IKeyChainRequest) => {
201
const chainStages = ExportKeys[KeyChain]?.chainStages;
202
if (!chainStages) {
203
throw new Error(`KeyChain ${KeyChain} does not contain chain stages`);
204
}
205
206
const keyChainStage = chainStages[ChainStage];
207
if (!keyChainStage) {
208
throw new Error(`KeyChainStage ${ChainStage} not found`);
209
}
210
211
const chainStageMessage = keyChainStage.messageToSendWhenTriggered;
212
213
if (!chainStageMessage) {
214
throw new Error(
215
`client requested key chain message in keychain ${KeyChain} at stage ${ChainStage} but they did not exist`
216
);
217
}
218
return chainStageMessage;
219
};