mirror of
https://github.com/thepeacockproject/Peacock
synced 2025-03-27 11:12:44 +01:00

* Fix "Contract undefined not found!" warnings * Implement support for /GetContractOpportunities * Add OpportunityData to MissionManifestMetadata * Resolved a ts-expect-error by providing types * Fix requiem unlockables pistol * Adjust max player level
1347 lines
32 KiB
TypeScript
1347 lines
32 KiB
TypeScript
/*
|
|
* The Peacock Project - a HITMAN server replacement.
|
|
* Copyright (C) 2021-2022 The Peacock Project Team
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import type * as core from "express-serve-static-core"
|
|
|
|
import type { IContractCreationPayload } from "../statemachines/contractCreation"
|
|
import type { Request } from "express"
|
|
import { ProfileChallengeData, SavedChallenge } from "./challenges"
|
|
import { SessionGhostModeDetails } from "../multiplayer/multiplayerService"
|
|
import { IContextListener } from "../statemachines/contextListeners"
|
|
import { Timer } from "@peacockproject/statemachine-parser"
|
|
|
|
/**
|
|
* A duration or relative point in time expressed in seconds.
|
|
*/
|
|
export type Seconds = number
|
|
|
|
/**
|
|
* The game's major version.
|
|
*/
|
|
export type GameVersion = "h1" | "h2" | "h3" | "scpc"
|
|
|
|
/**
|
|
* The server configuration's target audience.
|
|
*
|
|
* Notes:
|
|
* - pc-prod8 is deprecated, as HITMAN 3 after 3.100.0 no longer uses it.
|
|
*/
|
|
export type GameAudience =
|
|
| "pc-prod8"
|
|
| "pc-prod7"
|
|
| "pc-prod6"
|
|
| "steam-prod_8"
|
|
| "epic-prod_8"
|
|
| "xboxone-prod"
|
|
| "scpc-prod"
|
|
| "playtest01-prod_8"
|
|
|
|
/**
|
|
* Data from the JSON Web Token (JWT) authentication scheme.
|
|
*/
|
|
export interface JwtData {
|
|
/**
|
|
* Usually bearer.
|
|
*/
|
|
"auth:method": "bearer" | string
|
|
/**
|
|
* Always "user".
|
|
*/
|
|
roles: "user"
|
|
sub: string
|
|
/**
|
|
* Profile ID.
|
|
*/
|
|
unique_name: string
|
|
/**
|
|
* User ID.
|
|
*/
|
|
userid: string
|
|
/**
|
|
* Either "steam" or "epic" on PC.
|
|
*/
|
|
platform: "steam" | "epic"
|
|
/**
|
|
* Client/account locale.
|
|
*/
|
|
locale: string
|
|
/**
|
|
* Client/account region.
|
|
*/
|
|
rgn: string
|
|
/**
|
|
* External appid.
|
|
*/
|
|
pis: string
|
|
/**
|
|
* Country, specified by the locale property.
|
|
*/
|
|
cntry: string
|
|
/**
|
|
* Expires in.
|
|
*/
|
|
exp: string
|
|
/**
|
|
* Not before.
|
|
*/
|
|
nbf: string
|
|
/**
|
|
* Issuer (from external provider).
|
|
*/
|
|
iss: string
|
|
/**
|
|
* The audience.
|
|
*
|
|
* @see GameAudience
|
|
*/
|
|
aud: GameAudience
|
|
}
|
|
|
|
/**
|
|
* A request with a JSON web token (JWT) already parsed. Also contains our custom request properties.
|
|
*/
|
|
export interface RequestWithJwt<
|
|
Query = core.Query,
|
|
// TODO: Make this `unknown` instead, requires lots of changes elsewhere
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
RequestBody = any,
|
|
> extends Request<
|
|
core.ParamsDictionary,
|
|
// eslint-disable-next-line
|
|
any,
|
|
RequestBody,
|
|
core.Query & Query
|
|
> {
|
|
/**
|
|
* The user's JSON Web Token (JWT) data.
|
|
*/
|
|
jwt: JwtData
|
|
/**
|
|
* The current Hitman server version.
|
|
*/
|
|
serverVersion?: string
|
|
/**
|
|
* The game's version.
|
|
*/
|
|
gameVersion: GameVersion
|
|
/**
|
|
* Used internally to declare if a route should be propagated to its handler or cancelled early.
|
|
*/
|
|
shouldCease?: boolean
|
|
}
|
|
|
|
/**
|
|
* The status of cameras in a mission.
|
|
*/
|
|
export enum PeacockCameraStatus {
|
|
NotSpotted = "NOT_SPOTTED",
|
|
Spotted = "SPOTTED",
|
|
Erased = "ERASED",
|
|
}
|
|
|
|
/**
|
|
* The status of security cameras in a mission (event-end).
|
|
*/
|
|
export type SecurityCameraStatus = "destroyed" | "spotted" | "erased"
|
|
|
|
/**
|
|
* A repository ID (really just a UUID v4).
|
|
*/
|
|
export type RepositoryId = string
|
|
|
|
/**
|
|
* Possible mission `Metadata.Type` values.
|
|
*/
|
|
export type MissionType =
|
|
| "mission"
|
|
| "elusive"
|
|
| "escalation"
|
|
| "featured"
|
|
| "sniper"
|
|
| "usercreated"
|
|
| "creation"
|
|
| "tutorial"
|
|
| "orbis"
|
|
| "campaign"
|
|
| "arcade"
|
|
| "vsrace"
|
|
| "evergreen"
|
|
|
|
/**
|
|
* The last kill in a contract session.
|
|
*
|
|
* @see ContractSession
|
|
*/
|
|
export interface ContractSessionLastKill {
|
|
timestamp?: Date | number
|
|
repositoryIds?: RepositoryId[]
|
|
}
|
|
|
|
/**
|
|
* A contract session is created every time you start a level, which contains the data of the play session.
|
|
* Primarily used for scoring, saving, and loading.
|
|
*/
|
|
export interface ContractSession {
|
|
gameVersion: GameVersion
|
|
sessionStart: Date | number
|
|
lastUpdate: Date | number
|
|
contractId: string
|
|
userId: string
|
|
timerStart: Date | number
|
|
timerEnd: Date | number
|
|
duration: Date | number
|
|
crowdNpcKills: number
|
|
targetKills: Set<RepositoryId>
|
|
npcKills: Set<RepositoryId>
|
|
bodiesHidden: Set<RepositoryId>
|
|
pacifications: Set<RepositoryId>
|
|
disguisesUsed: Set<RepositoryId>
|
|
disguisesRuined: Set<RepositoryId>
|
|
spottedBy: Set<RepositoryId>
|
|
witnesses: Set<RepositoryId>
|
|
bodiesFoundBy: Set<RepositoryId>
|
|
legacyHasBodyBeenFound: boolean
|
|
killsNoticedBy: Set<RepositoryId>
|
|
completedObjectives: Set<RepositoryId>
|
|
failedObjectives: Set<RepositoryId>
|
|
recording: PeacockCameraStatus
|
|
lastAccident: number
|
|
lastKill: ContractSessionLastKill
|
|
kills: Set<RatingKill>
|
|
markedTargets: Set<RepositoryId>
|
|
compat: boolean
|
|
currentDisguise: string
|
|
difficulty: number
|
|
objectiveDefinitions: Map<string, unknown>
|
|
objectiveStates: Map<string, string>
|
|
objectiveContexts: Map<string, unknown>
|
|
/**
|
|
* Session Ghost Mode details.
|
|
*
|
|
* @since v5.0.0
|
|
*/
|
|
ghost?: SessionGhostModeDetails
|
|
/**
|
|
* The current state of the challenges.
|
|
*
|
|
* @since v5.6.0-dev.1
|
|
*/
|
|
challengeContexts?: {
|
|
[challengeId: string]: {
|
|
context: unknown
|
|
state: string
|
|
timers: Timer[]
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The SaveFile object passed by the client in /ProfileService/UpdateUserSaveFileTable
|
|
*/
|
|
export interface SaveFile {
|
|
// The contract session ID of the save
|
|
ContractSessionId: string
|
|
// The unix timestamp at the time of saving
|
|
TimeStamp: number
|
|
Value: {
|
|
// The name of the save slot
|
|
Name: string
|
|
// The token of the last event that happened before the save was made
|
|
LastEventToken: string
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The body sent with the UpdateUserSaveFileTable request from the game after saving.
|
|
*
|
|
* @see SaveFile
|
|
*/
|
|
export interface UpdateUserSaveFileTableBody {
|
|
clientSaveFileList: SaveFile[]
|
|
deletedSaveFileList: SaveFile[]
|
|
}
|
|
|
|
/**
|
|
* The Hitman server version in object form.
|
|
*/
|
|
export interface ServerVersion {
|
|
readonly _Major: number
|
|
readonly _Minor: number
|
|
readonly _Build: number
|
|
readonly _Revision: number
|
|
}
|
|
|
|
/**
|
|
* An event sent from the game client to the server.
|
|
*/
|
|
export interface ClientToServerEvent<EventValue = unknown> {
|
|
Value: EventValue extends object ? Readonly<EventValue> : EventValue
|
|
ContractSessionId: string
|
|
ContractId: string
|
|
Name: string
|
|
Timestamp: number
|
|
}
|
|
|
|
/**
|
|
* A wrapper for {@link ServerToClientEvent} that also has a timestamp value.
|
|
*
|
|
* @see ServerToClientEvent
|
|
*/
|
|
export interface S2CEventWithTimestamp<EventValue = unknown> {
|
|
time: number | string
|
|
event: ServerToClientEvent<EventValue>
|
|
}
|
|
|
|
/**
|
|
* A server to client push message. The message component is encoded JSON.
|
|
*/
|
|
export interface PushMessage {
|
|
time: number | string
|
|
message: string
|
|
}
|
|
|
|
/**
|
|
* A server to client event.
|
|
*/
|
|
export interface ServerToClientEvent<EventValue = unknown> {
|
|
message?: string
|
|
CreatedAt?: string
|
|
Token?: string
|
|
IsReplicated?: boolean
|
|
Version: ServerVersion
|
|
CreatedContract?: string | null
|
|
Id?: string
|
|
Name?: string
|
|
UserId?: string
|
|
ContractId?: string
|
|
SessionId?: string | null
|
|
ContractSessionId?: string
|
|
Timestamp?: number
|
|
Value?: EventValue
|
|
Origin?: string | null
|
|
}
|
|
|
|
export interface MissionStory {
|
|
CommonRepositoryId: RepositoryId
|
|
PreviouslyCompleted: boolean
|
|
IsMainOpportunity: boolean
|
|
Title: string
|
|
Summary: string
|
|
Briefing: string
|
|
Location: string
|
|
Image: string
|
|
}
|
|
|
|
export interface UserProfile {
|
|
Id: string
|
|
LinkedAccounts: {
|
|
dev?: string
|
|
epic?: string
|
|
steam?: string
|
|
gog?: string
|
|
xbox?: string
|
|
stadia?: string
|
|
}
|
|
Extensions: {
|
|
/**
|
|
* Map of escalation group ID to current level number.
|
|
*/
|
|
PeacockEscalations: {
|
|
[escalationId: string]: number
|
|
}
|
|
PeacockFavoriteContracts: string[]
|
|
PeacockCompletedEscalations: string[]
|
|
Saves: {
|
|
[slot: string]: {
|
|
Timestamp: number
|
|
ContractSessionId: string
|
|
Token: string
|
|
}
|
|
}
|
|
ChallengeProgression: {
|
|
[id: string]: ProfileChallengeData
|
|
}
|
|
/**
|
|
* Player progression data.
|
|
*/
|
|
progression: {
|
|
/**
|
|
* Player XP and level data.
|
|
*/
|
|
PlayerProfileXP: {
|
|
ProfileLevel: number
|
|
/**
|
|
* The total amount of XP a user has obtained.
|
|
*/
|
|
Total: number
|
|
}
|
|
}
|
|
defaultloadout?: {
|
|
[location: string]: {
|
|
"2"?: string
|
|
"3"?: string
|
|
"4"?: string
|
|
"5"?: string
|
|
}
|
|
}
|
|
entP: string[]
|
|
achievements?: unknown
|
|
gamepersistentdata: {
|
|
__stats?: unknown
|
|
PersistentBool: Record<string, unknown>
|
|
}
|
|
opportunityprogression: {
|
|
[opportunityId: RepositoryId]: boolean
|
|
}
|
|
}
|
|
ETag: string | null
|
|
Gamertag: string
|
|
DevId: string | null
|
|
SteamId: string | null
|
|
StadiaId: string | null
|
|
EpicId: string | null
|
|
NintendoId: string | null
|
|
XboxLiveId: string | null
|
|
PSNAccountId: string | null
|
|
PSNOnlineId: string | null
|
|
}
|
|
|
|
export interface RatingKill {
|
|
IsHeadshot: boolean
|
|
KillClass: string
|
|
KillItemCategory: string
|
|
KillMethodBroad: string
|
|
KillMethodStrict: string
|
|
KillItemRepositoryId: RepositoryId
|
|
// only used in contract creation?
|
|
RequiredKillMethodType?: number
|
|
// TODO: why did we do this??
|
|
_RepositoryId?: RepositoryId
|
|
// !!! use the one above this one - this is only a placeholder and will not actually work
|
|
RepositoryId?: RepositoryId
|
|
OutfitRepoId: string
|
|
}
|
|
|
|
export interface NamespaceEntitlementEpic {
|
|
namespace: string
|
|
itemId: string
|
|
owned: boolean
|
|
}
|
|
|
|
/**
|
|
* An unlockable item.
|
|
*/
|
|
export interface Unlockable {
|
|
Id: string
|
|
Opportunities?: number
|
|
DisplayNameLocKey: string
|
|
GameAsset: string | null
|
|
Guid: string
|
|
Type: string
|
|
Subtype?: string
|
|
// TODO: is this used?
|
|
SubType?: string
|
|
ImageId?: string | null
|
|
RMTPrice?: number
|
|
GamePrice?: number
|
|
IsPurchasable: boolean
|
|
IsPublished: boolean
|
|
IsDroppable: boolean
|
|
Capabilities: unknown[]
|
|
Qualities?: Record<string, unknown> | null
|
|
Properties: {
|
|
RewardHidden?: boolean
|
|
HowToUnlock?: string
|
|
AllowUpSync?: boolean
|
|
Background?: string
|
|
Icon?: string
|
|
LockedIcon?: string
|
|
DlcImage?: string
|
|
DlcName?: string
|
|
IsLocked?: boolean
|
|
Order?: number
|
|
ProgressionKey?: string
|
|
Season?: number
|
|
RequiredResources?: string[]
|
|
Entitlements?: string[]
|
|
ParentLocation?: string
|
|
GameChangers?: unknown[]
|
|
CreateContractId?: null | string
|
|
IsFreeDLC?: boolean
|
|
HideProgression?: boolean
|
|
ExcludeParentRewards?: boolean
|
|
Quality?: number | string
|
|
UpcomingContent?: boolean
|
|
UpcomingKey?: "UI_MENU_LIVETILE_CONTENT_UPCOMING_HEADLINE" | string
|
|
LimitedLoadout?: boolean
|
|
NormalLoadoutUnlock?:
|
|
| {
|
|
normal: string
|
|
pro1: string
|
|
}
|
|
| string
|
|
Unlocks?: string[]
|
|
Rarity?: string | null
|
|
// noinspection SpellCheckingInspection
|
|
LoadoutSlot?:
|
|
| "carriedweapon"
|
|
| "concealedweapon"
|
|
| "disguise"
|
|
| "gear"
|
|
| string
|
|
IsConsumable?: boolean
|
|
RepositoryId?: RepositoryId
|
|
OrderIndex?: number
|
|
Name?: string
|
|
Description?: string
|
|
UnlockOrder?: number
|
|
Location?: string
|
|
Equip?: string[]
|
|
GameAssets?: string[]
|
|
RepositoryAssets?: RepositoryId[]
|
|
Gameplay?: ItemGameplay
|
|
AlwaysAdd?: boolean
|
|
BlacklistedByDefault?: boolean
|
|
IsContainer?: boolean
|
|
LoadoutSettings?: {
|
|
GearSlotsEnabledCount?: number
|
|
GearSlotsAllowContainers?: boolean
|
|
ConcealedWeaponSlotEnabled?: boolean
|
|
}
|
|
UnlockedByDefault?: boolean
|
|
DifficultyUnlock?: {
|
|
pro1?: string
|
|
}
|
|
Difficulty?: string
|
|
/**
|
|
* Sniper rifle modifier repository IDs.
|
|
*/
|
|
Modifiers?: RepositoryId[] | null
|
|
// noinspection SpellCheckingInspection
|
|
/**
|
|
* Inclusion data for an unlockable. The only known use for this is
|
|
* sniper rifle unlockables for Sniper Assassin mode.
|
|
*/
|
|
InclusionData?: {
|
|
ContractTypes?: MissionType[] | null
|
|
} | null
|
|
/**
|
|
* Item perks - only known use is for Sniper Assassin.
|
|
*/
|
|
Perks?: string[] | null
|
|
}
|
|
Rarity?: string | null
|
|
}
|
|
|
|
export interface ItemGameplay {
|
|
range?: number
|
|
damage?: number
|
|
clipsize?: number
|
|
rateoffire?: number
|
|
}
|
|
|
|
export interface CompletionData {
|
|
Level: number
|
|
MaxLevel: number
|
|
XP: number
|
|
Completion: number
|
|
XpLeft: number
|
|
Id: string
|
|
SubLocationId: string
|
|
HideProgression: boolean
|
|
IsLocationProgression: boolean
|
|
Name: string | null
|
|
}
|
|
|
|
export interface UserCentricContract {
|
|
Contract: MissionManifest
|
|
Data: {
|
|
IsLocked: boolean
|
|
LockedReason: string
|
|
LocationLevel: number
|
|
LocationMaxLevel: number
|
|
LocationCompletion: number
|
|
LocationXpLeft: number
|
|
LocationHideProgression: boolean
|
|
ElusiveContractState: string
|
|
LastPlayedAt?: string
|
|
IsFeatured?: boolean
|
|
Completed?: boolean
|
|
LocationId: string
|
|
ParentLocationId: string
|
|
CompletionData?: CompletionData
|
|
DlcName: string
|
|
DlcImage: string
|
|
EscalationCompletedLevels?: number
|
|
EscalationTotalLevels?: number
|
|
InGroup?: string
|
|
}
|
|
}
|
|
|
|
export interface TargetCondition {
|
|
Type: string
|
|
RepositoryId?: RepositoryId
|
|
HardCondition?: boolean
|
|
ObjectiveId?: string
|
|
KillMethod?: string
|
|
}
|
|
|
|
/**
|
|
* Data structure for an objective's HUD template.
|
|
*/
|
|
export interface HUDTemplate {
|
|
display:
|
|
| string
|
|
| {
|
|
$loc: {
|
|
key: string
|
|
data: string
|
|
}
|
|
}
|
|
iconType?: number
|
|
}
|
|
|
|
/**
|
|
* Data structure for a mission manifest's `Data.VR` bricks property.
|
|
*/
|
|
export interface VRQualityDefinition {
|
|
Quality: string
|
|
Bricks: string[]
|
|
}
|
|
|
|
export interface MissionManifestObjective {
|
|
_comment?: string
|
|
Id: string
|
|
Type?: "kill" | "statemachine" | string
|
|
Scope?: string
|
|
Primary?: boolean
|
|
IsHidden?: boolean
|
|
BriefingText?: string | { $loc: { key: string; data: string | number[] } }
|
|
LongBriefingText?:
|
|
| string
|
|
| { $loc: { key: string; data: string | number[] } }
|
|
Image?: string
|
|
BriefingName?: string
|
|
ShowInHud?: boolean
|
|
CombinedDisplayInHud?: boolean
|
|
DisplayAsKillObjective?: boolean
|
|
Category?: "primary" | "secondary" | "condition" | string
|
|
ForceShowOnLoadingScreen?: boolean
|
|
/**
|
|
* Allow Elusive Target Arcade contracts to be restarted if this objective is already successfully completed.
|
|
*/
|
|
AllowEtRestartOnSuccess?: boolean
|
|
OnInactive?: {
|
|
IfCompleted?: {
|
|
State?: string
|
|
}
|
|
}
|
|
Definition?: {
|
|
display?: {
|
|
iconType?: number
|
|
}
|
|
ContextListeners?: null | Record<string, IContextListener<never>>
|
|
Scope?: string
|
|
States?: Record<string, unknown>
|
|
Constants?: Record<string, unknown>
|
|
Context?: Record<string, unknown | string[] | string>
|
|
}
|
|
Activation?: {
|
|
$eq?: (string | boolean)[]
|
|
}
|
|
OnActive?: {
|
|
IfInProgress?: {
|
|
Visible?: boolean
|
|
State?: "Completed" | "InProgress" | "Failed" | string
|
|
}
|
|
IfCompleted?: {
|
|
Visible?: boolean
|
|
State?: "Completed" | "InProgress" | "Failed" | string
|
|
}
|
|
IfFailed?: {
|
|
Visible?: boolean
|
|
State?: "Completed" | "InProgress" | "Failed" | string
|
|
}
|
|
}
|
|
ObjectiveType?: "kill" | "customkill" | "setpiece" | "custom" | string
|
|
TargetConditions?: TargetCondition[]
|
|
ExcludeFromScoring?: boolean
|
|
HUDTemplate?: HUDTemplate
|
|
SuccessEvent?: {
|
|
EventName: "Kill" | string
|
|
EventValues: {
|
|
RepositoryId: RepositoryId
|
|
}
|
|
}
|
|
FailedEvent?: {
|
|
EventName: string
|
|
EventValues?: {
|
|
RepositoryId?: RepositoryId
|
|
}
|
|
}
|
|
ResetEvent?: null
|
|
IgnoreIfInactive?: boolean
|
|
GameChangerName?: string
|
|
IsPrestigeObjective?: boolean
|
|
}
|
|
|
|
/**
|
|
* Data for a group contract.
|
|
*/
|
|
export type ContractGroupDefinition = {
|
|
/**
|
|
* The contract group type.
|
|
*/
|
|
Type: MissionType
|
|
/**
|
|
* The contracts in this group, ordered by their position in the group.
|
|
*/
|
|
Order: string[]
|
|
}
|
|
|
|
export interface EscalationInfo {
|
|
Type?: MissionType
|
|
InGroup?: string
|
|
NextContractId?: string
|
|
GroupData?: {
|
|
Level: number
|
|
TotalLevels: number
|
|
Completed: boolean
|
|
FirstContractId: string
|
|
}
|
|
}
|
|
|
|
export interface MissionManifestMetadata {
|
|
Id: string
|
|
Location: string
|
|
IsPublished?: boolean
|
|
CreationTimestamp?: string
|
|
CreatorUserId?: string
|
|
Title: string
|
|
Description?: string
|
|
BriefingVideo?:
|
|
| string
|
|
| {
|
|
Mode: string
|
|
VideoId: string
|
|
}[]
|
|
DebriefingVideo?: string
|
|
TileImage?:
|
|
| string
|
|
| {
|
|
Mode: string
|
|
Image: string
|
|
}[]
|
|
CodeName_Hint?: string
|
|
ScenePath: string
|
|
Type: MissionType
|
|
Release?: string | object
|
|
RequiredUnlockable?: string
|
|
Drops?: string[]
|
|
Opportunities?: string[]
|
|
OpportunityData?: MissionStory[]
|
|
Entitlements: string[]
|
|
LastUpdate?: string
|
|
PublicId?: string
|
|
GroupObjectiveDisplayOrder?: GroupObjectiveDisplayOrderItem[]
|
|
GameVersion?: string
|
|
ServerVersion?: string
|
|
AllowNonTargetKills?: boolean
|
|
Difficulty?: "pro1" | string
|
|
CharacterSetup?: {
|
|
Mode: "singleplayer" | "multiplayer" | string
|
|
Characters: [
|
|
{
|
|
Name: string
|
|
Id: string
|
|
MandatoryLoadout?: string[]
|
|
},
|
|
]
|
|
}[]
|
|
CharacterLoadoutData?: unknown
|
|
SpawnSelectionType?: "random" | string
|
|
Gamemodes?: ("versus" | string)[]
|
|
Enginemodes?: ("singleplayer" | "multiplayer" | string)[]
|
|
EndConditions?: {
|
|
PointLimit?: number
|
|
}
|
|
Subtype?: string
|
|
GroupTitle?: string
|
|
TargetExpiration?: number
|
|
TargetExpirationReduced?: number
|
|
TargetLifeTime?: number
|
|
NonTargetKillPenaltyEnabled?: boolean
|
|
NoticedTargetStreakPenaltyMax?: number
|
|
IsFeatured?: boolean
|
|
// Begin escalation-exclusive properties
|
|
InGroup?: string
|
|
NextContractId?: string
|
|
GroupData?: {
|
|
Level: number
|
|
TotalLevels: number
|
|
Completed: boolean
|
|
FirstContractId: string
|
|
}
|
|
// End escalation-exclusive properties
|
|
/**
|
|
* Useless property.
|
|
*
|
|
* @deprecated
|
|
*/
|
|
readonly UserData?: unknown | null
|
|
IsVersus?: boolean
|
|
IsEvergreenSafehouse?: boolean
|
|
UseContractProgressionData?: boolean
|
|
CpdId?: string
|
|
GroupDefinition?: ContractGroupDefinition
|
|
}
|
|
|
|
export interface GroupObjectiveDisplayOrderItem {
|
|
Id: string
|
|
IsNew?: boolean
|
|
}
|
|
|
|
export interface GameChanger {
|
|
Id: string
|
|
Name: string
|
|
Description: string
|
|
TileImage?: string | null
|
|
Icon?: string | null
|
|
ObjectivesCategory?: string | null
|
|
IsHidden?: boolean | null
|
|
Resource?: string[] | null
|
|
Objectives?: MissionManifestObjective[] | null
|
|
LongDescription?: string | null
|
|
IsPrestigeObjective?: boolean
|
|
}
|
|
|
|
/**
|
|
* A mission's manifest is what defines how a specific contract plays.
|
|
*
|
|
* @see MissionManifestMetadata
|
|
* @see MissionManifestObjective
|
|
*/
|
|
export interface MissionManifest {
|
|
Data: {
|
|
EnableSaving?: boolean
|
|
Objectives?: MissionManifestObjective[]
|
|
GameDifficulties?: {
|
|
Difficulty: "easy" | "normal" | "hard" | string
|
|
Bricks: string[]
|
|
}[]
|
|
GameModesBricks?: unknown[]
|
|
EngineModesBricks?: unknown[]
|
|
// noinspection SpellCheckingInspection
|
|
/**
|
|
* IOI typo.
|
|
*
|
|
* @deprecated
|
|
*/
|
|
EngineModessBricks?: null
|
|
MandatoryLoadout?: unknown[]
|
|
RecommendedLoadout?: unknown[]
|
|
Bricks: string[]
|
|
VR?: VRQualityDefinition[]
|
|
GameChangers?: string[]
|
|
GameChangerReferences?: GameChanger[]
|
|
Entrances?: string[]
|
|
Stashpoints?: string[]
|
|
EnableExits?: {
|
|
$eq?: (string | boolean)[]
|
|
}
|
|
DevOnlyBricks?: string[]
|
|
}
|
|
Metadata: MissionManifestMetadata
|
|
readonly UserData?: Record<string, never> | never[]
|
|
Peacock?: {
|
|
noAgencyPickupsActive?: boolean
|
|
noGear?: boolean
|
|
noCarriedWeapon?: boolean
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A configuration that tells the game where it should connect to.
|
|
* This config is the first thing that the game asks for when logging in.
|
|
*/
|
|
export interface ServerConnectionConfig {
|
|
Versions: {
|
|
Name: string
|
|
GAME_VER: string
|
|
ISSUER_ID: string
|
|
SERVER_VER: {
|
|
Metrics: {
|
|
MetricsServerHost: string
|
|
}
|
|
Authentication: {
|
|
AuthenticationHost: string
|
|
}
|
|
Configuration: {
|
|
Url: string
|
|
AgreementUrl: string
|
|
}
|
|
Resources: {
|
|
ResourcesServicePath: string
|
|
}
|
|
GlobalAuthentication: {
|
|
AuthenticationHost: string
|
|
RequestedAudience: string
|
|
}
|
|
}
|
|
}[]
|
|
}
|
|
|
|
/**
|
|
* The format we store our locations data in, which is more concise than the
|
|
* one used by the game.
|
|
*
|
|
* @see GameLocationsData
|
|
*/
|
|
export interface PeacockLocationsData {
|
|
/**
|
|
* The parent locations.
|
|
*/
|
|
parents: Record<string, Unlockable>
|
|
/**
|
|
* The sub-locations.
|
|
*/
|
|
children: Record<string, Unlockable>
|
|
}
|
|
|
|
/**
|
|
* A structure representing the game's LocationsData object.
|
|
*/
|
|
export interface GameLocationsData {
|
|
Data: {
|
|
HasMore: boolean
|
|
Page: number
|
|
Locations: {
|
|
/**
|
|
* The contract creation contract.
|
|
*/
|
|
Contract: MissionManifest
|
|
Location: Unlockable
|
|
SubLocation: Unlockable
|
|
}[]
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The body sent with the CreateFromParams request from the game during the final phase of contract creation.
|
|
*
|
|
* @see IContractCreationPayload
|
|
*/
|
|
export interface CreateFromParamsBody {
|
|
creationData: {
|
|
Title: string
|
|
Description: string
|
|
ContractId: string
|
|
ContractPublicId: string
|
|
Targets: IContractCreationPayload[]
|
|
ContractConditionIds: string[]
|
|
}
|
|
}
|
|
|
|
export interface CommonSelectScreenConfig {
|
|
template: unknown
|
|
data?: {
|
|
Unlocked: string[]
|
|
Contract: MissionManifest
|
|
OrderedUnlocks: Unlockable[]
|
|
UserCentric: UserCentricContract
|
|
}
|
|
}
|
|
|
|
export type CompiledIoiStatemachine = unknown
|
|
|
|
/**
|
|
* The `ChallengeProgress` data for a `challengetree` context listener.
|
|
*/
|
|
export interface ChallengeProgressCTreeContextListener {
|
|
total: number
|
|
completed: string[] | readonly string[]
|
|
missing: number
|
|
all: string[] | readonly string[]
|
|
count: number
|
|
}
|
|
|
|
/**
|
|
* The `ChallengeProgress` data for a `challengecount` context listener.
|
|
*/
|
|
export interface ChallengeProgressCCountContextListener {
|
|
total: number
|
|
count: number
|
|
}
|
|
|
|
export interface CompiledChallengeTreeCategory {
|
|
CategoryId: string
|
|
ChallengesCount: number
|
|
CompletedChallengesCount: number
|
|
CompletionData: CompletionData
|
|
Icon: string
|
|
Image: string
|
|
ImageLocked?: string
|
|
IsLocked: boolean
|
|
Location: Unlockable
|
|
Name: string
|
|
RequiredResources: string[]
|
|
SwitchData: {
|
|
Data: {
|
|
CategoryData: CompiledChallengeTreeCategoryInfo
|
|
Challenges: CompiledChallengeTreeData[]
|
|
CompletionData: CompletionData
|
|
HasNext: boolean
|
|
HasPrevious: boolean
|
|
NextCategoryIcon?: string
|
|
PreviousCategoryIcon?: string
|
|
}
|
|
IsLeaf: boolean
|
|
}
|
|
}
|
|
|
|
export interface CompiledChallengeTreeCategoryInfo {
|
|
Name: string
|
|
Image: string
|
|
Icon: string
|
|
ChallengesCount: number
|
|
CompletedChallengesCount: number
|
|
}
|
|
|
|
/**
|
|
* The data for a challenge's `ChallengeProgression` field. Tells the game how
|
|
* many challenges are completed, how many are left, etc.
|
|
*/
|
|
export type ChallengeTreeWaterfallState =
|
|
| ChallengeProgressCTreeContextListener
|
|
| ChallengeProgressCCountContextListener
|
|
| null
|
|
|
|
export interface CompiledChallengeTreeData {
|
|
CategoryName: string
|
|
ChallengeProgress?: ChallengeTreeWaterfallState
|
|
Completed: boolean
|
|
CompletionData: CompletionData
|
|
Description: string
|
|
DifficultyLevels?: unknown // more investigation required
|
|
Displayed?: boolean
|
|
Drops?: Unlockable[]
|
|
HideProgression: boolean
|
|
Icon: string
|
|
Id: string
|
|
ImageName: string
|
|
IsLocked: boolean
|
|
IsPlayable: boolean
|
|
LocationId: string
|
|
Name: string
|
|
ParentLocationId: string
|
|
Rewards: {
|
|
MasteryXP?: number
|
|
}
|
|
Type?: string
|
|
UserCentricContract?: UserCentricContract
|
|
}
|
|
|
|
export interface CompiledChallengeIngameData {
|
|
Id: string
|
|
GroupId?: string
|
|
Name: string
|
|
Type: "Hit" | string
|
|
Description?: string
|
|
ImageName?: string
|
|
Definition: CompiledIoiStatemachine
|
|
Tags?: string[]
|
|
Drops?: string[]
|
|
LastModified?: string
|
|
PlayableSince?: string | null
|
|
PlayableUntil?: string | null
|
|
Xp: number
|
|
XpModifier: unknown
|
|
InclusionData?: {
|
|
ContractIds?: string[]
|
|
ContractTypes?: string[]
|
|
Locations?: string[]
|
|
GameModes?: string[]
|
|
}
|
|
CrowdChoice?: {
|
|
Tag: string
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Game-facing challenge progression data.
|
|
*/
|
|
export interface ChallengeProgressionData {
|
|
ChallengeId: string
|
|
ProfileId: string
|
|
Completed: boolean
|
|
State: Record<string, unknown>
|
|
CompletedAt: Date | string | null
|
|
MustBeSaved: boolean
|
|
}
|
|
|
|
export interface CompiledChallengeRuntimeData {
|
|
Challenge: CompiledChallengeIngameData
|
|
Progression: ChallengeProgressionData
|
|
}
|
|
|
|
export interface CompiledChallengeRewardData {
|
|
ChallengeId: string
|
|
ChallengeName: string
|
|
ChallengeDescription: string
|
|
ChallengeImageUrl: string
|
|
XPGain: number
|
|
}
|
|
|
|
export type LoadoutSavingMechanism = "PROFILES" | "LEGACY"
|
|
export type ImageLoadingStrategy = "SAVEASREQUESTED" | "ONLINE" | "OFFLINE"
|
|
|
|
export type Flags = Record<
|
|
string,
|
|
{ desc: string; default: boolean | string | number }
|
|
>
|
|
|
|
/**
|
|
* A "hit" object.
|
|
*/
|
|
export interface IHit {
|
|
Id: string
|
|
UserCentricContract: UserCentricContract
|
|
Location: Unlockable
|
|
SubLocation?: Unlockable
|
|
ChallengesCompleted: number
|
|
ChallengesTotal: number
|
|
LocationLevel: number
|
|
LocationMaxLevel: number
|
|
LocationCompletion: number
|
|
LocationXPLeft: number
|
|
LocationHideProgression: boolean
|
|
}
|
|
|
|
/**
|
|
* A video object.
|
|
*
|
|
* @see ICampaignVideo
|
|
* @see StoryData
|
|
*/
|
|
export interface IVideo {
|
|
VideoTitle: string
|
|
VideoHeader: string
|
|
VideoId: string
|
|
Entitlements: string[]
|
|
IsLocked: boolean
|
|
LockedReason?: string
|
|
VideoType: string
|
|
VideoImage: string
|
|
RequiredResources: string[]
|
|
Data: {
|
|
DlcName: string
|
|
DlcImage: string
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A campaign mission item.
|
|
*
|
|
* @see IHit
|
|
*/
|
|
export type ICampaignMission = {
|
|
Type: "Mission"
|
|
Data: IHit
|
|
}
|
|
|
|
/**
|
|
* A campaign video item.
|
|
*
|
|
* @see IVideo
|
|
*/
|
|
export type ICampaignVideo = {
|
|
Type: "Video"
|
|
Data: IVideo
|
|
}
|
|
|
|
export interface RegistryChallenge extends SavedChallenge {
|
|
/**
|
|
* Warning: this property is INTERNAL and should NOT BE SPECIFIED by API users.
|
|
*
|
|
* @internal
|
|
*/
|
|
inGroup?: string
|
|
}
|
|
|
|
/**
|
|
* An element for the game's story data.
|
|
*/
|
|
export type StoryData = ICampaignMission | ICampaignVideo
|
|
|
|
/**
|
|
* A campaign object.
|
|
*/
|
|
export interface Campaign {
|
|
Name: string
|
|
Image: string
|
|
Type: MissionType | string
|
|
BackgroundImage?: string | null
|
|
StoryData: StoryData[]
|
|
Subgroups?: Campaign[]
|
|
Properties?: {
|
|
BackgroundImage?: string | null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A loadout.
|
|
*/
|
|
export interface Loadout {
|
|
/**
|
|
* Random ID.
|
|
*
|
|
* @since Peacock v5
|
|
*/
|
|
id: string
|
|
name: string
|
|
data: {
|
|
[locationName: string]: {
|
|
readonly 2?: string
|
|
readonly 3?: string
|
|
readonly 4?: string
|
|
} & { [briefcaseId: string]: string }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The object for individual game versions' loadout profiles data.
|
|
*
|
|
* @see LoadoutFile
|
|
*/
|
|
export interface LoadoutsGameVersion {
|
|
selected: string | null
|
|
loadouts: Loadout[]
|
|
}
|
|
|
|
/**
|
|
* The top-level format for the loadout profiles storage file.
|
|
*/
|
|
export interface LoadoutFile {
|
|
h1: LoadoutsGameVersion
|
|
h2: LoadoutsGameVersion
|
|
h3: LoadoutsGameVersion
|
|
}
|
|
|
|
/**
|
|
* A function that generates a campaign mission object for use in the campaigns menu.
|
|
*/
|
|
export type GenSingleMissionFunc = (
|
|
contractId: string,
|
|
gameVersion: GameVersion,
|
|
) => ICampaignMission
|
|
|
|
/**
|
|
* A function that generates a campaign video object for use in the campaigns menu.
|
|
*/
|
|
export type GenSingleVideoFunc = (
|
|
videoId: string,
|
|
gameVersion: GameVersion,
|
|
) => ICampaignVideo
|
|
|
|
/**
|
|
* A "hits category" is used to display lists of contracts in-game.
|
|
*
|
|
* @see IHit
|
|
*/
|
|
export interface HitsCategoryCategory {
|
|
Category: string
|
|
Data: {
|
|
Type: string
|
|
Hits: IHit[]
|
|
Page: number
|
|
HasMore: boolean
|
|
}
|
|
CurrentSubType: string
|
|
}
|
|
|
|
export interface PlayNextCampaignDetails {
|
|
CampaignName: string
|
|
ParentCampaignName?: string
|
|
}
|
|
|
|
export interface PlayNextGetCampaignsHookReturn {
|
|
/**
|
|
* The UUID of the next contract in the campaign.
|
|
*/
|
|
nextContractId: string
|
|
/**
|
|
* An object containing the campaign's details.
|
|
*/
|
|
campaignDetails: PlayNextCampaignDetails
|
|
}
|
|
|
|
export type SafehouseCategory = {
|
|
Category: string
|
|
SubCategories: SafehouseCategory[]
|
|
IsLeaf: boolean
|
|
Data: null
|
|
}
|
|
|
|
export type SniperLoadout = {
|
|
ID: string
|
|
InstanceID: string
|
|
Unlockable: Unlockable
|
|
MainUnlockable: Unlockable
|
|
}
|
|
|
|
/**
|
|
* Common type for the `Entrances` and `AgencyPickups` configs.
|
|
*/
|
|
export type SceneConfig = Record<string, string[]>
|
|
|
|
/**
|
|
* Where a state machine's `Context` data should be stored.
|
|
*
|
|
* - For `profile`, the challenge's context data should be stored in the user's
|
|
* profile. This data will be used across hits, instead of being constrained
|
|
* to a single hit, like `Hit` is.
|
|
*
|
|
* - For `hit`, the challenge's context data should be stored with persistent
|
|
* data for the current contract. This appears to function differently when
|
|
* this is used in objectives.
|
|
*
|
|
* - For `session`, the challenge's context data should be stored on the
|
|
* contract session. When a mission is restarted, this data is not persisted,
|
|
* since that creates a new session.
|
|
*/
|
|
export type ContextScopedStorageLocation = "profile" | "hit" | "session"
|
|
|
|
/**
|
|
* Evergreen-related types
|
|
*/
|
|
export type CPDStore = Record<string, Record<string, string | number | boolean>>
|
|
|
|
export type ContractProgressionData = Record<string, string | number | boolean>
|
|
|
|
/** SMF's lastDeploy.json */
|
|
export interface SMFLastDeploy {
|
|
loadOrder: string[]
|
|
lastServerSideStates?: {
|
|
unlockables?: Unlockable[]
|
|
contracts?: {
|
|
[k: string]: MissionManifest
|
|
}
|
|
blobs?: Record<string, string>
|
|
}
|
|
}
|