返回提交历史
Modified
src/services/worldStateService.ts
+59
-8
Modified
src/types/worldStateTypes.ts
+1
-1
XFEstudio/XFESpaceNinjaServer
feat: sortie seed validation (#3722)
Closes #2833 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3722 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
d38a405c
代码差异
2 个文件
+60
-9
@@ -601,8 +601,7 @@ const pushTilesetModifiers = (modifiers: string[], tileset: TSortieTileset): voi
601
601
};
602
602
603
603
export const getSortie = (day: number): ISortie => {
604
const seed = new SRng(day).randomInt(0, 100_000);
605
const rng = new SRng(seed);
604
const rng = new SRng(new SRng(day).randomInt(0, 100_000));
606
605
607
606
const boss = rng.randomElement(sortieBosses)!;
608
607
const enemyFaction = sortieBossToFaction[boss];
@@ -682,7 +681,7 @@ export const getSortie = (day: number): ISortie => {
682
681
const tileset = sortieTilesets[node as keyof typeof sortieTilesets] as TSortieTileset;
683
682
pushTilesetModifiers(modifiers, tileset);
684
683
685
const missionType = rng.randomElement(sortieTilesetMissions[tileset])!;
684
const missionType = rng.randomElement(sortieTilesetMissions[tileset])! as TMissionType;
686
685
687
686
if (missionTypes.has(missionType) || missionType == "MT_ASSASSINATION") {
688
687
i--;
@@ -709,6 +708,11 @@ export const getSortie = (day: number): ISortie => {
709
708
missionTypes.add(missionType);
710
709
}
711
710
711
let clientSeed = rng.randomInt(0, 100_000);
712
while (!validateSortieSeed(clientSeed, selectedNodes)) {
713
clientSeed = rng.randomInt(0, 100_000);
714
}
715
712
716
const dayStart = getSortieTime(day);
713
717
const dayEnd = getSortieTime(day + 1);
714
718
return {
@@ -716,16 +720,63 @@ export const getSortie = (day: number): ISortie => {
716
720
Activation: { $date: { $numberLong: dayStart.toString() } },
717
721
Expiry: { $date: { $numberLong: dayEnd.toString() } },
718
722
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
719
Seed: selectedNodes.find(
720
x => x.tileset == "CorpusIcePlanetTileset" || x.tileset == "CorpusIcePlanetTilesetCaves"
721
)
722
? 2081 // this seed produces 12 zeroes in a row if asked to pick (0, 1); this way the CorpusIcePlanetTileset/CorpusIcePlanetTilesetCaves image is always index 0, the 'correct' choice.
723
: seed,
723
Seed: clientSeed,
724
724
Boss: boss,
725
725
Variants: selectedNodes
726
726
};
727
727
};
728
728
729
const SORTIE_FALLBACK_MISSION_TYPES: TMissionType[] = [
730
"MT_EXTERMINATION",
731
"MT_SURVIVAL",
732
"MT_RESCUE",
733
"MT_SABOTAGE",
734
//"MT_CAPTURE",
735
"MT_INTEL",
736
"MT_DEFENSE",
737
"MT_MOBILE_DEFENSE",
738
"MT_TERRITORY",
739
"MT_RETRIEVAL",
740
"MT_HIVE",
741
"MT_EXCAVATE",
742
"MT_ARTIFACT"
743
];
744
745
const validateSortieSeed = (seed: number, variants: ISortieMission[]): boolean => {
746
const rng = new SRng(seed);
747
for (const variant of variants) {
748
if (variant.missionType != "MT_ASSASSINATION") {
749
const tileset = ExportTilesets[variant.tileset];
750
let missionPermutation = tileset.missions[variant.missionType];
751
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
752
if (!missionPermutation) {
753
const options = SORTIE_FALLBACK_MISSION_TYPES.filter(missionType => missionType in tileset.missions);
754
const replacementType = options[rng.randomInt(0, options.length - 1)];
755
missionPermutation = tileset.missions[replacementType];
756
/*logger.debug(
757
`${variant.missionType} not supported by ${variant.tileset}; picking ${replacementType} instead`
758
);*/
759
}
760
if (missionPermutation.enemySpecs?.length) {
761
rng.randomInt(1, missionPermutation.enemySpecs.length);
762
}
763
if (missionPermutation.extraEnemySpecs?.length) {
764
rng.randomInt(1, missionPermutation.extraEnemySpecs.length);
765
}
766
rng.randomFloat(); // difficulty
767
}
768
if (variant.missionType != "MT_ARENA" && variant.missionType != "MT_JUNCTION") {
769
const locationTextureIndex = rng.randomInt(0, 1); // In general, each tileset has 2 texture options (there are exceptions of course, like MT_ARENA and MT_JUNCTION).
770
if (variant.tileset == "CorpusIcePlanetTileset" || variant.tileset == "CorpusIcePlanetTilesetCaves") {
771
if (locationTextureIndex != 0) {
772
return false; // For the corpus ice planet tileset, index 1 is an infested corpus ship image, which we don't want.
773
}
774
}
775
}
776
}
777
return true;
778
};
779
729
780
interface IRotatingSeasonChallengePools {
730
781
daily: string[];
731
782
weekly: string[];
@@ -274,7 +274,7 @@ export interface ISortie {
274
274
}
275
275
276
276
export interface ISortieMission {
277
missionType: string;
277
missionType: TMissionType;
278
278
modifierType: string;
279
279
node: string;
280
280
tileset: string;