forked from OpenWF/SpaceNinjaServer
		
	feat: dynamic void fissure missions
This commit is contained in:
		
							parent
							
								
									61a8d01f64
								
							
						
					
					
						commit
						45bc292237
					
				@ -1,6 +1,15 @@
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
import { getWorldState } from "@/src/services/worldStateService";
 | 
			
		||||
import { getWorldState, populateFissures } from "@/src/services/worldStateService";
 | 
			
		||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
 | 
			
		||||
 | 
			
		||||
export const worldStateController: RequestHandler = (req, res) => {
 | 
			
		||||
    res.json(getWorldState(req.query.buildLabel as string | undefined));
 | 
			
		||||
export const worldStateController: RequestHandler = async (req, res) => {
 | 
			
		||||
    const buildLabel = req.query.buildLabel as string | undefined;
 | 
			
		||||
    const worldState = getWorldState(buildLabel);
 | 
			
		||||
 | 
			
		||||
    // Omitting void fissures for versions prior to Dante Unbound to avoid script errors.
 | 
			
		||||
    if (!buildLabel || version_compare(buildLabel, "2024.03.24.20.00") >= 0) {
 | 
			
		||||
        await populateFissures(worldState);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    res.json(worldState);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@ import { JSONStringify } from "json-with-bigint";
 | 
			
		||||
import { startWebServer } from "./services/webService";
 | 
			
		||||
 | 
			
		||||
import { validateConfig } from "@/src/services/configWatcherService";
 | 
			
		||||
import { updateWorldStateCollections } from "./services/worldStateService";
 | 
			
		||||
 | 
			
		||||
// Patch JSON.stringify to work flawlessly with Bigints.
 | 
			
		||||
JSON.stringify = JSONStringify;
 | 
			
		||||
@ -33,6 +34,11 @@ mongoose
 | 
			
		||||
    .then(() => {
 | 
			
		||||
        logger.info("Connected to MongoDB");
 | 
			
		||||
        startWebServer();
 | 
			
		||||
 | 
			
		||||
        void updateWorldStateCollections();
 | 
			
		||||
        setInterval(() => {
 | 
			
		||||
            void updateWorldStateCollections();
 | 
			
		||||
        }, 60_000);
 | 
			
		||||
    })
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        if (error instanceof Error) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								src/models/worldStateModel.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/models/worldStateModel.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
import { IFissureDatabase } from "@/src/types/worldStateTypes";
 | 
			
		||||
import { model, Schema } from "mongoose";
 | 
			
		||||
 | 
			
		||||
const fissureSchema = new Schema<IFissureDatabase>({
 | 
			
		||||
    Activation: Date,
 | 
			
		||||
    Expiry: Date,
 | 
			
		||||
    Node: String, // must be unique
 | 
			
		||||
    Modifier: String,
 | 
			
		||||
    Hard: Boolean
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
fissureSchema.index({ Expiry: 1 }, { expireAfterSeconds: 0 }); // With this, MongoDB will automatically delete expired entries.
 | 
			
		||||
 | 
			
		||||
export const Fissure = model<IFissureDatabase>("Fissure", fissureSchema);
 | 
			
		||||
@ -1,12 +1,13 @@
 | 
			
		||||
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
 | 
			
		||||
import fissureMissions from "@/static/fixed_responses/worldState/fissureMissions.json";
 | 
			
		||||
import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json";
 | 
			
		||||
import sortieTilesetMissions from "@/static/fixed_responses/worldState/sortieTilesetMissions.json";
 | 
			
		||||
import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json";
 | 
			
		||||
import { buildConfig } from "@/src/services/buildConfigService";
 | 
			
		||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
 | 
			
		||||
import { config } from "@/src/services/configService";
 | 
			
		||||
import { SRng } from "@/src/services/rngService";
 | 
			
		||||
import { ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus";
 | 
			
		||||
import { getRandomElement, getRandomInt, SRng } from "@/src/services/rngService";
 | 
			
		||||
import { eMissionType, ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus";
 | 
			
		||||
import {
 | 
			
		||||
    ICalendarDay,
 | 
			
		||||
    ICalendarEvent,
 | 
			
		||||
@ -21,8 +22,9 @@ import {
 | 
			
		||||
    IWorldState,
 | 
			
		||||
    TCircuitGameMode
 | 
			
		||||
} from "../types/worldStateTypes";
 | 
			
		||||
import { version_compare } from "../helpers/inventoryHelpers";
 | 
			
		||||
import { toMongoDate, toOid, version_compare } from "../helpers/inventoryHelpers";
 | 
			
		||||
import { logger } from "../utils/logger";
 | 
			
		||||
import { Fissure } from "../models/worldStateModel";
 | 
			
		||||
 | 
			
		||||
const sortieBosses = [
 | 
			
		||||
    "SORTIE_BOSS_HYENA",
 | 
			
		||||
@ -1089,6 +1091,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
			
		||||
        Alerts: [],
 | 
			
		||||
        Sorties: [],
 | 
			
		||||
        LiteSorties: [],
 | 
			
		||||
        ActiveMissions: [],
 | 
			
		||||
        GlobalUpgrades: [],
 | 
			
		||||
        VoidStorms: [],
 | 
			
		||||
        EndlessXpChoices: [],
 | 
			
		||||
@ -1097,14 +1100,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
			
		||||
        SyndicateMissions: [...staticWorldState.SyndicateMissions]
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Omit void fissures for versions prior to Dante Unbound to avoid script errors.
 | 
			
		||||
    if (buildLabel && version_compare(buildLabel, "2024.03.24.20.00") < 0) {
 | 
			
		||||
        worldState.ActiveMissions = [];
 | 
			
		||||
        if (version_compare(buildLabel, "2017.10.12.17.04") < 0) {
 | 
			
		||||
    // Old versions seem to really get hung up on not being able to load these.
 | 
			
		||||
    if (buildLabel && version_compare(buildLabel, "2017.10.12.17.04") < 0) {
 | 
			
		||||
        worldState.PVPChallengeInstances = [];
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (config.worldState?.starDays) {
 | 
			
		||||
        worldState.Goals.push({
 | 
			
		||||
@ -1343,6 +1342,24 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
			
		||||
    return worldState;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const populateFissures = async (worldState: IWorldState): Promise<void> => {
 | 
			
		||||
    const fissures = await Fissure.find({});
 | 
			
		||||
    for (const fissure of fissures) {
 | 
			
		||||
        const meta = ExportRegions[fissure.Node];
 | 
			
		||||
        worldState.ActiveMissions.push({
 | 
			
		||||
            _id: toOid(fissure._id),
 | 
			
		||||
            Region: meta.systemIndex + 1,
 | 
			
		||||
            Seed: 1337,
 | 
			
		||||
            Activation: toMongoDate(fissure.Activation),
 | 
			
		||||
            Expiry: toMongoDate(fissure.Expiry),
 | 
			
		||||
            Node: fissure.Node,
 | 
			
		||||
            MissionType: eMissionType[meta.missionIndex].tag,
 | 
			
		||||
            Modifier: fissure.Modifier,
 | 
			
		||||
            Hard: fissure.Hard
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const idToBountyCycle = (id: string): number => {
 | 
			
		||||
    return Math.trunc((parseInt(id.substring(0, 8), 16) * 1000) / 9000_000);
 | 
			
		||||
};
 | 
			
		||||
@ -1470,3 +1487,59 @@ const nightwaveTagToSeason: Record<string, number> = {
 | 
			
		||||
    RadioLegionIntermissionSyndicate: 1, // Intermission I
 | 
			
		||||
    RadioLegionSyndicate: 0 // The Wolf of Saturn Six
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const updateWorldStateCollections = async (): Promise<void> => {
 | 
			
		||||
    const fissures = await Fissure.find();
 | 
			
		||||
 | 
			
		||||
    const activeNodes = new Set<string>();
 | 
			
		||||
    for (const fissure of fissures) {
 | 
			
		||||
        activeNodes.add(fissure.Node);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const tierToFurthestExpiry: Record<string, number> = {
 | 
			
		||||
        VoidT1: 0,
 | 
			
		||||
        VoidT2: 0,
 | 
			
		||||
        VoidT3: 0,
 | 
			
		||||
        VoidT4: 0,
 | 
			
		||||
        VoidT5: 0,
 | 
			
		||||
        VoidT6: 0,
 | 
			
		||||
        VoidT1Hard: 0,
 | 
			
		||||
        VoidT2Hard: 0,
 | 
			
		||||
        VoidT3Hard: 0,
 | 
			
		||||
        VoidT4Hard: 0,
 | 
			
		||||
        VoidT5Hard: 0,
 | 
			
		||||
        VoidT6Hard: 0
 | 
			
		||||
    };
 | 
			
		||||
    for (const fissure of fissures) {
 | 
			
		||||
        const key = fissure.Modifier + (fissure.Hard ? "Hard" : "");
 | 
			
		||||
        tierToFurthestExpiry[key] = Math.max(tierToFurthestExpiry[key], fissure.Expiry.getTime());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const deadline = Date.now() - 6 * unixTimesInMs.minute;
 | 
			
		||||
    for (const [tier, expiry] of Object.entries(tierToFurthestExpiry)) {
 | 
			
		||||
        if (expiry < deadline) {
 | 
			
		||||
            const numFissures = getRandomInt(1, 3);
 | 
			
		||||
            for (let i = 0; i != numFissures; ++i) {
 | 
			
		||||
                const modifier = tier.replace("Hard", "") as
 | 
			
		||||
                    | "VoidT1"
 | 
			
		||||
                    | "VoidT2"
 | 
			
		||||
                    | "VoidT3"
 | 
			
		||||
                    | "VoidT4"
 | 
			
		||||
                    | "VoidT5"
 | 
			
		||||
                    | "VoidT6";
 | 
			
		||||
                let node: string;
 | 
			
		||||
                do {
 | 
			
		||||
                    node = getRandomElement(fissureMissions[modifier])!;
 | 
			
		||||
                } while (activeNodes.has(node));
 | 
			
		||||
                activeNodes.add(node);
 | 
			
		||||
                await Fissure.insertOne({
 | 
			
		||||
                    Activation: new Date(),
 | 
			
		||||
                    Expiry: new Date(Date.now() + getRandomInt(60, 120) * unixTimesInMs.minute),
 | 
			
		||||
                    Node: node,
 | 
			
		||||
                    Modifier: modifier,
 | 
			
		||||
                    Hard: tier.indexOf("Hard") != -1 ? true : undefined
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -9,8 +9,8 @@ export interface IWorldState {
 | 
			
		||||
    Sorties: ISortie[];
 | 
			
		||||
    LiteSorties: ILiteSortie[];
 | 
			
		||||
    SyndicateMissions: ISyndicateMissionInfo[];
 | 
			
		||||
    GlobalUpgrades: IGlobalUpgrade[];
 | 
			
		||||
    ActiveMissions: IFissure[];
 | 
			
		||||
    GlobalUpgrades: IGlobalUpgrade[];
 | 
			
		||||
    NodeOverrides: INodeOverride[];
 | 
			
		||||
    VoidStorms: IVoidStorm[];
 | 
			
		||||
    PVPChallengeInstances: IPVPChallengeInstance[];
 | 
			
		||||
@ -86,6 +86,14 @@ export interface IFissure {
 | 
			
		||||
    Hard?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IFissureDatabase {
 | 
			
		||||
    Activation: Date;
 | 
			
		||||
    Expiry: Date;
 | 
			
		||||
    Node: string;
 | 
			
		||||
    Modifier: "VoidT1" | "VoidT2" | "VoidT3" | "VoidT4" | "VoidT5" | "VoidT6";
 | 
			
		||||
    Hard?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface INodeOverride {
 | 
			
		||||
    _id: IOid;
 | 
			
		||||
    Activation?: IMongoDate;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										170
									
								
								static/fixed_responses/worldState/fissureMissions.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								static/fixed_responses/worldState/fissureMissions.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,170 @@
 | 
			
		||||
{
 | 
			
		||||
    "VoidT1": [
 | 
			
		||||
        "SolNode23",
 | 
			
		||||
        "SolNode66",
 | 
			
		||||
        "SolNode45",
 | 
			
		||||
        "SolNode41",
 | 
			
		||||
        "SolNode59",
 | 
			
		||||
        "SolNode39",
 | 
			
		||||
        "SolNode75",
 | 
			
		||||
        "SolNode113",
 | 
			
		||||
        "SolNode85",
 | 
			
		||||
        "SolNode58",
 | 
			
		||||
        "SolNode101",
 | 
			
		||||
        "SolNode109",
 | 
			
		||||
        "SolNode26",
 | 
			
		||||
        "SolNode15",
 | 
			
		||||
        "SolNode61",
 | 
			
		||||
        "SolNode123",
 | 
			
		||||
        "SolNode16",
 | 
			
		||||
        "SolNode79",
 | 
			
		||||
        "SolNode2",
 | 
			
		||||
        "SolNode22",
 | 
			
		||||
        "SolNode68",
 | 
			
		||||
        "SolNode89",
 | 
			
		||||
        "SolNode11",
 | 
			
		||||
        "SolNode46",
 | 
			
		||||
        "SolNode36",
 | 
			
		||||
        "SolNode27",
 | 
			
		||||
        "SolNode14",
 | 
			
		||||
        "SolNode106",
 | 
			
		||||
        "SolNode30",
 | 
			
		||||
        "SolNode107",
 | 
			
		||||
        "SolNode63",
 | 
			
		||||
        "SolNode128"
 | 
			
		||||
    ],
 | 
			
		||||
    "VoidT2": [
 | 
			
		||||
        "SolNode141",
 | 
			
		||||
        "SolNode149",
 | 
			
		||||
        "SolNode10",
 | 
			
		||||
        "SolNode93",
 | 
			
		||||
        "SettlementNode11",
 | 
			
		||||
        "SolNode137",
 | 
			
		||||
        "SolNode132",
 | 
			
		||||
        "SolNode73",
 | 
			
		||||
        "SolNode82",
 | 
			
		||||
        "SolNode25",
 | 
			
		||||
        "SolNode88",
 | 
			
		||||
        "SolNode126",
 | 
			
		||||
        "SolNode135",
 | 
			
		||||
        "SolNode74",
 | 
			
		||||
        "SettlementNode15",
 | 
			
		||||
        "SolNode147",
 | 
			
		||||
        "SolNode67",
 | 
			
		||||
        "SolNode20",
 | 
			
		||||
        "SolNode42",
 | 
			
		||||
        "SolNode18",
 | 
			
		||||
        "SolNode31",
 | 
			
		||||
        "SolNode139",
 | 
			
		||||
        "SettlementNode12",
 | 
			
		||||
        "SolNode100",
 | 
			
		||||
        "SolNode140",
 | 
			
		||||
        "SolNode70",
 | 
			
		||||
        "SettlementNode1",
 | 
			
		||||
        "SettlementNode14",
 | 
			
		||||
        "SolNode50",
 | 
			
		||||
        "SettlementNode2",
 | 
			
		||||
        "SolNode146",
 | 
			
		||||
        "SettlementNode3",
 | 
			
		||||
        "SolNode97",
 | 
			
		||||
        "SolNode125",
 | 
			
		||||
        "SolNode19",
 | 
			
		||||
        "SolNode121",
 | 
			
		||||
        "SolNode96",
 | 
			
		||||
        "SolNode131"
 | 
			
		||||
    ],
 | 
			
		||||
    "VoidT3": [
 | 
			
		||||
        "SolNode62",
 | 
			
		||||
        "SolNode17",
 | 
			
		||||
        "SolNode403",
 | 
			
		||||
        "SolNode6",
 | 
			
		||||
        "SolNode118",
 | 
			
		||||
        "SolNode211",
 | 
			
		||||
        "SolNode217",
 | 
			
		||||
        "SolNode401",
 | 
			
		||||
        "SolNode64",
 | 
			
		||||
        "SolNode405",
 | 
			
		||||
        "SolNode84",
 | 
			
		||||
        "SolNode402",
 | 
			
		||||
        "SolNode408",
 | 
			
		||||
        "SolNode122",
 | 
			
		||||
        "SolNode57",
 | 
			
		||||
        "SolNode216",
 | 
			
		||||
        "SolNode205",
 | 
			
		||||
        "SolNode215",
 | 
			
		||||
        "SolNode404",
 | 
			
		||||
        "SolNode209",
 | 
			
		||||
        "SolNode406",
 | 
			
		||||
        "SolNode204",
 | 
			
		||||
        "SolNode203",
 | 
			
		||||
        "SolNode409",
 | 
			
		||||
        "SolNode400",
 | 
			
		||||
        "SolNode212",
 | 
			
		||||
        "SolNode1",
 | 
			
		||||
        "SolNode412",
 | 
			
		||||
        "SolNode49",
 | 
			
		||||
        "SolNode78",
 | 
			
		||||
        "SolNode410",
 | 
			
		||||
        "SolNode407",
 | 
			
		||||
        "SolNode220"
 | 
			
		||||
    ],
 | 
			
		||||
    "VoidT4": [
 | 
			
		||||
        "SolNode188",
 | 
			
		||||
        "SolNode403",
 | 
			
		||||
        "SolNode189",
 | 
			
		||||
        "SolNode21",
 | 
			
		||||
        "SolNode102",
 | 
			
		||||
        "SolNode171",
 | 
			
		||||
        "SolNode196",
 | 
			
		||||
        "SolNode184",
 | 
			
		||||
        "SolNode185",
 | 
			
		||||
        "SolNode76",
 | 
			
		||||
        "SolNode195",
 | 
			
		||||
        "SolNode164",
 | 
			
		||||
        "SolNode401",
 | 
			
		||||
        "SolNode405",
 | 
			
		||||
        "SolNode56",
 | 
			
		||||
        "SolNode402",
 | 
			
		||||
        "SolNode408",
 | 
			
		||||
        "SolNode4",
 | 
			
		||||
        "SolNode181",
 | 
			
		||||
        "SolNode406",
 | 
			
		||||
        "SolNode162",
 | 
			
		||||
        "SolNode72",
 | 
			
		||||
        "SolNode407",
 | 
			
		||||
        "SolNode177",
 | 
			
		||||
        "SolNode404",
 | 
			
		||||
        "SolNode400",
 | 
			
		||||
        "SolNode409",
 | 
			
		||||
        "SolNode43",
 | 
			
		||||
        "SolNode166",
 | 
			
		||||
        "SolNode172",
 | 
			
		||||
        "SolNode412",
 | 
			
		||||
        "SolNode187",
 | 
			
		||||
        "SolNode38",
 | 
			
		||||
        "SolNode175",
 | 
			
		||||
        "SolNode81",
 | 
			
		||||
        "SolNode48",
 | 
			
		||||
        "SolNode410",
 | 
			
		||||
        "SolNode153",
 | 
			
		||||
        "SolNode173"
 | 
			
		||||
    ],
 | 
			
		||||
    "VoidT5": [
 | 
			
		||||
        "SolNode747",
 | 
			
		||||
        "SolNode743",
 | 
			
		||||
        "SolNode742",
 | 
			
		||||
        "SolNode744",
 | 
			
		||||
        "SolNode745",
 | 
			
		||||
        "SolNode748",
 | 
			
		||||
        "SolNode746",
 | 
			
		||||
        "SolNode741"
 | 
			
		||||
    ],
 | 
			
		||||
    "VoidT6": [
 | 
			
		||||
        "SolNode717",
 | 
			
		||||
        "SolNode309",
 | 
			
		||||
        "SolNode718",
 | 
			
		||||
        "SolNode232",
 | 
			
		||||
        "SolNode230",
 | 
			
		||||
        "SolNode310"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
@ -327,195 +327,6 @@
 | 
			
		||||
      "Nodes": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "ActiveMissions": [
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a7509d93367863785932d" },
 | 
			
		||||
      "Region": 15,
 | 
			
		||||
      "Seed": 80795,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715107081517" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode400",
 | 
			
		||||
      "MissionType": "MT_EXTERMINATION",
 | 
			
		||||
      "Modifier": "VoidT3",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a75f959a5964cadb39879" },
 | 
			
		||||
      "Region": 19,
 | 
			
		||||
      "Seed": 32067,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715107321237" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode747",
 | 
			
		||||
      "MissionType": "MT_INTEL",
 | 
			
		||||
      "Modifier": "VoidT5",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a779d3e347839ff301814" },
 | 
			
		||||
      "Region": 7,
 | 
			
		||||
      "Seed": 51739,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715107741454" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode64",
 | 
			
		||||
      "MissionType": "MT_TERRITORY",
 | 
			
		||||
      "Modifier": "VoidT3"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a77d916c199f4644ee67d" },
 | 
			
		||||
      "Region": 17,
 | 
			
		||||
      "Seed": 61179,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715107801647" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode718",
 | 
			
		||||
      "MissionType": "MT_ALCHEMY",
 | 
			
		||||
      "Modifier": "VoidT6"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a78c98a609b49b8410726" },
 | 
			
		||||
      "Region": 3,
 | 
			
		||||
      "Seed": 9520,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715108041501" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode79",
 | 
			
		||||
      "MissionType": "MT_INTEL",
 | 
			
		||||
      "Modifier": "VoidT1",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a7df15eeabaac79b0a061" },
 | 
			
		||||
      "Region": 6,
 | 
			
		||||
      "Seed": 48861,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715109361974" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode67",
 | 
			
		||||
      "MissionType": "MT_INTEL",
 | 
			
		||||
      "Modifier": "VoidT2",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a7df25eeabaac79b0a062" },
 | 
			
		||||
      "Region": 5,
 | 
			
		||||
      "Seed": 13550,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715109361974" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode10",
 | 
			
		||||
      "MissionType": "MT_SABOTAGE",
 | 
			
		||||
      "Modifier": "VoidT2",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a83cdec0d5181435f1324" },
 | 
			
		||||
      "Region": 19,
 | 
			
		||||
      "Seed": 39392,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715110861506" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode742",
 | 
			
		||||
      "MissionType": "MT_DEFENSE",
 | 
			
		||||
      "Modifier": "VoidT5"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a83cdec0d5181435f1325" },
 | 
			
		||||
      "Region": 19,
 | 
			
		||||
      "Seed": 88668,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715110861506" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode743",
 | 
			
		||||
      "MissionType": "MT_MOBILE_DEFENSE",
 | 
			
		||||
      "Modifier": "VoidT5"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a83cdec0d5181435f1326" },
 | 
			
		||||
      "Region": 19,
 | 
			
		||||
      "Seed": 73823,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715110861506" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode741",
 | 
			
		||||
      "MissionType": "MT_ASSAULT",
 | 
			
		||||
      "Modifier": "VoidT5"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a878d23d1514873170466" },
 | 
			
		||||
      "Region": 9,
 | 
			
		||||
      "Seed": 88696,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715111821951" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode4",
 | 
			
		||||
      "MissionType": "MT_EXTERMINATION",
 | 
			
		||||
      "Modifier": "VoidT4",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a887d4903098c10992fe6" },
 | 
			
		||||
      "Region": 6,
 | 
			
		||||
      "Seed": 66337,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112061729" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode18",
 | 
			
		||||
      "MissionType": "MT_TERRITORY",
 | 
			
		||||
      "Modifier": "VoidT2"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a887d4903098c10992fe7" },
 | 
			
		||||
      "Region": 10,
 | 
			
		||||
      "Seed": 5135,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112061729" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode149",
 | 
			
		||||
      "MissionType": "MT_DEFENSE",
 | 
			
		||||
      "Modifier": "VoidT2"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a8931586c301b1fbe63d3" },
 | 
			
		||||
      "Region": 15,
 | 
			
		||||
      "Seed": 32180,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112241196" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode408",
 | 
			
		||||
      "MissionType": "MT_DEFENSE",
 | 
			
		||||
      "Modifier": "VoidT4"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a8931586c301b1fbe63d4" },
 | 
			
		||||
      "Region": 12,
 | 
			
		||||
      "Seed": 22521,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112241196" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode181",
 | 
			
		||||
      "MissionType": "MT_EXTERMINATION",
 | 
			
		||||
      "Modifier": "VoidT4"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a8931586c301b1fbe63d5" },
 | 
			
		||||
      "Region": 2,
 | 
			
		||||
      "Seed": 28500,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112241196" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode128",
 | 
			
		||||
      "MissionType": "MT_EXTERMINATION",
 | 
			
		||||
      "Modifier": "VoidT1"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a8931586c301b1fbe63d6" },
 | 
			
		||||
      "Region": 3,
 | 
			
		||||
      "Seed": 24747,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112241196" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode26",
 | 
			
		||||
      "MissionType": "MT_DEFENSE",
 | 
			
		||||
      "Modifier": "VoidT1"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "_id": { "$oid": "663a8931586c301b1fbe63d7" },
 | 
			
		||||
      "Region": 17,
 | 
			
		||||
      "Seed": 63914,
 | 
			
		||||
      "Activation": { "$date": { "$numberLong": "1715112241196" } },
 | 
			
		||||
      "Expiry": { "$date": { "$numberLong": "2000000000000" } },
 | 
			
		||||
      "Node": "SolNode717",
 | 
			
		||||
      "MissionType": "MT_SURVIVAL",
 | 
			
		||||
      "Modifier": "VoidT6",
 | 
			
		||||
      "Hard": true
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "NodeOverrides": [
 | 
			
		||||
    { "_id": { "$oid": "549b18e9b029cef5991d6aec" }, "Node": "EuropaHUB", "Hide": true },
 | 
			
		||||
    { "_id": { "$oid": "54a1737aeb658f6cbccf70ff" }, "Node": "ErisHUB", "Hide": true },
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user