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

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

代码差异

6 个文件 +23 -9
Modified src/controllers/api/getNewRewardSeedController.ts +0 -2
@@ -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
Modified src/models/inventoryModels/inventoryModel.ts +1 -1
@@ -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 },
Modified src/services/missionInventoryUpdateService.ts +15 -3
@@ -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 }
Modified src/services/rngService.ts +5 -1
@@ -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 }
Modified src/types/inventoryTypes/inventoryTypes.ts +1 -1
@@ -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;
Modified src/types/requestTypes.ts +1 -1
@@ -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: