diff --git a/src/app.ts b/src/app.ts index 36c1437e..48079166 100644 --- a/src/app.ts +++ b/src/app.ts @@ -23,7 +23,8 @@ app.use((req, _res, next) => { } // U18 uses application/x-www-form-urlencoded even tho the data is JSON which Express doesn't like. - if (req.headers["content-type"] == "application/x-www-form-urlencoded") { + // U17 sets no Content-Type at all, which Express also doesn't like. + if (!req.headers["content-type"] || req.headers["content-type"] == "application/x-www-form-urlencoded") { req.headers["content-type"] = "application/octet-stream"; } diff --git a/src/controllers/api/loginController.ts b/src/controllers/api/loginController.ts index 4ba97134..de8b7951 100644 --- a/src/controllers/api/loginController.ts +++ b/src/controllers/api/loginController.ts @@ -82,8 +82,11 @@ export const loginController: RequestHandler = async (request, response) => { } } else { if (account.Nonce && account.ClientType != "webui" && !account.Dropped && !loginRequest.kick) { - response.status(400).json({ error: "nonce still set" }); - return; + // U17 seems to handle "nonce still set" like a login failure. + if (version_compare(buildLabel, "2015.12.05.18.07") >= 0) { + response.status(400).send({ error: "nonce still set" }); + return; + } } account.ClientType = loginRequest.ClientType; diff --git a/src/routes/api.ts b/src/routes/api.ts index aeecf060..56602f4a 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -186,6 +186,7 @@ apiRouter.get("/getVendorInfo.php", getVendorInfoController); apiRouter.get("/hub", hubController); apiRouter.get("/hubInstances", hubInstancesController); apiRouter.get("/inbox.php", inboxController); +apiRouter.get("/getMessages.php", inboxController); // unsure if this is correct, but needed for U17 apiRouter.get("/inventory.php", inventoryController); apiRouter.get("/loginRewards.php", loginRewardsController); apiRouter.get("/logout.php", logoutController); @@ -278,6 +279,7 @@ apiRouter.post("/playerSkills.php", playerSkillsController); apiRouter.post("/postGuildAdvertisement.php", postGuildAdvertisementController); apiRouter.post("/projectionManager.php", projectionManagerController); apiRouter.post("/purchase.php", purchaseController); +apiRouter.post("/questControl.php", questControlController); // U17 apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController); apiRouter.post("/releasePet.php", releasePetController); apiRouter.post("/removeFromGuild.php", removeFromGuildController); diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 946997fc..a8129194 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -744,6 +744,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => { // Omit void fissures for versions prior to Dante Unbound to avoid script errors. if (buildLabel && version_compare(buildLabel, "2024.03.24.20.00") < 0) { worldState.ActiveMissions = []; + if (version_compare(buildLabel, "2017.10.12.17.04") < 0) { + // Old versions seem to really get hung up on not being able to load these. + worldState.PVPChallengeInstances = []; + } } if (config.worldState?.starDays) { diff --git a/src/types/worldStateTypes.ts b/src/types/worldStateTypes.ts index 1e8d4033..68c68753 100644 --- a/src/types/worldStateTypes.ts +++ b/src/types/worldStateTypes.ts @@ -12,6 +12,7 @@ export interface IWorldState { GlobalUpgrades: IGlobalUpgrade[]; ActiveMissions: IFissure[]; NodeOverrides: INodeOverride[]; + PVPChallengeInstances: IPVPChallengeInstance[]; EndlessXpChoices: IEndlessXpChoice[]; SeasonInfo: { Activation: IMongoDate; @@ -130,6 +131,21 @@ export interface ILiteSortie { }[]; } +export interface IPVPChallengeInstance { + _id: IOid; + challengeTypeRefID: string; + startDate: IMongoDate; + endDate: IMongoDate; + params: { + n: string; // "ScriptParamValue"; + v: number; + }[]; + isGenerated: boolean; + PVPMode: string; + subChallenges: IOid[]; + Category: string; // "PVPChallengeTypeCategory_WEEKLY" | "PVPChallengeTypeCategory_WEEKLY_ROOT" | "PVPChallengeTypeCategory_DAILY"; +} + export interface IEndlessXpChoice { Category: string; Choices: string[];