Skip to content

Commit

Permalink
refactor!: game versioned missionsInLocation, fix certain contracts w…
Browse files Browse the repository at this point in the history
…hen resolved, rename missionsInLocations -> missionsInLocation (#550)

Fixes #510 #505 #504

Needs testing and checking over more than twice.

## Breaking Changes
- `controller.missionsInLocations` is now
`controller.missionsInLocation` (as it always should have been!).
- The aforementioned `controller.missionsInLocations` is now **split by
game version**.
- `controller.addEscalation` has a new parameter: `(groupContract,
locationId, **gameVersion**, ...levels)` (highlighted using asterisks).

---

Also this removes some terrible hacks we've had to do. We should've
always done it like this!
  • Loading branch information
RDIL authored Jan 15, 2025
2 parents 6eee4c0 + 73991fe commit 17ba3ea
Show file tree
Hide file tree
Showing 10 changed files with 768 additions and 414 deletions.
20 changes: 13 additions & 7 deletions components/candle/challengeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,15 +959,21 @@ export class ChallengeService extends ChallengeRegistry {

let contracts = isSniperLocation(child)
? // @ts-expect-error This is fine - we know it will be there
this.controller.missionsInLocations.sniper[child]
: // @ts-expect-error This is fine - we know it will be there
(this.controller.missionsInLocations[child] ?? [])
this.controller.missionsInLocation[gameVersion].sniper[child]
: // @ts-expect-error This is fine - we can index this
(this.controller.missionsInLocation[gameVersion][child] ?? [])
.concat(
// @ts-expect-error This is fine - we know it will be there
this.controller.missionsInLocations.escalations[child],
// @ts-expect-error This is fine - we can index this
this.controller.missionsInLocation[gameVersion]
.escalations[child] ?? [],
)
.concat(
gameVersion === "h3"
? // @ts-expect-error This is fine - we know it will be there
this.controller.missionsInLocation[gameVersion]
.arcade[child]
: [],
)
// @ts-expect-error This is fine - we know it will be there
.concat(this.controller.missionsInLocations.arcade[child])

if (!contracts) {
contracts = []
Expand Down
14 changes: 0 additions & 14 deletions components/contracts/escalations/escalationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,6 @@ import type {
import { getUserData } from "../../databaseHandler"
import { log, LogLevel } from "../../loggingInterop"

/**
* Put a group id in here to hide it from the menus on 2016.
* This should only be used if:
* - The content is custom.
* - The content is on a 2016 map.
*/
export const no2016 = [
"0cceeecb-c8fe-42a4-aee4-d7b575f56a1b",
"9e0188e8-bdad-476c-b4ce-2faa5d2be56c",
"115425b1-e797-47bf-b517-410dc7507397",
"74415eca-d01e-4070-9bc9-5ef9b4e8f7d2",
"07bbf22b-d6ae-4883-bec2-122eeeb7b665",
]

/**
* An array of contract types to determine whether the escalation service
* should be used.
Expand Down
3 changes: 1 addition & 2 deletions components/contracts/hitsCategoryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import { userAuths } from "../officialServerAuth"
import { log, LogLevel } from "../loggingInterop"
import { fastClone, getRemoteService } from "../utils"
import { orderedETAs } from "./elusiveTargetArcades"
import { missionsInLocations } from "./missionsInLocation"
import assert from "assert"

/**
Expand Down Expand Up @@ -240,7 +239,7 @@ export class HitsCategoryService {
const nEscalations: string[] = []

for (const escalations of Object.values(
missionsInLocations.escalations,
controller.missionsInLocation[gameVersion].escalations,
)) {
for (const id of escalations) {
const contract = controller.resolveContract(
Expand Down
908 changes: 616 additions & 292 deletions components/contracts/missionsInLocation.ts

Large diffs are not rendered by default.

96 changes: 78 additions & 18 deletions components/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { parse } from "json5"
import { userAuths } from "./officialServerAuth"
// @ts-expect-error Ignore JSON import
import LEGACYFF from "../contractdata/COLORADO/FREEDOMFIGHTERSLEGACY.json"
import { missionsInLocations } from "./contracts/missionsInLocation"
import { missionsInLocation } from "./contracts/missionsInLocation"
import { createContext, Script } from "vm"
import { ChallengeService } from "./candle/challengeService"
import { getFlag } from "./flags"
Expand Down Expand Up @@ -334,6 +334,9 @@ export class Controller {
[contractId: string, gameVersion: GameVersion, isGroup: boolean],
MissionManifest | undefined
>
fixContract: SyncHook<
[contract: MissionManifest, gameVersion: GameVersion]
>
getContractIdsForGroupDiscovery: SyncHook<[string[]]>
contributeCampaigns: SyncHook<
[
Expand All @@ -359,7 +362,7 @@ export class Controller {
configs,
getVersionedConfig,
}
public missionsInLocations = missionsInLocations
public missionsInLocation = missionsInLocation
/**
* Note: if you are adding a contract, please use {@link addMission}!
*/
Expand Down Expand Up @@ -392,6 +395,7 @@ export class Controller {
newEvent: new SyncHook(),
newMetricsEvent: new SyncHook(),
getContractManifest: new SyncBailHook(),
fixContract: new SyncHook(),
getContractIdsForGroupDiscovery: new SyncHook(),
contributeCampaigns: new SyncHook(),
getSearchResults: new AsyncSeriesHook(),
Expand Down Expand Up @@ -627,6 +631,49 @@ export class Controller {
return json
}

/**
* Fixes a contract based on game version.
*
* An example of this is the location for Holiday Hoarders changing in
* HITMAN 3 thus breaking the contract in standalone 2016.
*
* @param contract The contract to fix.
* @param gameVersion The game version.
* @returns The fixed contract.
*/
private fixContract(
contract: MissionManifest,
gameVersion: GameVersion,
): MissionManifest {
switch (gameVersion) {
case "h1": {
if (contract.Metadata.Location === "LOCATION_PARIS_NOEL")
contract.Metadata.Location = "LOCATION_PARIS"

break
}
case "h2": {
if (contract.Metadata.Location === "LOCATION_PARIS_NOEL")
contract.Metadata.Location = "LOCATION_PARIS"

if (contract.Metadata.Location === "LOCATION_HOKKAIDO_MAMUSHI")
contract.Metadata.Location = "LOCATION_HOKKAIDO"

// Fix The Jeffrey Consolation
if (contract.Data.Bricks)
contract.Data.Bricks = contract.Data.Bricks.filter(
(brick) =>
!brick.includes("override_constantjeff.brick"),
)
}
}

// See if any plugins want to make any changes
this.hooks.fixContract.call(contract, gameVersion)

return contract
}

/**
* Get a contract by its ID.
*
Expand Down Expand Up @@ -670,6 +717,7 @@ export class Controller {
)

if (optionalPluginJson) {
// We skip fixing plugins as we assume they know what they're doing.
return fastClone(
getGroup
? this.getGroupContract(optionalPluginJson, gameVersion)
Expand All @@ -680,10 +728,13 @@ export class Controller {
const registryJson: MissionManifest | undefined = internalContracts[id]

if (registryJson) {
return fastClone(
getGroup
? this.getGroupContract(registryJson, gameVersion)
: registryJson,
return this.fixContract(
fastClone(
getGroup
? this.getGroupContract(registryJson, gameVersion)
: registryJson,
),
gameVersion,
)
}

Expand All @@ -692,10 +743,13 @@ export class Controller {
: undefined

if (openCtJson) {
return fastClone(
getGroup
? this.getGroupContract(openCtJson, gameVersion)
: openCtJson,
return this.fixContract(
fastClone(
getGroup
? this.getGroupContract(openCtJson, gameVersion)
: openCtJson,
),
gameVersion,
)
}

Expand All @@ -704,10 +758,13 @@ export class Controller {
: undefined

if (officialJson) {
return fastClone(
getGroup
? this.getGroupContract(officialJson, gameVersion)
: officialJson,
return this.fixContract(
fastClone(
getGroup
? this.getGroupContract(officialJson, gameVersion)
: officialJson,
),
gameVersion,
)
}

Expand Down Expand Up @@ -739,24 +796,27 @@ export class Controller {
*
* @param groupContract The escalation group contract, ALL levels must have the Id of this in Metadata.InGroup
* @param locationId The location of the escalation's ID.
* @param gameVersion The game version to add the escalation to.
* @param levels The escalation's levels.
*/
public addEscalation(
groupContract: MissionManifest,
locationId: string,
gameVersion: GameVersion,
...levels: MissionManifest[]
): void {
const fixedLevels = [...levels].filter(Boolean)

this.addMission(groupContract)
fixedLevels.forEach((level) => this.addMission(level))

type K = keyof typeof this.missionsInLocations.escalations
type K =
keyof (typeof this.missionsInLocation)[GameVersion]["escalations"]

// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.missionsInLocations.escalations[locationId as K] ??= <any>[]
// @ts-expect-error This is fine.
this.missionsInLocation[gameVersion].escalations[locationId as K] ??= []

const a = this.missionsInLocations.escalations[
const a = this.missionsInLocation[gameVersion].escalations[
locationId as K
] as string[]

Expand Down
Loading

0 comments on commit 17ba3ea

Please sign in to comment.