返回提交历史
Modified
src/controllers/api/getNewRewardSeedController.ts
+0
-2
Modified
src/models/inventoryModels/inventoryModel.ts
+1
-1
Modified
src/services/missionInventoryUpdateService.ts
+15
-3
Modified
src/services/rngService.ts
+5
-1
Modified
src/types/inventoryTypes/inventoryTypes.ts
+1
-1
Modified
src/types/requestTypes.ts
+1
-1
XFEstudio/SpaceNinjaServer
fix: generate rewards based on RewardSeed to match what's show in client (#1628)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1628 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
3f0a2bec
代码差异
6 个文件
+23
-9
@@ -1,14 +1,12 @@
1
1
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
2
2
import { generateRewardSeed } from "@/src/services/inventoryService";
3
3
import { getAccountIdForRequest } from "@/src/services/loginService";
4
import { logger } from "@/src/utils/logger";
5
4
import { RequestHandler } from "express";
6
5
7
6
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
8
7
const accountId = await getAccountIdForRequest(req);
9
8
10
9
const rewardSeed = generateRewardSeed();
11
logger.debug(`generated new reward seed: ${rewardSeed}`);
12
10
await Inventory.updateOne(
13
11
{
14
12
accountOwnerId: accountId
@@ -1213,7 +1213,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1213
1213
accountOwnerId: Schema.Types.ObjectId,
1214
1214
SubscribedToEmails: { type: Number, default: 0 },
1215
1215
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
1216
RewardSeed: Number,
1216
RewardSeed: BigInt,
1217
1217
1218
1218
//Credit
1219
1219
RegularCredits: { type: Number, default: 0 },
@@ -9,7 +9,7 @@ import {
9
9
} from "warframe-public-export-plus";
10
10
import { IMissionInventoryUpdateRequest, IRewardInfo } from "../types/requestTypes";
11
11
import { logger } from "@/src/utils/logger";
12
import { IRngResult, getRandomElement, getRandomReward } from "@/src/services/rngService";
12
import { IRngResult, SRng, getRandomElement, getRandomReward } from "@/src/services/rngService";
13
13
import { equipmentKeys, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
14
14
import {
15
15
addBooster,
@@ -31,6 +31,7 @@ import {
31
31
addShipDecorations,
32
32
addStanding,
33
33
combineInventoryChanges,
34
generateRewardSeed,
34
35
updateCurrency,
35
36
updateSyndicate
36
37
} from "@/src/services/inventoryService";
@@ -70,7 +71,12 @@ const getRotations = (rotationCount: number, tierOverride: number | undefined):
70
71
return rotatedValues;
71
72
};
72
73
73
const getRandomRewardByChance = (pool: IReward[]): IRngResult | undefined => {
74
const getRandomRewardByChance = (pool: IReward[], rng?: SRng): IRngResult | undefined => {
75
if (rng) {
76
const res = rng.randomReward(pool as IRngResult[]);
77
rng.randomFloat(); // something related to rewards multiplier
78
return res;
79
}
74
80
return getRandomReward(pool as IRngResult[]);
75
81
};
76
82
@@ -548,6 +554,11 @@ export const addMissionRewards = async (
548
554
return { MissionRewards: [] };
549
555
}
550
556
557
if (rewardInfo.rewardSeed) {
558
// We're using a reward seed, so give the client a new one in the response. On live, missionInventoryUpdate seems to always provide a fresh one in the response.
559
inventory.RewardSeed = generateRewardSeed();
560
}
561
551
562
//TODO: check double reward merging
552
563
const MissionRewards: IMissionReward[] = getRandomMissionDrops(rewardInfo, wagerTier);
553
564
logger.debug("random mission drops:", MissionRewards);
@@ -1062,6 +1073,7 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | u
1062
1073
if (rewardManifests.length != 0) {
1063
1074
logger.debug(`generating random mission rewards`, { rewardManifests, rotations });
1064
1075
}
1076
const rng = new SRng(BigInt(RewardInfo.rewardSeed ?? generateRewardSeed()) ^ 0xffffffffffffffffn);
1065
1077
rewardManifests.forEach(name => {
1066
1078
const table = ExportRewards[name];
1067
1079
if (!table) {
@@ -1070,7 +1082,7 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | u
1070
1082
}
1071
1083
for (const rotation of rotations) {
1072
1084
const rotationRewards = table[rotation];
1073
const drop = getRandomRewardByChance(rotationRewards);
1085
const drop = getRandomRewardByChance(rotationRewards, rng);
1074
1086
if (drop) {
1075
1087
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
1076
1088
}
@@ -31,7 +31,7 @@ const getRewardAtPercentage = <T extends { probability: number }>(pool: T[], per
31
31
return item;
32
32
}
33
33
}
34
throw new Error("What the fuck?");
34
return pool[pool.length - 1];
35
35
};
36
36
37
37
export const getRandomReward = <T extends { probability: number }>(pool: T[]): T | undefined => {
@@ -142,4 +142,8 @@ export class SRng {
142
142
this.state = (0x5851f42d4c957f2dn * this.state + 0x14057b7ef767814fn) & 0xffffffffffffffffn;
143
143
return (Number(this.state >> 38n) & 0xffffff) * 0.000000059604645;
144
144
}
145
146
randomReward<T extends { probability: number }>(pool: T[]): T | undefined {
147
return getRewardAtPercentage(pool, this.randomFloat());
148
}
145
149
}
@@ -194,7 +194,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
194
194
Mailbox?: IMailboxClient;
195
195
SubscribedToEmails: number;
196
196
Created: IMongoDate;
197
RewardSeed: number;
197
RewardSeed: number | bigint;
198
198
RegularCredits: number;
199
199
PremiumCredits: number;
200
200
PremiumCreditsFree: number;
@@ -141,7 +141,7 @@ export interface IRewardInfo {
141
141
EOM_AFK?: number;
142
142
rewardQualifications?: string; // did a Survival for 5 minutes and this was "1"
143
143
PurgatoryRewardQualifications?: string;
144
rewardSeed?: number;
144
rewardSeed?: number | bigint;
145
145
periodicMissionTag?: string;
146
146
147
147
// for bounties, only EOM_AFK and node are given from above, plus: