Compare commits

..

13 Commits
main ... main

Author SHA1 Message Date
35d5c01203 fix: login failure on u29 heart of deimos and below (#1959)
Reviewed-on: OpenWF/SpaceNinjaServer#1959
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-02 04:03:42 -07:00
8f8bc5b364 fix: don't set G3/Zanuka death marks by default (#1950)
These should only be set to true after completing an invasion for the enemy faction. Re #1097

Reviewed-on: OpenWF/SpaceNinjaServer#1950
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:55:01 -07:00
a8227ce54c feat: cure vasca virus (#1949)
Closes #1946

Reviewed-on: OpenWF/SpaceNinjaServer#1949
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:54:50 -07:00
ec9dc2aa5f fix: multiply standing cost by purchase quantity (#1948)
Closes #1945

Reviewed-on: OpenWF/SpaceNinjaServer#1948
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:54:27 -07:00
f7906c91e3 fix: ignore purchaseQuantity for webui add items (#1944)
Closes #1942

Reviewed-on: OpenWF/SpaceNinjaServer#1944
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:54:04 -07:00
159598979d fix: don't duplicate level key credits reward (#1940)
Closes #1939

Reviewed-on: OpenWF/SpaceNinjaServer#1940
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:53:40 -07:00
4983417201 chore: update certificate (#1937)
This is good for *.faketls.com until March 2026.

Reviewed-on: OpenWF/SpaceNinjaServer#1937
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:53:28 -07:00
9b652f5c3c fix: spoof nemesis to avoid script errors in older versions (#1936)
Reviewed-on: OpenWF/SpaceNinjaServer#1936
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:53:10 -07:00
19b04533df fix: omit void fissures for U35.1 (#1935)
This version also has a script error even tho it should know most of the new deimos nodes...

Reviewed-on: OpenWF/SpaceNinjaServer#1935
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:52:43 -07:00
cddd4bdf5c fix: filter sortie armor/shields modifier based on mission faction (#1934)
Closes #1931

Reviewed-on: OpenWF/SpaceNinjaServer#1934
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 13:51:31 -07:00
12b6e5d16e fix: login failure on U31 the new war & U30.5 sisters of parvos (#1943)
Reviewed-on: OpenWF/SpaceNinjaServer#1943
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-01 05:23:25 -07:00
8eefd67d79 chore: fix typo 2025-05-01 13:09:45 +02:00
c4b2248df5 fix: login failure on U31.5 angels of the zariman (#1933)
Reviewed-on: OpenWF/SpaceNinjaServer#1933
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-30 23:50:02 -07:00
15 changed files with 192 additions and 137 deletions

View File

@ -1,5 +1,5 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getAccountForRequest } from "@/src/services/loginService";
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import { config } from "@/src/services/configService";
import allDialogue from "@/static/fixed_responses/allDialogue.json";
@ -24,11 +24,12 @@ import {
import { logger } from "@/src/utils/logger";
import { catBreadHash } from "@/src/helpers/stringHelpers";
import { Types } from "mongoose";
import { isNemesisCompatibleWithVersion } from "@/src/helpers/nemesisHelpers";
export const inventoryController: RequestHandler = async (request, response) => {
const accountId = await getAccountIdForRequest(request);
const account = await getAccountForRequest(request);
const inventory = await Inventory.findOne({ accountOwnerId: accountId });
const inventory = await Inventory.findOne({ accountOwnerId: account._id });
if (!inventory) {
response.status(400).json({ error: "inventory was undefined" });
@ -119,12 +120,15 @@ export const inventoryController: RequestHandler = async (request, response) =>
inventory.LastInventorySync = new Types.ObjectId();
await inventory.save();
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
response.json(
await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query, account.BuildLabel)
);
};
export const getInventoryResponse = async (
inventory: TInventoryDatabaseDocument,
xpBasedLevelCapDisabled: boolean
xpBasedLevelCapDisabled: boolean,
buildLabel: string | undefined
): Promise<IInventoryClient> => {
const inventoryWithLoadOutPresets = await inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>(
"LoadOutPresets"
@ -299,6 +303,15 @@ export const getInventoryResponse = async (
// Set 2FA enabled so trading post can be used
inventoryResponse.HWIDProtectEnabled = true;
// Fix nemesis for older versions
if (
inventoryResponse.Nemesis &&
buildLabel &&
!isNemesisCompatibleWithVersion(inventoryResponse.Nemesis, buildLabel)
) {
inventoryResponse.Nemesis = undefined;
}
return inventoryResponse;
};

View File

@ -47,7 +47,8 @@ export const loginController: RequestHandler = async (request, response) => {
ForceLogoutVersion: 0,
ConsentNeeded: false,
TrackedSettings: [],
Nonce: nonce
Nonce: nonce,
BuildLabel: buildLabel
});
logger.debug("created new account");
response.json(createLoginResponse(myAddress, newAccount, buildLabel));
@ -88,6 +89,7 @@ export const loginController: RequestHandler = async (request, response) => {
account.ClientType = loginRequest.ClientType;
account.Nonce = nonce;
account.CountryCode = loginRequest.lang.toUpperCase();
account.BuildLabel = buildLabel;
}
await account.save();
@ -99,8 +101,6 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b
id: account.id,
DisplayName: account.DisplayName,
CountryCode: account.CountryCode,
ClientType: account.ClientType,
CrossPlatformAllowed: account.CrossPlatformAllowed,
ForceLogoutVersion: account.ForceLogoutVersion,
AmazonAuthToken: account.AmazonAuthToken,
AmazonRefreshToken: account.AmazonRefreshToken,
@ -109,14 +109,22 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b
Nonce: account.Nonce,
Groups: [],
IRC: config.myIrcAddresses ?? [myAddress],
HUB: `https://${myAddress}/api/`,
NRS: config.NRS,
DTLS: 99,
BuildLabel: buildLabel,
MatchmakingBuildId: buildConfig.matchmakingBuildId
BuildLabel: buildLabel
};
if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) {
resp.platformCDNs = [`https://${myAddress}/`];
if (version_compare(buildLabel, "2021.04.13.19.58") >= 0) {
resp.DTLS = 99;
if (version_compare(buildLabel, "2022.04.29.12.53") >= 0) {
resp.ClientType = account.ClientType;
if (version_compare(buildLabel, "2022.09.06.19.24") >= 0) {
resp.CrossPlatformAllowed = account.CrossPlatformAllowed;
resp.HUB = `https://${myAddress}/api/`;
resp.MatchmakingBuildId = buildConfig.matchmakingBuildId;
if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) {
resp.platformCDNs = [`https://${myAddress}/`];
}
}
}
}
return resp;
};

View File

@ -1,6 +1,6 @@
import { RequestHandler } from "express";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getAccountForRequest } from "@/src/services/loginService";
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
import { generateRewardSeed, getInventory } from "@/src/services/inventoryService";
@ -49,11 +49,11 @@ import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes";
*/
//move credit calc in here, return MissionRewards: [] if no reward info
export const missionInventoryUpdateController: RequestHandler = async (req, res): Promise<void> => {
const accountId = await getAccountIdForRequest(req);
const account = await getAccountForRequest(req);
const missionReport = getJSONfromString<IMissionInventoryUpdateRequest>((req.body as string).toString());
logger.debug("mission report:", missionReport);
const inventory = await getInventory(accountId);
const inventory = await getInventory(account._id.toString());
const firstCompletion = missionReport.SortieId
? inventory.CompletedSorties.indexOf(missionReport.SortieId) == -1
: false;
@ -65,7 +65,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
) {
inventory.RewardSeed = generateRewardSeed();
await inventory.save();
const inventoryResponse = await getInventoryResponse(inventory, true);
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
res.json({
InventoryJson: JSON.stringify(inventoryResponse),
MissionRewards: []
@ -84,7 +84,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
inventory.RewardSeed = generateRewardSeed();
await inventory.save();
const inventoryResponse = await getInventoryResponse(inventory, true);
const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel);
//TODO: figure out when to send inventory. it is needed for many cases.
res.json({

View File

@ -7,7 +7,7 @@ export const addItemsController: RequestHandler = async (req, res) => {
const requests = req.body as IAddItemRequest[];
const inventory = await getInventory(accountId);
for (const request of requests) {
await addItem(inventory, request.ItemType, request.ItemCount, true);
await addItem(inventory, request.ItemType, request.ItemCount, true, undefined, undefined, true);
}
await inventory.save();
res.end();

View File

@ -10,7 +10,7 @@ export const toMongoDate = (date: Date): IMongoDate => {
return { $date: { $numberLong: date.getTime().toString() } };
};
export const fromMongoData = (date: IMongoDate): Date => {
export const fromMongoDate = (date: IMongoDate): Date => {
return new Date(parseInt(date.$date.$numberLong));
};

View File

@ -6,7 +6,7 @@ import { logger } from "../utils/logger";
import { IOid } from "../types/commonTypes";
import { Types } from "mongoose";
import { addMods, generateRewardSeed } from "../services/inventoryService";
import { isArchwingMission } from "../services/worldStateService";
import { isArchwingMission, version_compare } from "../services/worldStateService";
import { fromStoreItem, toStoreItem } from "../services/itemDataService";
import { createMessage } from "../services/inboxService";
@ -237,15 +237,39 @@ const corpusVersionThreeWeapons = [
export const getWeaponsForManifest = (manifest: string): readonly string[] => {
switch (manifest) {
case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix":
case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix": // >= 35.6.0
return kuvaLichVersionSixWeapons;
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree":
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour":
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree": // >= 35.6.0
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour": // >= 37.0.0
return corpusVersionThreeWeapons;
}
throw new Error(`unknown nemesis manifest: ${manifest}`);
};
export const isNemesisCompatibleWithVersion = (
nemesis: { manifest: string; Faction: string },
buildLabel: string
): boolean => {
// Anything below 35.6.0 is not going to be okay given our set of supported manifests.
if (version_compare(buildLabel, "2024.05.15.11.07") < 0) {
return false;
}
if (nemesis.Faction == "FC_INFESTATION") {
// Anything below 38.5.0 isn't gonna like an infested lich.
if (version_compare(buildLabel, "2025.03.18.16.07") < 0) {
return false;
}
} else if (nemesis.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour") {
// Anything below 37.0.0 isn't gonna know version 4, but version 3 is identical in terms of weapon choices, so we can spoof it to that.
if (version_compare(buildLabel, "2024.10.01.11.03") < 0) {
nemesis.manifest = "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree";
}
}
return true;
};
export const getInnateDamageTag = (
KillingSuit: string
):

View File

@ -1688,9 +1688,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Like BossAladV,BossCaptainVor come for you on missions % chance
DeathMarks: { type: [String], default: [] },
//Zanuka
Harvestable: { type: Boolean, default: true },
Harvestable: Boolean,
//Grustag three
DeathSquadable: { type: Boolean, default: true },
DeathSquadable: Boolean,
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },

View File

@ -20,6 +20,7 @@ const databaseAccountSchema = new Schema<IDatabaseAccountJson>(
ConsentNeeded: { type: Boolean, required: true },
TrackedSettings: { type: [String], default: [] },
Nonce: { type: Number, default: 0 },
BuildLabel: String,
Dropped: Boolean,
LatestEventMessageDate: { type: Date, default: 0 },
LastLoginRewardDate: { type: Number, default: 0 },

View File

@ -69,7 +69,7 @@ import {
import { createShip } from "./shipService";
import {
catbrowDetails,
fromMongoData,
fromMongoDate,
kubrowDetails,
kubrowFurPatternsWeights,
kubrowWeights,
@ -332,7 +332,8 @@ export const addItem = async (
quantity: number = 1,
premiumPurchase: boolean = false,
seed?: bigint,
targetFingerprint?: string
targetFingerprint?: string,
exactQuantity: boolean = false
): Promise<IInventoryChanges> => {
// Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
if (typeName in ExportBundles) {
@ -490,7 +491,9 @@ export const addItem = async (
// Multipling by purchase quantity for gear because:
// - The Saya's Vigil scanner message has it as a non-counted attachment.
// - Blueprints for Ancient Protector Specter, Shield Osprey Specter, etc. have num=1 despite giving their purchaseQuantity.
quantity *= ExportGear[typeName].purchaseQuantity ?? 1;
if (!exactQuantity) {
quantity *= ExportGear[typeName].purchaseQuantity ?? 1;
}
const consumablesChanges = [
{
ItemType: typeName,
@ -1506,7 +1509,9 @@ export const applyClientEquipmentUpdates = (
}
if (InfestationDate) {
item.InfestationDate = fromMongoData(InfestationDate);
// 2147483647000 means cured, otherwise became infected
item.InfestationDate =
InfestationDate.$date.$numberLong == "2147483647000" ? new Date(0) : fromMongoDate(InfestationDate);
}
});
};

View File

@ -858,8 +858,7 @@ export const addMissionRewards = async (
for (const reward of fixedLevelRewards.levelKeyRewards2) {
//quest stage completion credit rewards
if (reward.rewardType == "RT_CREDITS") {
inventory.RegularCredits += reward.amount;
missionCompletionCredits += reward.amount;
missionCompletionCredits += reward.amount; // will be added to inventory in addCredits
continue;
}
MissionRewards.push({

View File

@ -223,10 +223,10 @@ export const handlePurchase = async (
purchaseResponse.Standing = [
{
Tag: syndicateTag,
Standing: favour.standingCost
Standing: favour.standingCost * purchaseRequest.PurchaseParams.Quantity
}
];
affiliation.Standing -= favour.standingCost;
affiliation.Standing -= favour.standingCost * purchaseRequest.PurchaseParams.Quantity;
}
}
}

View File

@ -230,40 +230,6 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
const boss = rng.randomElement(sortieBosses)!;
const modifiers = [
"SORTIE_MODIFIER_LOW_ENERGY",
"SORTIE_MODIFIER_IMPACT",
"SORTIE_MODIFIER_SLASH",
"SORTIE_MODIFIER_PUNCTURE",
"SORTIE_MODIFIER_EXIMUS",
"SORTIE_MODIFIER_MAGNETIC",
"SORTIE_MODIFIER_CORROSIVE",
"SORTIE_MODIFIER_VIRAL",
"SORTIE_MODIFIER_ELECTRICITY",
"SORTIE_MODIFIER_RADIATION",
"SORTIE_MODIFIER_GAS",
"SORTIE_MODIFIER_FIRE",
"SORTIE_MODIFIER_EXPLOSION",
"SORTIE_MODIFIER_FREEZE",
"SORTIE_MODIFIER_TOXIN",
"SORTIE_MODIFIER_POISON",
"SORTIE_MODIFIER_HAZARD_RADIATION",
"SORTIE_MODIFIER_HAZARD_MAGNETIC",
"SORTIE_MODIFIER_HAZARD_FOG", // TODO: push this if the mission tileset is Grineer Forest
"SORTIE_MODIFIER_HAZARD_FIRE", // TODO: push this if the mission tileset is Corpus Ship or Grineer Galleon
"SORTIE_MODIFIER_HAZARD_ICE",
"SORTIE_MODIFIER_HAZARD_COLD",
"SORTIE_MODIFIER_SECONDARY_ONLY",
"SORTIE_MODIFIER_SHOTGUN_ONLY",
"SORTIE_MODIFIER_SNIPER_ONLY",
"SORTIE_MODIFIER_RIFLE_ONLY",
"SORTIE_MODIFIER_MELEE_ONLY",
"SORTIE_MODIFIER_BOW_ONLY"
];
if (sortieBossToFaction[boss] == "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_SHIELDS");
if (sortieBossToFaction[boss] != "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_ARMOR");
const nodes: string[] = [];
const availableMissionIndexes: number[] = [];
for (const [key, value] of Object.entries(ExportRegions)) {
@ -314,9 +280,38 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
sortieFactionToSpecialMissionTileset[sortieBossToFaction[boss]]
);
const modifiers = [
"SORTIE_MODIFIER_LOW_ENERGY",
"SORTIE_MODIFIER_IMPACT",
"SORTIE_MODIFIER_SLASH",
"SORTIE_MODIFIER_PUNCTURE",
"SORTIE_MODIFIER_EXIMUS",
"SORTIE_MODIFIER_MAGNETIC",
"SORTIE_MODIFIER_CORROSIVE",
"SORTIE_MODIFIER_VIRAL",
"SORTIE_MODIFIER_ELECTRICITY",
"SORTIE_MODIFIER_RADIATION",
"SORTIE_MODIFIER_GAS",
"SORTIE_MODIFIER_FIRE",
"SORTIE_MODIFIER_EXPLOSION",
"SORTIE_MODIFIER_FREEZE",
"SORTIE_MODIFIER_TOXIN",
"SORTIE_MODIFIER_POISON",
"SORTIE_MODIFIER_HAZARD_RADIATION",
"SORTIE_MODIFIER_HAZARD_MAGNETIC",
"SORTIE_MODIFIER_HAZARD_FOG", // TODO: push this if the mission tileset is Grineer Forest
"SORTIE_MODIFIER_HAZARD_FIRE", // TODO: push this if the mission tileset is Corpus Ship or Grineer Galleon
"SORTIE_MODIFIER_HAZARD_ICE",
"SORTIE_MODIFIER_HAZARD_COLD",
"SORTIE_MODIFIER_SECONDARY_ONLY",
"SORTIE_MODIFIER_SHOTGUN_ONLY",
"SORTIE_MODIFIER_SNIPER_ONLY",
"SORTIE_MODIFIER_RIFLE_ONLY",
"SORTIE_MODIFIER_BOW_ONLY"
];
if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) {
const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY");
const modifierType = rng.randomElement(filteredModifiers)!;
const modifierType = rng.randomElement(modifiers)!;
selectedNodes.push({
missionType: "MT_ASSASSINATION",
@ -334,12 +329,21 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
continue;
}
const filteredModifiers =
missionType === "MT_TERRITORY"
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
: modifiers;
modifiers.push("SORTIE_MODIFIER_MELEE_ONLY"); // not an assassination mission, can now push this
const modifierType = rng.randomElement(filteredModifiers)!;
if (missionType != "MT_TERRITORY") {
modifiers.push("SORTIE_MODIFIER_HAZARD_RADIATION");
}
if (ExportRegions[node].factionIndex == 0) {
// Grineer
modifiers.push("SORTIE_MODIFIER_ARMOR");
} else if (ExportRegions[node].factionIndex == 1) {
// Corpus
modifiers.push("SORTIE_MODIFIER_SHIELDS");
}
const modifierType = rng.randomElement(modifiers)!;
selectedNodes.push({
missionType,
@ -717,8 +721,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
SyndicateMissions: [...staticWorldState.SyndicateMissions]
};
// Omit void fissures for versions prior to Whispers in the Walls to avoid errors with the unknown deimos nodes having void fissures.
if (buildLabel && version_compare(buildLabel, "2023.11.06.13.39") <= 0) {
// 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 = [];
}

View File

@ -3,8 +3,8 @@ import { Types } from "mongoose";
export interface IAccountAndLoginResponseCommons {
DisplayName: string;
CountryCode: string;
ClientType: string;
CrossPlatformAllowed: boolean;
ClientType?: string;
CrossPlatformAllowed?: boolean;
ForceLogoutVersion: number;
AmazonAuthToken?: string;
AmazonRefreshToken?: string;
@ -16,6 +16,7 @@ export interface IAccountAndLoginResponseCommons {
export interface IDatabaseAccountRequiredFields extends IAccountAndLoginResponseCommons {
email: string;
password: string;
BuildLabel?: string;
}
export interface IDatabaseAccount extends IDatabaseAccountRequiredFields {
@ -46,10 +47,10 @@ export interface ILoginResponse extends IAccountAndLoginResponseCommons {
id: string;
Groups: IGroup[];
BuildLabel: string;
MatchmakingBuildId: string;
MatchmakingBuildId?: string;
platformCDNs?: string[];
NRS?: string[];
DTLS: number;
DTLS?: number;
IRC: string[];
HUB?: string;
}

View File

@ -1,38 +1,38 @@
-----BEGIN CERTIFICATE-----
MIIGLzCCBRegAwIBAgIRAILIyLcitteoEGcJt1QBXvcwDQYJKoZIhvcNAQELBQAw
gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UE
AxMuU2VjdGlnbyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD
QTAeFw0yNDA4MDIwMDAwMDBaFw0yNTA4MDIyMzU5NTlaMBcxFTATBgNVBAMMDCou
dmlhdGxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTToSjY
3aUIxjghIkikJfFExVwSEzIM2XaQNJE+SxQ6Cc+xUR5QJrMJnM/39sH5c5imMEUo
2OnstCIaVMPx5ZPN+HXLsvmoVAe2/xYe7emnZ5ZFTUXPyqkzDRg0hkMJiWWo/Nmf
ypZfUJoz6hVkXwsgNFPTVuo7aECQFlZslh2HQVDOfBaNBxQBaOJ5vf6nllf/aLyB
tZ74nlLynVYV9kYzISP4dUcxQ+D4HZgIxyOQfcN3EHUS1ZVaIp8hupOygF8zGQyJ
uzFozzg5I59U+hT1yQG3FlwTBnP+sA0+hW0LBTbWSISm0If1SgHlUEqxLlosjuTG
BG45h9o2bAz9po0CAwEAAaOCAvswggL3MB8GA1UdIwQYMBaAFI2MXsRUrYrhd+mb
+ZsF4bgBjWHhMB0GA1UdDgQWBBQ/OeA2gLbVIKIuIitYRqSRUWMP3TAOBgNVHQ8B
MIIGMDCCBRigAwIBAgIQX4800cgswlDH/QexMSnnnjANBgkqhkiG9w0BAQsFADCB
jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB
MB4XDTI1MDMwNjAwMDAwMFoXDTI2MDMwNjIzNTk1OVowGDEWMBQGA1UEAwwNKi5m
YWtldGxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMe42XWK
HJuR7doFTX79zrEKfTlD2hjRIif3dHKJNTJNvZa52mIoHelP7RVUuFOhp7aZCNLh
IEzDyZObl8vwO6L2PVu5tbBEEoNixbpfhc8ZICEBuVo2UAhnJFcMJtuvtrCq+7ye
oczM/k/nh8FBz2WnLzWs4CZt1sa5knZXFmBmsHJQtQIC6vx7QzVcKGOlAosIEHSK
X4nIz5fLgWSzor1Gay56j31PTk+qRvlPQM2aKiLWnlLfRED4zHJqLe94itu8llPX
b6g+cLxxRKUpMqtG/15cDdBZwv40Dja7bmNfe1u4w2QCVLjvHVaVpNXbcRay/Mhn
M1w5LzDZmV58b18CAwEAAaOCAvwwggL4MB8GA1UdIwQYMBaAFI2MXsRUrYrhd+mb
+ZsF4bgBjWHhMB0GA1UdDgQWBBS6/x/N38wMJrQq/cE1oIcRERMonTAOBgNVHQ8B
Af8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
BQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQICBzAlMCMGCCsGAQUFBwIBFhdo
dHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgEwgYQGCCsGAQUFBwEBBHgw
djBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNB
RG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAjBggrBgEFBQcwAYYX
aHR0cDovL29jc3Auc2VjdGlnby5jb20wIwYDVR0RBBwwGoIMKi52aWF0bHMuY29t
ggp2aWF0bHMuY29tMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdQDd3Mo0ldfh
FgXnlTL6x5/4PRxQ39sAOhQSdgosrLvIKgAAAZEVLi9VAAAEAwBGMEQCIGiZNOV7
IvcHKU7nEaxFgWPpUu2CxyULg1ueJTYwTT12AiAJWQv3RrqCtOJC7JEdztILs3Bn
an9s0Bf93uOE4C/LiAB3AA3h8jAr0w3BQGISCepVLvxHdHyx1+kw7w5CHrR+Tqo0
AAABkRUuLxAAAAQDAEgwRgIhAOhlC+IpJV3uAaDCRXi6RZ+V8++QaLaTEtqFp2UP
yWeSAiEA8qtGDk1RE1VGwQQcJCf3CBYU5YTlsZNi7F6hEONLuzMAdwAS8U40vVNy
TIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZEVLi7kAAAEAwBIMEYCIQDWCnSm
N+2/xxo8bl3pbpNBEBZZIwnYPQW0A+SJ0+dboQIhANjH2L0xV/+rPuPMzK40vk3J
1fWHLocLjpgaxGhsBAOzMA0GCSqGSIb3DQEBCwUAA4IBAQBcObVjc1zFdOER50ZF
mI+WyVF8t6nV6dm3zIDraLA4++zKUu9UKNJm9YPqLdPP7uTLHz6wuBNmyuWPdF0r
qAf4vsK3tcAds7kjK8injewEUCPG20mtNMUHyhlNEOJR2ySPPQ6Q+t+TtGAnimKa
Zr86quYgYaJYhoEEXcbB9fMoDQYlJDzgT2DXvfM4cyoden2tYZ3gQS6ftiXacBe0
WzFWYZ8mIP2Kb+D9tCapB9MVUzu3XJVy3S2FLQEWcWIvjnpad73a0/35i/nro6/k
TSK+MKBEBaNZuHJ8ubCToo1BftnsS8HuEPTNe8W1hyc2YmT9f5YQP6HWB2rxjH42
OTXh
aHR0cDovL29jc3Auc2VjdGlnby5jb20wJQYDVR0RBB4wHIINKi5mYWtldGxzLmNv
bYILZmFrZXRscy5jb20wggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AJaXZL9V
WJet90OHaDcIQnfp8DrV9qTzNm5GpD8PyqnGAAABlWsz5fgAAAQDAEcwRQIgTN7Y
/mDqiD3RbGVLEOQK2wvXsboBolBRwGJFuFEsDScCIQCQ0qfb/0V8qqSxrkx/PiVS
1lSn5gBEnQUiQOkefcnW0gB2ABmG1Mcoqm/+ugNveCpNAZGqzi1yMQ+uzl1wQS0l
TMfUAAABlWsz5dAAAAQDAEcwRQIhAJnQJyrSCWWdi9Kyoa7XuMGyDKt183jJMY0E
71abTuBOAiBC+WnK1esG6xr8aVGHRcc+1U/I7LiaG3LCRMYtCKrTGwB2AMs49xWJ
fIShRF9bwd37yW7ymlnNRwppBYWwyxTDFFjnAAABlWsz5f4AAAQDAEcwRQIhAJUs
4PWDwyQJnCxCyEwFlFUY2uYQkGrQPA9f9Sw5Xk1fAiB63eQtZQGjvzvhOghy6z9a
8oGYbDfDQ/zfisMYO7rM6zANBgkqhkiG9w0BAQsFAAOCAQEAEHnSoeBbWiK3CS3a
px0BL+YXxRxdUcTMHgn5o+LlI9sWlpf+JLXmn7Z4QA6fAwT4k/Ue7xsmIq0OraDk
/pEVXWm1HO/9wUkGQg0DBi77BpfHircd7OWIMdt250Q8UAmZkOyhVgnwBcScqMwq
2T5CPaYvYGgYWx/qkIBv7JqhVbrP82rnF9b9ZUZ8GIE31chBmtMva9AsnAN5dmRw
81bVvPWXUfX30CYu5sxeWL06Zpy9nfJumxZri1SWXNTBjSvud2jsZ8tSCUAWLL/4
ui3Vien9m2oMOpaA8xbS88ZTk9Alm/o5febEKJZUPlytQzij8gQpiovFw2v+Cdei
+tFXKw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB

View File

@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDE06Eo2N2lCMY4
ISJIpCXxRMVcEhMyDNl2kDSRPksUOgnPsVEeUCazCZzP9/bB+XOYpjBFKNjp7LQi
GlTD8eWTzfh1y7L5qFQHtv8WHu3pp2eWRU1Fz8qpMw0YNIZDCYllqPzZn8qWX1Ca
M+oVZF8LIDRT01bqO2hAkBZWbJYdh0FQznwWjQcUAWjieb3+p5ZX/2i8gbWe+J5S
8p1WFfZGMyEj+HVHMUPg+B2YCMcjkH3DdxB1EtWVWiKfIbqTsoBfMxkMibsxaM84
OSOfVPoU9ckBtxZcEwZz/rANPoVtCwU21kiEptCH9UoB5VBKsS5aLI7kxgRuOYfa
NmwM/aaNAgMBAAECggEAEYK8bzxf96tAq0SzXqAP6heSsV7AS28eN7CbpKJUnp+N
OOePDnHWB46e31exoc82DAoY+EYqiiEvY2tRSD9wi8ZCyQQOz6w8kZUju42T3/ov
Ooy+06upXYU3sIQXv8YM7bjridbv+JHRQ27D8BRGamB6l0yRinQvkbLf8d9mOYkj
P5yYrpMPV/mfgkCir/aBlGOzmI+CuOv7FdF9DIz2OehtPXOzbExuab4xOQ4NQrN9
TfzWWS798D86e5uDx+Ab0pfege8IJvEBjU5ngZo3aeS/F5i2us+BXImu1P6IrYdb
ekXUo9VJPEHiD02iyLW/gFz3/AsWa3ztinXN0I069wKBgQD7yGPX6LG7MXlXEqL2
DuCrFsKzVC4z0c/cpPXO8Xb8rGzvHR7Oa0i5Bo7i5wRiVXS87HT25iZmB78yjKnI
bVmWA3tVWInx6fixbZUO7L4D/Q1Ddfin/DiXyNpAhKii0QgpD61P7HJnrfnwUar5
Vpwd2grnPNCbuILZxAZhtIXRnwKBgQDIH5hmyiIUAvrz+4UpE55ecxTMOkj0+Pgx
79KpSjXfEIk5V7UmCSk1SusQWq8Ri9d6QqPcTptVhxmC/geolp9bCW14JdORbjNv
5+3JfAwgZJtbDP4l3GKf168fLQXzSpWCW3vT1lCBz4x4nNs2EudTdDCn5aUVLGEJ
v15Iz0dQUwKBgHuZh8n55SXrx5FDCNSZwRi796Bo9rVhjhTWtgR87NhlHKTVOsZC
TFToL0Sb+776DHCh81kw6jC0JNv/yWkmpQ/LbcQbzrv/C6KuFLpa5Xy3wMcZJpPw
cSex5dI+TTqAOu1NUNsnS5IyCbw7mx8DsWfGHgweApovHa0hWbClGfwpAoGAfSt9
6DTfkcK3cilMhX+2236BcKe4ADlFC/7jtW0sOsQeAFbCf/LU6ndchVMjEwdzlA3g
bahg8eLZaxw2cBUdwRQpey+1n83csE7RZOeIsi4bGZ0LzWSF71I5P3eqtBxfXTSZ
Q8tVeYv2YW5CkhTKyWDwGePCGHc0jqM6drHm+e8CgYEA+IkvplnK76zx3M579TpI
M2ffiC2b12FtJMpgnNrk6HZ19o2mhbte/7wf9SHVqsRw4V7/n6rzBJ5wzEHOWre7
7PrkLgS0mY2SRfMmeT74m59dA8GpvhBUW/Xa4wlDtZkU2iIcDkKnYLjgrTKjlK86
ER+evzmHeTqYJzuK8Mfq93I=
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHuNl1ihybke3a
BU1+/c6xCn05Q9oY0SIn93RyiTUyTb2WudpiKB3pT+0VVLhToae2mQjS4SBMw8mT
m5fL8Dui9j1bubWwRBKDYsW6X4XPGSAhAblaNlAIZyRXDCbbr7awqvu8nqHMzP5P
54fBQc9lpy81rOAmbdbGuZJ2VxZgZrByULUCAur8e0M1XChjpQKLCBB0il+JyM+X
y4Fks6K9Rmsueo99T05Pqkb5T0DNmioi1p5S30RA+Mxyai3veIrbvJZT12+oPnC8
cUSlKTKrRv9eXA3QWcL+NA42u25jX3tbuMNkAlS47x1WlaTV23EWsvzIZzNcOS8w
2ZlefG9fAgMBAAECggEAT1Tti/LASks8300b60WFxG0WMJjzGMh5eMaiSpyVtNWM
aUKJrFOjDfnhgoeUcCPWKoG/L4Sc/+EFQMydDzTte120IasysEFZ2TZytAUdcZXZ
XUMCDQNl5vCRTsJU7Q5u0t4YAGRCgMcsfTDKi8lISGiQKBHzN1CJ74Xm13rgOInd
lAc0wd5S89sL6RYmRTj1LvuZ95EHXHqQGdv0fIFEyP3pF1iPwcoTuIVEeICqnEvW
vd8CVO68eH3HFIwioqjp4qW3pxPZMhVq4161805uAMkoQlE+7MtEVenmP++1u1gM
FjvAs3j9CZqOHZKcLlOtcGSwDlD++fCMMT4slLgLgQKBgQDy58E5nuYXdxlFQQk4
QccUKpyJ2aVXyp9xvTFBot/5Pik1SkuDzv2XU1OTxdxf3EongLy91nMJ2/6/39Je
lf0/2MjzCtJ/lSzZ/zpJAu86UkBkWBAA5loGIof6OKedbEIgqpJqtK59S+j3ExO9
eqa+uFrtt1UfaJG4A7TT+dIvIwKBgQDSfSOdSM5Dh3KsQHVnIWcIkzwTtlJlO+rG
6rDEADxw6Kp8VIL/dq4Foe8yW4VqLVrWUuZsU6jzC9GdnyYi6VaqZ/iSUtGkBMOT
WTTYhqXlURaQ13jhqdwCZJRbVI72JbXn2OGEv8DgXnk//QKED/8VdKqAzCSr1t1f
3yfwei0AlQKBgD19KU66yKg7/+umEP1quUiDmOjUbaSRqFcUe3mQD356m9ffnMob
BdrevxNzTNv/Wc4yKpUryic+x3gu4oQLF/annAbaQHsHejkdANYmpgRvedls6XAw
360Z5K4U1WlmVD8Mrs/QOTOCmdChxad7euZgqLPwat3ujKS2W3oljW1dAoGBAM4/
AB6lsDZLCfnuTxt2h1bHrh5CkAnR5AJ1BC+Ja6/WyvZ4eMOIroumWJKnStr3BgLr
yAxtDSbZddNUljGvIdRnfBEkRXbJlDlVN4rSpMtF4S6bcz7rCUDu/M9g05Qs70j2
IkPJAFzZNUWVzFlKs096uXbqkSQvrUq7ho8DqAThAoGBAL7Nrbr5LWcBgvwEhEla
VRfYb0FUrDwLIrVWntJjW566/pVQQ4BmatsblLjlQYWk9MCIYXWZbnB+2fRx9yjQ
Adggez7Dws/Mrh/wVudKgayHCy5Lgd8rYjNgC+VZf8XGrWX3QXMJ6UWAyQLTeoO7
hToW9o9CQMIhaR43G8di1kjF
-----END PRIVATE KEY-----