import type { RequestHandler } from "express";
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
import { getAccountForRequest, getBuildLabel } from "../../services/loginService.ts";
import { getInventory2, addMods, addMiscItem, addSkin } from "../../services/inventoryService.ts";
import type { IOid } from "../../types/commonTypes.ts";
import { logger } from "../../utils/logger.ts";
import gameToBuildVersion from "../../constants/gameToBuildVersion.ts";
import { fromOid, version_compare } from "../../helpers/inventoryHelpers.ts";
export const arcaneCommonController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req);
const inventory = await getInventory2(
account._id.toString(),
"WeaponSkins",
"OperatorAmps",
"Upgrades",
"RawUpgrades",
"MiscItems"
);
const json = getJSONfromString<IArcaneCommonRequest | IArcaneLegacyRequest>(String(req.body));
if (!("newRank" in json) && "skinId" in json) {
// logger.debug(`legacy arcane request:`, json);
let skinId = json.skinId;
if (json.giveItem && json.itemTypeName && json.modType == 6) {
const inventoryChanges = addSkin(inventory, json.itemTypeName);
skinId = fromOid(inventoryChanges.WeaponSkins![0].ItemId);
}
const item = json.modType == 5 ? inventory.OperatorAmps.id(skinId) : inventory.WeaponSkins.id(skinId);
if (item) {
if (json.operationType == "Install") {
const resp: IArcaneLegacyInstallResp = { newLevel: 0 };
let currentLevel = item.UpgradeFingerprint
? (JSON.parse(item.UpgradeFingerprint) as { lvl: number }).lvl
: -1;
// Return different arcane
if (item.UpgradeType && item.UpgradeType != json.arcaneType && currentLevel >= 0) {
const numToRefund = legacyArcaneLevelCounts[currentLevel];
resp.numToRefund = numToRefund;
resp.typeToRefund = item.UpgradeType;
addMods(inventory, [{ ItemType: item.UpgradeType, ItemCount: numToRefund }]);
item.UpgradeFingerprint = undefined;
item.UpgradeType = undefined;
currentLevel = -1;
}
const newLevel = currentLevel + 1;
resp.newLevel = newLevel;
let numConsumed = legacyArcaneLevelCounts[newLevel];
if (currentLevel >= 0) {
numConsumed -= legacyArcaneLevelCounts[currentLevel];
}
item.UpgradeFingerprint = JSON.stringify({ lvl: newLevel });
item.UpgradeType = json.arcaneType!;
addMods(inventory, [{ ItemType: json.arcaneType!, ItemCount: numConsumed * -1 }]);
if (json.giveItem) {
resp.AddedSkinId = skinId;
}
// logger.debug(`legacy arcane resp:`, resp);
res.json(resp);
} else if (json.operationType == "Distill") {
const currentLevel = (JSON.parse(item.UpgradeFingerprint!) as { lvl: number }).lvl;
const arcaneType = item.UpgradeType!;
const numToRefund = legacyArcaneLevelCounts[currentLevel];
item.UpgradeFingerprint = undefined;
item.UpgradeType = undefined;
addMods(inventory, [{ ItemType: arcaneType, ItemCount: numToRefund }]);
const buildLabel = getBuildLabel(req, account);
if (version_compare(buildLabel, gameToBuildVersion["19.4.1"]) <= 0) {
addMiscItem(inventory, "/Lotus/Types/Recipes/CosmeticUnenhancerItem", -1);
}
res.json({ arcaneType, numToRefund });
} else {
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
throw new Error(`unknown legacy arcaneCommon operationType: ${json.operationType}`);
}
} else {
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
throw new Error(`Failed to find item with OID ${json.skinId}, modType ${json.modType}`);
}
await inventory.save();
return;
}
const upgrade = inventory.Upgrades.id(json.arcane.ItemId.$oid);
if (json.newRank == -1) {
// Break down request?
if (!upgrade || !upgrade.UpgradeFingerprint) {
throw new Error(`Failed to find upgrade with OID ${json.arcane.ItemId.$oid}`);
}
// Remove Upgrade
inventory.Upgrades.pull({ _id: json.arcane.ItemId.$oid });
// Add RawUpgrades
const numRawUpgradesToGive = arcaneLevelCounts[(JSON.parse(upgrade.UpgradeFingerprint) as { lvl: number }).lvl];
addMods(inventory, [
{
ItemType: json.arcane.ItemType,
ItemCount: numRawUpgradesToGive
}
]);
res.json({ upgradeId: json.arcane.ItemId.$oid, numConsumed: numRawUpgradesToGive });
} else {
// Upgrade request?
let numConsumed = arcaneLevelCounts[json.newRank];
let upgradeId = json.arcane.ItemId.$oid;
if (upgrade) {
// Have an existing Upgrade item?
if (upgrade.UpgradeFingerprint) {
const existingLevel = (JSON.parse(upgrade.UpgradeFingerprint) as { lvl: number }).lvl;
numConsumed -= arcaneLevelCounts[existingLevel];
}
upgrade.UpgradeFingerprint = JSON.stringify({ lvl: json.newRank });
} else {
const newLength = inventory.Upgrades.push({
ItemType: json.arcane.ItemType,
UpgradeFingerprint: JSON.stringify({ lvl: json.newRank })
});
upgradeId = inventory.Upgrades[newLength - 1]._id.toString();
}
// Remove RawUpgrades
addMods(inventory, [
{
ItemType: json.arcane.ItemType,
ItemCount: numConsumed * -1
}
]);
res.json({ newLevel: json.newRank, numConsumed, upgradeId });
}
await inventory.save();
};
const arcaneLevelCounts = [0, 3, 6, 10, 15, 21];
const legacyArcaneLevelCounts = [1, 3, 6, 10];
interface IArcaneCommonRequest {
arcane: {
ItemType: string;
ItemId: IOid;
FromSKU: boolean;
UpgradeFingerprint: string;
PendingRerollFingerprint: string;
ItemCount: number;
LastAdded: IOid;
};
newRank: number;
}
interface IArcaneLegacyRequest {
arcaneType?: string;
skinId: string;
operationType: "Install" | "Distill" | "idk";
modType?: number; // 6 for WeaponSkins, 5 for Amps. not present in U18.5
giveItem?: boolean;
itemTypeName?: string;
}
interface IArcaneLegacyInstallResp {
newLevel: number;
typeToRefund?: string;
numToRefund?: number;
AddedSkinId?: string;
}
// interface IArcaneLegacyDistillResp {
// arcaneType: string;
// numToRefund: number;
// }
import type { RequestHandler } from "express";
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
import { getAccountForRequest, getBuildLabel } from "../../services/loginService.ts";
import { getInventory2, addMods, addMiscItem, addSkin } from "../../services/inventoryService.ts";
import type { IOid } from "../../types/commonTypes.ts";
import { logger } from "../../utils/logger.ts";
import gameToBuildVersion from "../../constants/gameToBuildVersion.ts";
import { fromOid, version_compare } from "../../helpers/inventoryHelpers.ts";
export const arcaneCommonController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req);
const inventory = await getInventory2(
account._id.toString(),
"WeaponSkins",
"OperatorAmps",
"Upgrades",
"RawUpgrades",
"MiscItems"
);
const json = getJSONfromString<IArcaneCommonRequest | IArcaneLegacyRequest>(String(req.body));
if (!("newRank" in json) && "skinId" in json) {
// logger.debug(`legacy arcane request:`, json);
let skinId = json.skinId;
if (json.giveItem && json.itemTypeName && json.modType == 6) {
const inventoryChanges = addSkin(inventory, json.itemTypeName);
skinId = fromOid(inventoryChanges.WeaponSkins![0].ItemId);
}
const item = json.modType == 5 ? inventory.OperatorAmps.id(skinId) : inventory.WeaponSkins.id(skinId);
if (item) {
if (json.operationType == "Install") {
const resp: IArcaneLegacyInstallResp = { newLevel: 0 };
let currentLevel = item.UpgradeFingerprint
? (JSON.parse(item.UpgradeFingerprint) as { lvl: number }).lvl
: -1;
// Return different arcane
if (item.UpgradeType && item.UpgradeType != json.arcaneType && currentLevel >= 0) {
const numToRefund = legacyArcaneLevelCounts[currentLevel];
resp.numToRefund = numToRefund;
resp.typeToRefund = item.UpgradeType;
addMods(inventory, [{ ItemType: item.UpgradeType, ItemCount: numToRefund }]);
item.UpgradeFingerprint = undefined;
item.UpgradeType = undefined;
currentLevel = -1;
}
const newLevel = currentLevel + 1;
resp.newLevel = newLevel;
let numConsumed = legacyArcaneLevelCounts[newLevel];
if (currentLevel >= 0) {
numConsumed -= legacyArcaneLevelCounts[currentLevel];
}
item.UpgradeFingerprint = JSON.stringify({ lvl: newLevel });
item.UpgradeType = json.arcaneType!;
addMods(inventory, [{ ItemType: json.arcaneType!, ItemCount: numConsumed * -1 }]);
if (json.giveItem) {
resp.AddedSkinId = skinId;
}
// logger.debug(`legacy arcane resp:`, resp);
res.json(resp);
} else if (json.operationType == "Distill") {
const currentLevel = (JSON.parse(item.UpgradeFingerprint!) as { lvl: number }).lvl;
const arcaneType = item.UpgradeType!;
const numToRefund = legacyArcaneLevelCounts[currentLevel];
item.UpgradeFingerprint = undefined;
item.UpgradeType = undefined;
addMods(inventory, [{ ItemType: arcaneType, ItemCount: numToRefund }]);
const buildLabel = getBuildLabel(req, account);
if (version_compare(buildLabel, gameToBuildVersion["19.4.1"]) <= 0) {
addMiscItem(inventory, "/Lotus/Types/Recipes/CosmeticUnenhancerItem", -1);
}
res.json({ arcaneType, numToRefund });
} else {
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
throw new Error(`unknown legacy arcaneCommon operationType: ${json.operationType}`);
}
} else {
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
throw new Error(`Failed to find item with OID ${json.skinId}, modType ${json.modType}`);
}
await inventory.save();
return;
}
const upgrade = inventory.Upgrades.id(json.arcane.ItemId.$oid);
if (json.newRank == -1) {
// Break down request?
if (!upgrade || !upgrade.UpgradeFingerprint) {
throw new Error(`Failed to find upgrade with OID ${json.arcane.ItemId.$oid}`);
}
// Remove Upgrade
inventory.Upgrades.pull({ _id: json.arcane.ItemId.$oid });
// Add RawUpgrades
const numRawUpgradesToGive = arcaneLevelCounts[(JSON.parse(upgrade.UpgradeFingerprint) as { lvl: number }).lvl];
addMods(inventory, [
{
ItemType: json.arcane.ItemType,
ItemCount: numRawUpgradesToGive
}
]);
res.json({ upgradeId: json.arcane.ItemId.$oid, numConsumed: numRawUpgradesToGive });
} else {
// Upgrade request?
let numConsumed = arcaneLevelCounts[json.newRank];
let upgradeId = json.arcane.ItemId.$oid;
if (upgrade) {
// Have an existing Upgrade item?
if (upgrade.UpgradeFingerprint) {
const existingLevel = (JSON.parse(upgrade.UpgradeFingerprint) as { lvl: number }).lvl;
numConsumed -= arcaneLevelCounts[existingLevel];
}
upgrade.UpgradeFingerprint = JSON.stringify({ lvl: json.newRank });
} else {
const newLength = inventory.Upgrades.push({
ItemType: json.arcane.ItemType,
UpgradeFingerprint: JSON.stringify({ lvl: json.newRank })
});
upgradeId = inventory.Upgrades[newLength - 1]._id.toString();
}
// Remove RawUpgrades
addMods(inventory, [
{
ItemType: json.arcane.ItemType,
ItemCount: numConsumed * -1
}
]);
res.json({ newLevel: json.newRank, numConsumed, upgradeId });
}
await inventory.save();
};
const arcaneLevelCounts = [0, 3, 6, 10, 15, 21];
const legacyArcaneLevelCounts = [1, 3, 6, 10];
interface IArcaneCommonRequest {
arcane: {
ItemType: string;
ItemId: IOid;
FromSKU: boolean;
UpgradeFingerprint: string;
PendingRerollFingerprint: string;
ItemCount: number;
LastAdded: IOid;
};
newRank: number;
}
interface IArcaneLegacyRequest {
arcaneType?: string;
skinId: string;
operationType: "Install" | "Distill" | "idk";
modType?: number; // 6 for WeaponSkins, 5 for Amps. not present in U18.5
giveItem?: boolean;
itemTypeName?: string;
}
interface IArcaneLegacyInstallResp {
newLevel: number;
typeToRefund?: string;
numToRefund?: number;
AddedSkinId?: string;
}
// interface IArcaneLegacyDistillResp {
// arcaneType: string;
// numToRefund: number;
// }