mirror of
https://github.com/thepeacockproject/Peacock
synced 2025-02-10 05:24:28 +01:00
Implement "Contract search", "Trending", and "Most played last week" tiles for contracts menu (#117)
* Refactor: use function for lookupContractPublicId * Trending and Mostplayed now display stuff * Add call to contract-preserving backend * Actually download contract data from official * add getRemoteService function * implement "contract search" tile * Change variable naming * Run prettier * Change naming to hitmaps * officialSearchContract -> contractsModeRouting.ts * Fix imports
This commit is contained in:
parent
5f5ce0abe0
commit
4a08faeec0
@ -93,6 +93,7 @@ import FrankensteinPlanningTemplate from "../static/FrankensteinPlanningTemplate
|
||||
import Videos from "../static/Videos.json"
|
||||
import ChallengeLocationTemplate from "../static/ChallengeLocationTemplate.json"
|
||||
import ContractSearchPageTemplate from "../static/ContractSearchPageTemplate.json"
|
||||
import ContractSearchPaginateTemplate from "../static/ContractSearchPaginateTemplate.json"
|
||||
import ContractSearchResponseTemplate from "../static/ContractSearchResponseTemplate.json"
|
||||
import LegacyDebriefingChallengesTemplate from "../static/LegacyDebriefingChallengesTemplate.json"
|
||||
import DebriefingChallengesTemplate from "../static/DebriefingChallengesTemplate.json"
|
||||
@ -189,6 +190,7 @@ const configs: Record<string, unknown> = {
|
||||
Videos,
|
||||
ChallengeLocationTemplate,
|
||||
ContractSearchPageTemplate,
|
||||
ContractSearchPaginateTemplate,
|
||||
ContractSearchResponseTemplate,
|
||||
MasteryUnlockablesTemplate,
|
||||
SniperLoadouts,
|
||||
|
@ -16,14 +16,20 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { RequestWithJwt } from "../types/types"
|
||||
import type {
|
||||
contractSearchResult,
|
||||
GameVersion,
|
||||
RequestWithJwt,
|
||||
} from "../types/types"
|
||||
import type { Response } from "express"
|
||||
import { getConfig, getVersionedConfig } from "../configSwizzleManager"
|
||||
import { getUserData } from "../databaseHandler"
|
||||
import { generateUserCentric } from "./dataGen"
|
||||
import { controller } from "../controller"
|
||||
import { controller, preserveContracts } from "../controller"
|
||||
import { createLocationsData } from "../menus/destinations"
|
||||
import { contractCreationTutorialId } from "../utils"
|
||||
import { userAuths } from "../officialServerAuth"
|
||||
import { log, LogLevel } from "../loggingInterop"
|
||||
import { getRemoteService, contractCreationTutorialId } from "../utils"
|
||||
|
||||
export function contractsModeHome(req: RequestWithJwt, res: Response): void {
|
||||
const contractsHomeTemplate = getConfig("ContractsTemplate", false)
|
||||
@ -57,3 +63,39 @@ export function contractsModeHome(req: RequestWithJwt, res: Response): void {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function officialSearchContract(
|
||||
userId: string,
|
||||
gameVersion: GameVersion,
|
||||
filters: string[],
|
||||
pageNumber: number,
|
||||
): Promise<contractSearchResult> {
|
||||
const remoteService = getRemoteService(gameVersion)
|
||||
const user = userAuths.get(userId)
|
||||
|
||||
if (!user) {
|
||||
log(LogLevel.WARN, `No authentication for user ${userId}!`)
|
||||
return undefined
|
||||
}
|
||||
|
||||
const resp = await user._useService<{
|
||||
data: contractSearchResult
|
||||
}>(
|
||||
pageNumber === 0
|
||||
? `https://${remoteService}.hitman.io/profiles/page/ContractSearch?sorting=`
|
||||
: `https://${remoteService}.hitman.io/profiles/page/ContractSearchPaginate?page=${pageNumber}&sorting=`,
|
||||
false,
|
||||
filters,
|
||||
)
|
||||
|
||||
preserveContracts(
|
||||
resp.data.data.Data.Contracts.map(
|
||||
(c) => c.UserCentricContract.Contract.Metadata.PublicId,
|
||||
),
|
||||
)
|
||||
|
||||
controller.storeIdToPublicId(
|
||||
resp.data.data.Data.Contracts.map((c) => c.UserCentricContract),
|
||||
)
|
||||
return resp.data.data
|
||||
}
|
||||
|
@ -22,10 +22,13 @@ import {
|
||||
contractIdToHitObject,
|
||||
controller,
|
||||
featuredContractGroups,
|
||||
preserveContracts,
|
||||
} from "../controller"
|
||||
import { getUserData } from "../databaseHandler"
|
||||
import { orderedETs } from "./elusiveTargets"
|
||||
import { fastClone } from "components/utils"
|
||||
import { userAuths } from "../officialServerAuth"
|
||||
import { log, LogLevel } from "../loggingInterop"
|
||||
import { fastClone, getRemoteService } from "../utils"
|
||||
|
||||
function paginate<Element>(
|
||||
elements: Element[],
|
||||
@ -96,6 +99,7 @@ export class HitsCategoryService {
|
||||
* Hits categories that should not be automatically paginated.
|
||||
*/
|
||||
public paginationExempt = ["Elusive_Target_Hits", "Arcade", "Sniper"]
|
||||
public realtimeFetched = ["Trending", "MostPlayedLastWeek"]
|
||||
|
||||
/**
|
||||
* The number of hits per page.
|
||||
@ -168,11 +172,48 @@ export class HitsCategoryService {
|
||||
hitsCategory.CurrentSubType = "MyPlaylist_all"
|
||||
})
|
||||
|
||||
// intentionally don't handle Trending
|
||||
// intentionally don't handle MostPlayedLastWeek
|
||||
// intentionally don't handle Arcade
|
||||
}
|
||||
|
||||
private async fetchFromOfficial(
|
||||
categoryName: string,
|
||||
pageNumber: number,
|
||||
gameVersion: GameVersion,
|
||||
userId: string,
|
||||
): Promise<HitsCategoryCategory> {
|
||||
const remoteService = getRemoteService(gameVersion)
|
||||
const user = userAuths.get(userId)
|
||||
|
||||
if (!user) {
|
||||
log(LogLevel.WARN, `No authentication for user ${userId}!`)
|
||||
return undefined
|
||||
}
|
||||
|
||||
const resp = await user._useService<{
|
||||
data: HitsCategoryCategory
|
||||
}>(
|
||||
`https://${remoteService}.hitman.io/profiles/page/HitsCategory?page=${pageNumber}&type=${categoryName}&mode=dataonly`,
|
||||
true,
|
||||
)
|
||||
const hits = resp.data.data.Data.Hits
|
||||
preserveContracts(
|
||||
hits.map(
|
||||
(hit) => hit.UserCentricContract.Contract.Metadata.PublicId,
|
||||
),
|
||||
)
|
||||
|
||||
// Stores the repo ID —— public ID lookup for the planning page to use.
|
||||
hits.forEach((hit) =>
|
||||
controller.contractIdToPublicId.set(
|
||||
hit.UserCentricContract.Contract.Metadata.Id,
|
||||
hit.UserCentricContract.Contract.Metadata.PublicId,
|
||||
),
|
||||
)
|
||||
controller.storeIdToPublicId(hits.map((hit) => hit.UserCentricContract))
|
||||
|
||||
return resp.data.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a {@link HitsCategoryCategory} object for the current page.
|
||||
*
|
||||
@ -182,12 +223,20 @@ export class HitsCategoryService {
|
||||
* @param userId The current user's ID.
|
||||
* @returns The {@link HitsCategoryCategory} object.
|
||||
*/
|
||||
public paginateHitsCategory(
|
||||
public async paginateHitsCategory(
|
||||
categoryName: string,
|
||||
pageNumber: number,
|
||||
gameVersion: GameVersion,
|
||||
userId: string,
|
||||
): HitsCategoryCategory {
|
||||
): Promise<HitsCategoryCategory> {
|
||||
if (this.realtimeFetched.includes(categoryName)) {
|
||||
return await this.fetchFromOfficial(
|
||||
categoryName,
|
||||
pageNumber,
|
||||
gameVersion,
|
||||
userId,
|
||||
)
|
||||
}
|
||||
const hitsCategory: HitsCategoryCategory = {
|
||||
Category: categoryName,
|
||||
Data: {
|
||||
|
@ -56,7 +56,12 @@ import * as axios from "axios"
|
||||
import * as ini from "js-ini"
|
||||
import * as statemachineParser from "@peacockproject/statemachine-parser"
|
||||
import * as utils from "./utils"
|
||||
import { addDashesToPublicId, fastClone } from "./utils"
|
||||
import {
|
||||
addDashesToPublicId,
|
||||
fastClone,
|
||||
getRemoteService,
|
||||
hitmapsUrl,
|
||||
} from "./utils"
|
||||
import * as sessionSerialization from "./sessionSerialization"
|
||||
import * as databaseHandler from "./databaseHandler"
|
||||
import * as playnext from "./menus/playnext"
|
||||
@ -393,6 +398,10 @@ export class Controller {
|
||||
* Note: if you are adding a contract, please use {@link addMission}!
|
||||
*/
|
||||
public contracts: Map<string, MissionManifest> = new Map()
|
||||
|
||||
// Converts a contract's ID to public ID.
|
||||
public contractIdToPublicId: Map<string, string> = new Map()
|
||||
|
||||
public challengeService: ChallengeService
|
||||
public masteryService: MasteryService
|
||||
/**
|
||||
@ -880,14 +889,11 @@ export class Controller {
|
||||
ErrorReason?: string | null
|
||||
}
|
||||
|
||||
const resp = await axios.default.get<Response>(
|
||||
`https://backend.rdil.rocks/partners/hitmaps/contract`,
|
||||
{
|
||||
params: {
|
||||
publicId: id,
|
||||
},
|
||||
const resp = await axios.default.get<Response>(hitmapsUrl, {
|
||||
params: {
|
||||
publicId: id,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
const fetchedData = resp.data
|
||||
const hasData = !!fetchedData?.contract?.Contract
|
||||
@ -989,12 +995,7 @@ export class Controller {
|
||||
gameVersion: GameVersion,
|
||||
userId: string,
|
||||
): Promise<MissionManifest | undefined> {
|
||||
const remoteService =
|
||||
gameVersion === "h3"
|
||||
? "hm3-service"
|
||||
: gameVersion === "h2"
|
||||
? "pc2-service"
|
||||
: "pc-service"
|
||||
const remoteService = getRemoteService(gameVersion)
|
||||
|
||||
const user = userAuths.get(userId)
|
||||
|
||||
@ -1136,6 +1137,15 @@ export class Controller {
|
||||
this._internalContracts = decompressed.b
|
||||
this._internalElusives = decompressed.el
|
||||
}
|
||||
|
||||
public storeIdToPublicId(contracts: UserCentricContract[]): void {
|
||||
contracts.forEach((c) =>
|
||||
controller.contractIdToPublicId.set(
|
||||
c.Contract.Metadata.Id,
|
||||
c.Contract.Metadata.PublicId,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1265,4 +1275,18 @@ export function contractIdToHitObject(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an array of publicIds to the contract preservation backend.
|
||||
* @param publicIds The contract publicIds to send.
|
||||
*/
|
||||
export async function preserveContracts(publicIds: string[]): Promise<void> {
|
||||
for (const id of publicIds) {
|
||||
await axios.default.get<Response>(hitmapsUrl, {
|
||||
params: {
|
||||
publicId: addDashesToPublicId(id),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const controller = new Controller()
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
STEAM_NAMESPACE_2016,
|
||||
} from "./platformEntitlements"
|
||||
import { GameVersion } from "./types/types"
|
||||
import { getRemoteService } from "./utils"
|
||||
|
||||
/**
|
||||
* The base class for an entitlement strategy.
|
||||
@ -66,12 +67,7 @@ export class IOIStrategy extends EntitlementStrategy {
|
||||
constructor(gameVersion: GameVersion, private readonly issuerId: string) {
|
||||
super()
|
||||
this.issuerId = issuerId
|
||||
this._remoteService =
|
||||
gameVersion === "h3"
|
||||
? "hm3-service"
|
||||
: gameVersion === "h2"
|
||||
? "pc2-service"
|
||||
: "pc-service"
|
||||
this._remoteService = getRemoteService(gameVersion)
|
||||
}
|
||||
|
||||
override async get(userId: string) {
|
||||
|
@ -41,6 +41,8 @@ import {
|
||||
} from "./menus/destinations"
|
||||
import type {
|
||||
CommonSelectScreenConfig,
|
||||
contractSearchResult,
|
||||
GameVersion,
|
||||
HitsCategoryCategory,
|
||||
IHit,
|
||||
MissionManifest,
|
||||
@ -62,7 +64,10 @@ import {
|
||||
generateUserCentric,
|
||||
} from "./contracts/dataGen"
|
||||
import { log, LogLevel } from "./loggingInterop"
|
||||
import { contractsModeHome } from "./contracts/contractsModeRouting"
|
||||
import {
|
||||
contractsModeHome,
|
||||
officialSearchContract,
|
||||
} from "./contracts/contractsModeRouting"
|
||||
import random from "random"
|
||||
import { getUserData } from "./databaseHandler"
|
||||
import {
|
||||
@ -1131,79 +1136,80 @@ menuDataRouter.get(
|
||||
},
|
||||
)
|
||||
|
||||
async function lookupContractPublicId(
|
||||
publicid: string,
|
||||
userId: string,
|
||||
gameVersion: GameVersion,
|
||||
) {
|
||||
const publicIdRegex = /\d{12}/
|
||||
|
||||
while (publicid.includes("-")) {
|
||||
publicid = publicid.replace("-", "")
|
||||
}
|
||||
|
||||
if (!publicIdRegex.test(publicid)) {
|
||||
return {
|
||||
PublicId: publicid,
|
||||
ErrorReason: "notfound",
|
||||
}
|
||||
}
|
||||
|
||||
const contract = await controller.contractByPubId(
|
||||
publicid,
|
||||
userId,
|
||||
gameVersion,
|
||||
)
|
||||
|
||||
if (!contract) {
|
||||
return {
|
||||
PublicId: publicid,
|
||||
ErrorReason: "notfound",
|
||||
}
|
||||
}
|
||||
|
||||
const location = (
|
||||
getVersionedConfig(
|
||||
"allunlockables",
|
||||
gameVersion,
|
||||
false,
|
||||
) as readonly Unlockable[]
|
||||
).find((entry) => entry.Id === contract.Metadata.Location)
|
||||
|
||||
return {
|
||||
Contract: contract,
|
||||
Location: location,
|
||||
UserCentricContract: generateUserCentric(contract, userId, gameVersion),
|
||||
}
|
||||
}
|
||||
|
||||
menuDataRouter.get(
|
||||
"/LookupContractPublicId",
|
||||
async (req: RequestWithJwt<{ publicid: string }>, res) => {
|
||||
const publicIdRegex = /\d{12}/
|
||||
let publicid = req.query.publicid
|
||||
const templateLookupContractById = getVersionedConfig(
|
||||
"LookupContractByIdTemplate",
|
||||
req.gameVersion,
|
||||
false,
|
||||
)
|
||||
|
||||
if (!publicid) {
|
||||
if (!req.query.publicid) {
|
||||
return res.status(400).send("no public id specified!")
|
||||
}
|
||||
|
||||
while (publicid.includes("-")) {
|
||||
publicid = publicid.replace("-", "")
|
||||
}
|
||||
|
||||
if (!publicIdRegex.test(publicid)) {
|
||||
res.json({
|
||||
template: templateLookupContractById,
|
||||
data: {
|
||||
PublicId: req.query.publicid,
|
||||
ErrorReason: "notfound",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const contract = await controller.contractByPubId(
|
||||
publicid,
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
)
|
||||
|
||||
if (!contract) {
|
||||
res.json({
|
||||
template: templateLookupContractById,
|
||||
data: {
|
||||
PublicId: req.query.publicid,
|
||||
ErrorReason: "notfound",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const location = (
|
||||
getVersionedConfig(
|
||||
"allunlockables",
|
||||
res.json({
|
||||
template: getVersionedConfig(
|
||||
"LookupContractByIdTemplate",
|
||||
req.gameVersion,
|
||||
false,
|
||||
) as readonly Unlockable[]
|
||||
).find((entry) => entry.Id === contract.Metadata.Location)
|
||||
|
||||
res.json({
|
||||
template: templateLookupContractById,
|
||||
data: {
|
||||
Contract: contract,
|
||||
Location: location,
|
||||
UserCentricContract: generateUserCentric(
|
||||
contract,
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
),
|
||||
},
|
||||
),
|
||||
data: await lookupContractPublicId(
|
||||
req.query.publicid,
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
menuDataRouter.get(
|
||||
"/HitsCategory",
|
||||
(req: RequestWithJwt<{ type: string; page?: number | string }>, res) => {
|
||||
async (
|
||||
req: RequestWithJwt<{ type: string; page?: number | string }>,
|
||||
res,
|
||||
) => {
|
||||
const category = req.query.type
|
||||
|
||||
const response: {
|
||||
@ -1225,7 +1231,7 @@ menuDataRouter.get(
|
||||
|
||||
pageNumber = pageNumber < 0 ? 0 : pageNumber
|
||||
|
||||
response.data = hitsCategoryService.paginateHitsCategory(
|
||||
response.data = await hitsCategoryService.paginateHitsCategory(
|
||||
category,
|
||||
pageNumber as number,
|
||||
req.gameVersion,
|
||||
@ -1555,32 +1561,34 @@ menuDataRouter.post(
|
||||
specialContracts,
|
||||
)
|
||||
|
||||
const contracts: { UserCentricContract: UserCentricContract }[] = []
|
||||
let searchResult: contractSearchResult = undefined
|
||||
|
||||
for (const contract of specialContracts) {
|
||||
const userCentric = generateUserCentric(
|
||||
controller.resolveContract(contract),
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
)
|
||||
if (specialContracts.length > 0) {
|
||||
// Handled by a plugin
|
||||
|
||||
if (!userCentric) {
|
||||
log(LogLevel.ERROR, "UC is null! (contract not registered?)")
|
||||
continue
|
||||
const contracts: { UserCentricContract: UserCentricContract }[] = []
|
||||
|
||||
for (const contract of specialContracts) {
|
||||
const userCentric = generateUserCentric(
|
||||
controller.resolveContract(contract),
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
)
|
||||
|
||||
if (!userCentric) {
|
||||
log(
|
||||
LogLevel.ERROR,
|
||||
"UC is null! (contract not registered?)",
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
contracts.push({
|
||||
UserCentricContract: userCentric,
|
||||
})
|
||||
}
|
||||
|
||||
contracts.push({
|
||||
UserCentricContract: userCentric,
|
||||
})
|
||||
}
|
||||
|
||||
res.json({
|
||||
template: getVersionedConfig(
|
||||
"ContractSearchResponseTemplate",
|
||||
req.gameVersion,
|
||||
false,
|
||||
),
|
||||
data: {
|
||||
searchResult = {
|
||||
Data: {
|
||||
Contracts: contracts,
|
||||
TotalCount: contracts.length,
|
||||
@ -1589,7 +1597,40 @@ menuDataRouter.post(
|
||||
HasPrevious: false,
|
||||
HasMore: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// No plugins handle this. Getting search results from official
|
||||
searchResult = await officialSearchContract(
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
req.body,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
res.json({
|
||||
template: getVersionedConfig(
|
||||
"ContractSearchResponseTemplate",
|
||||
req.gameVersion,
|
||||
false,
|
||||
),
|
||||
data: searchResult,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
menuDataRouter.post(
|
||||
"/ContractSearchPaginate",
|
||||
jsonMiddleware(),
|
||||
async (req: RequestWithJwt<{ page: number }, string[]>, res) => {
|
||||
res.json({
|
||||
template: getConfig("ContractSearchPaginateTemplate", false),
|
||||
data: await officialSearchContract(
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
req.body,
|
||||
req.query.page,
|
||||
),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
@ -32,7 +32,12 @@ import {
|
||||
} from "../contracts/dataGen"
|
||||
import { getConfig } from "../configSwizzleManager"
|
||||
import { getUserData, writeUserData } from "../databaseHandler"
|
||||
import { getDefaultSuitFor, nilUuid, unlockOrderComparer } from "../utils"
|
||||
import {
|
||||
fastClone,
|
||||
getDefaultSuitFor,
|
||||
nilUuid,
|
||||
unlockOrderComparer,
|
||||
} from "../utils"
|
||||
|
||||
import type { Response } from "express"
|
||||
import { createInventory } from "../inventory"
|
||||
@ -81,7 +86,7 @@ export async function planningView(
|
||||
controller.escalationMappings[escalationGroupId]["1"]
|
||||
}
|
||||
|
||||
const contractData =
|
||||
let contractData =
|
||||
req.gameVersion === "h1" &&
|
||||
req.query.contractid === "42bac555-bbb9-429d-a8ce-f1ffdf94211c"
|
||||
? _legacyBull
|
||||
@ -90,7 +95,27 @@ export async function planningView(
|
||||
: controller.resolveContract(req.query.contractid)
|
||||
|
||||
if (!contractData) {
|
||||
log(LogLevel.ERROR, `Not found: ${req.query.contractid}.`)
|
||||
log(
|
||||
LogLevel.WARN,
|
||||
`Trying to download contract ${req.query.contractid} due to it not found locally.`,
|
||||
)
|
||||
const publicId = controller.contractIdToPublicId.get(
|
||||
req.query.contractid,
|
||||
)
|
||||
if (publicId) {
|
||||
const officialJson = await controller.downloadContract(
|
||||
req.jwt.unique_name,
|
||||
publicId,
|
||||
req.gameVersion,
|
||||
)
|
||||
if (officialJson) {
|
||||
contractData = fastClone(officialJson)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!contractData) {
|
||||
log(LogLevel.ERROR, `Not found: ${req.query.contractid}, .`)
|
||||
res.status(400).send("no ct")
|
||||
return
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ import {
|
||||
} from "./databaseHandler"
|
||||
import { OfficialServerAuth, userAuths } from "./officialServerAuth"
|
||||
import { randomUUID } from "crypto"
|
||||
import { getFlag } from "./flags"
|
||||
import { clearInventoryFor } from "./inventory"
|
||||
import {
|
||||
EpicH1Strategy,
|
||||
@ -125,12 +124,7 @@ export async function handleOauthToken(
|
||||
// ts-expect-error Non-optional, we're reassigning.
|
||||
delete req.jwt.aud // audience
|
||||
|
||||
if (
|
||||
((external_platform === "steam" ||
|
||||
getFlag("legacyContractDownloader") === true) &&
|
||||
isHitman3) ||
|
||||
!isFrankenstein
|
||||
) {
|
||||
if (!isFrankenstein) {
|
||||
if (userAuths.has(req.jwt.unique_name)) {
|
||||
userAuths
|
||||
.get(req.jwt.unique_name)!
|
||||
@ -206,12 +200,7 @@ export async function handleOauthToken(
|
||||
Always store user auth for H1 & H2
|
||||
If on steam or using legacy contract downloader, then store user auth for H3
|
||||
*/
|
||||
if (
|
||||
((external_platform === "steam" ||
|
||||
getFlag("legacyContractDownloader") === true) &&
|
||||
isHitman3) ||
|
||||
!isFrankenstein
|
||||
) {
|
||||
if (!isFrankenstein) {
|
||||
const authContainer = new OfficialServerAuth(
|
||||
gameVersion,
|
||||
req.body.access_token,
|
||||
|
@ -182,6 +182,22 @@ export type MissionType =
|
||||
| "vsrace"
|
||||
| "evergreen"
|
||||
|
||||
/**
|
||||
* The data acquired when using the "contract search" functionality.
|
||||
*/
|
||||
export interface contractSearchResult {
|
||||
Data: {
|
||||
Contracts: {
|
||||
UserCentricContract: UserCentricContract
|
||||
}[]
|
||||
ErrorReason: string
|
||||
HasMore: boolean
|
||||
HasPrevious: boolean
|
||||
Page: number
|
||||
TotalCount: number
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The last kill in a contract session.
|
||||
*
|
||||
|
@ -19,6 +19,7 @@
|
||||
import { decode } from "jsonwebtoken"
|
||||
import type { NextFunction, Response } from "express"
|
||||
import type {
|
||||
GameVersion,
|
||||
MissionManifestObjective,
|
||||
RepositoryId,
|
||||
RequestWithJwt,
|
||||
@ -82,6 +83,14 @@ export async function checkForUpdates(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getRemoteService(gameVersion: GameVersion): string {
|
||||
return gameVersion === "h3"
|
||||
? "hm3-service"
|
||||
: gameVersion === "h2"
|
||||
? "pc2-service"
|
||||
: "pc-service"
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that validates the authentication token sent by the client.
|
||||
*
|
||||
@ -224,6 +233,8 @@ export function getDefaultSuitFor(location: string) {
|
||||
|
||||
export const nilUuid = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
export const hitmapsUrl = "https://backend.rdil.rocks/partners/hitmaps/contract"
|
||||
|
||||
export function isObjectiveActive(
|
||||
objective: MissionManifestObjective,
|
||||
doneObjectives: Set<RepositoryId>,
|
||||
|
2014
static/ContractSearchPaginateTemplate.json
Normal file
2014
static/ContractSearchPaginateTemplate.json
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user