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: void storm rotation (#2171)

Re #1512 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2171 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

3e99e069
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

3 个文件 +78 -44
Modified src/services/worldStateService.ts +69 -0
@@ -16,6 +16,7 @@ import {
16 16 ISortie,
17 17 ISortieMission,
18 18 ISyndicateMissionInfo,
19 IVoidStorm,
19 20 IWorldState
20 21 } from "../types/worldStateTypes";
21 22 import { version_compare } from "../helpers/inventoryHelpers";
@@ -963,6 +964,61 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
963 964 };
964 965 };
965 966
967 // Not very faithful, but to avoid the same node coming up back-to-back (which is not valid), I've split these into 2 arrays which we're alternating between.
968
969 const voidStormMissionsA = {
970 VoidT1: ["CrewBattleNode519", "CrewBattleNode518", "CrewBattleNode515", "CrewBattleNode503"],
971 VoidT2: ["CrewBattleNode501", "CrewBattleNode534", "CrewBattleNode530"],
972 VoidT3: ["CrewBattleNode521", "CrewBattleNode516"],
973 VoidT4: [
974 "CrewBattleNode555",
975 "CrewBattleNode553",
976 "CrewBattleNode554",
977 "CrewBattleNode539",
978 "CrewBattleNode531",
979 "CrewBattleNode527"
980 ]
981 };
982
983 const voidStormMissionsB = {
984 VoidT1: ["CrewBattleNode509", "CrewBattleNode522", "CrewBattleNode511", "CrewBattleNode512"],
985 VoidT2: ["CrewBattleNode535", "CrewBattleNode533"],
986 VoidT3: ["CrewBattleNode524", "CrewBattleNode525"],
987 VoidT4: [
988 "CrewBattleNode542",
989 "CrewBattleNode538",
990 "CrewBattleNode543",
991 "CrewBattleNode536",
992 "CrewBattleNode550",
993 "CrewBattleNode529"
994 ]
995 };
996
997 const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
998 const activation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
999 const expiry = activation + 90 * unixTimesInMs.minute;
1000 let accum = 0;
1001 const rng = new SRng(new SRng(hour).randomInt(0, 100_000));
1002 const voidStormMissions = structuredClone(hour & 1 ? voidStormMissionsA : voidStormMissionsB);
1003 for (const tier of ["VoidT1", "VoidT1", "VoidT2", "VoidT3", "VoidT4", "VoidT4"] as const) {
1004 const idx = rng.randomInt(0, voidStormMissions[tier].length - 1);
1005 const node = voidStormMissions[tier][idx];
1006 voidStormMissions[tier].splice(idx, 1);
1007 arr.push({
1008 _id: {
1009 $oid:
1010 ((activation / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
1011 "0321e89b" +
1012 (accum++).toString().padStart(8, "0")
1013 },
1014 Node: node,
1015 Activation: { $date: { $numberLong: activation.toString() } },
1016 Expiry: { $date: { $numberLong: expiry.toString() } },
1017 ActiveMissionTier: tier
1018 });
1019 }
1020 };
1021
966 1022 const doesTimeSatsifyConstraints = (timeSecs: number): boolean => {
967 1023 if (config.worldState?.eidolonOverride) {
968 1024 const eidolonEpoch = 1391992660;
@@ -1032,6 +1088,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1032 1088 Sorties: [],
1033 1089 LiteSorties: [],
1034 1090 GlobalUpgrades: [],
1091 VoidStorms: [],
1035 1092 EndlessXpChoices: [],
1036 1093 KnownCalendarSeasons: [],
1037 1094 ...staticWorldState,
@@ -1228,6 +1285,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1228 1285 worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1));
1229 1286 }
1230 1287
1288 // Void Storms
1289 const hour = Math.trunc(timeMs / unixTimesInMs.hour);
1290 const overLastHourStormExpiry = hour * unixTimesInMs.hour + 10 * unixTimesInMs.minute;
1291 const thisHourStormActivation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
1292 if (overLastHourStormExpiry > timeMs) {
1293 pushVoidStorms(worldState.VoidStorms, hour - 2);
1294 }
1295 pushVoidStorms(worldState.VoidStorms, hour - 1);
1296 if (isBeforeNextExpectedWorldStateRefresh(timeMs, thisHourStormActivation)) {
1297 pushVoidStorms(worldState.VoidStorms, hour);
1298 }
1299
1231 1300 // Sentient Anomaly cycling every 30 minutes
1232 1301 const halfHour = Math.trunc(timeMs / (unixTimesInMs.hour / 2));
1233 1302 const tmp = {
Modified src/types/worldStateTypes.ts +9 -0
@@ -12,6 +12,7 @@ export interface IWorldState {
12 12 GlobalUpgrades: IGlobalUpgrade[];
13 13 ActiveMissions: IFissure[];
14 14 NodeOverrides: INodeOverride[];
15 VoidStorms: IVoidStorm[];
15 16 PVPChallengeInstances: IPVPChallengeInstance[];
16 17 EndlessXpChoices: IEndlessXpChoice[];
17 18 SeasonInfo?: {
@@ -131,6 +132,14 @@ export interface ILiteSortie {
131 132 }[];
132 133 }
133 134
135 export interface IVoidStorm {
136 _id: IOid;
137 Node: string;
138 Activation: IMongoDate;
139 Expiry: IMongoDate;
140 ActiveMissionTier: string;
141 }
142
134 143 export interface IPVPChallengeInstance {
135 144 _id: IOid;
136 145 challengeTypeRefID: string;
Modified static/fixed_responses/worldState/worldState.json +0 -44
@@ -2562,50 +2562,6 @@
2562 2562 ]
2563 2563 }
2564 2564 ],
2565 "VoidStorms": [
2566 {
2567 "_id": { "$oid": "663a7581ced28e18f694b550" },
2568 "Node": "CrewBattleNode519",
2569 "Activation": { "$date": { "$numberLong": "1715109601821" } },
2570 "Expiry": { "$date": { "$numberLong": "2000000000000" } },
2571 "ActiveMissionTier": "VoidT1"
2572 },
2573 {
2574 "_id": { "$oid": "663a7581ced28e18f694b551" },
2575 "Node": "CrewBattleNode515",
2576 "Activation": { "$date": { "$numberLong": "1715109601825" } },
2577 "Expiry": { "$date": { "$numberLong": "2000000000000" } },
2578 "ActiveMissionTier": "VoidT1"
2579 },
2580 {
2581 "_id": { "$oid": "663a7581ced28e18f694b554" },
2582 "Node": "CrewBattleNode536",
2583 "Activation": { "$date": { "$numberLong": "1715109601832" } },
2584 "Expiry": { "$date": { "$numberLong": "2000000000000" } },
2585 "ActiveMissionTier": "VoidT4"
2586 },
2587 {
2588 "_id": { "$oid": "663a7581ced28e18f694b555" },
2589 "Node": "CrewBattleNode539",
2590 "Activation": { "$date": { "$numberLong": "1715109601834" } },
2591 "Expiry": { "$date": { "$numberLong": "2000000000000" } },
2592 "ActiveMissionTier": "VoidT4"
2593 },
2594 {
2595 "_id": { "$oid": "663a7581ced28e18f694b553" },
2596 "Node": "CrewBattleNode521",
2597 "Activation": { "$date": { "$numberLong": "1715109601829" } },
2598 "Expiry": { "$date": { "$numberLong": "2000000000000" } },
2599 "ActiveMissionTier": "VoidT3"
2600 },
2601 {
2602 "_id": { "$oid": "663a7581ced28e18f694b552" },
2603 "Node": "CrewBattleNode535",
2604 "Activation": { "$date": { "$numberLong": "1715109601827" } },
2605 "Expiry": { "$date": { "$numberLong": "2000000000000" } },
2606 "ActiveMissionTier": "VoidT2"
2607 }
2608 ],
2609 2565 "PrimeAccessAvailability": { "State": "PRIME1" },
2610 2566 "PrimeVaultAvailabilities": [false, false, false, false, false],
2611 2567 "PrimeTokenAvailability": true,