diff --git a/server/src/gamedata/parse.ts b/server/src/gamedata/parse.ts index 2afb369..e29f41d 100644 --- a/server/src/gamedata/parse.ts +++ b/server/src/gamedata/parse.ts @@ -49,10 +49,20 @@ export interface ParseStats { localizedNames: number; } +/** + * Canonical tradeable id: an item with @enchantmentlevel n>0 is `@`. + * This matters for enchanted refined resources, whose base names already carry + * `_LEVELn` (e.g. T4_LEATHER_LEVEL3) AND an @enchantmentlevel — the real id the + * market uses is `T4_LEATHER_LEVEL3@3`, not `T4_LEATHER_LEVEL3`. + */ +function canonicalId(uniqueName: string, enchantLevel: number | null): string { + return enchantLevel && enchantLevel > 0 ? `${uniqueName}@${enchantLevel}` : uniqueName; +} + function parseCraftResources(req: Raw): ParsedRecipe['inputs'] { return asArray(req.craftresource) .map((r) => ({ - item: String(r['@uniquename'] ?? ''), + item: canonicalId(String(r['@uniquename'] ?? ''), num(r['@enchantmentlevel'])), count: num(r['@count']) ?? 0, maxReturnAmount: num(r['@maxreturnamount']), })) @@ -84,10 +94,15 @@ function collectItem(raw: Raw, items: ParsedItem[], recipes: ParsedRecipe[]): vo const uniqueName = raw['@uniquename']; if (!uniqueName || typeof uniqueName !== 'string') return; + // Some items (enchanted refined resources like T4_LEATHER_LEVEL3) carry their + // own @enchantmentlevel and no enchantments node — their tradeable id is @n. + const selfLevel = num(raw['@enchantmentlevel']) ?? 0; + const selfId = canonicalId(uniqueName, selfLevel); + const base: ParsedItem = { - uniqueName, + uniqueName: selfId, baseName: uniqueName, - enchantment: 0, + enchantment: selfLevel, tier: num(raw['@tier']), weight: num(raw['@weight']), itemValue: num(raw['@itemvalue']), @@ -96,7 +111,7 @@ function collectItem(raw: Raw, items: ParsedItem[], recipes: ParsedRecipe[]): vo craftingCategory: raw['@craftingcategory'] ?? null, }; items.push(base); - recipes.push(...parseRecipesForOutput(uniqueName, raw.craftingrequirements)); + recipes.push(...parseRecipesForOutput(selfId, raw.craftingrequirements)); // Enchanted variants live under enchantments.enchantment with their own recipes. for (const ench of asArray(raw.enchantments?.enchantment)) {