diff --git a/README/FIX_WEAPON_ITEM_INCLUDE.md b/README/FIX_WEAPON_ITEM_INCLUDE.md new file mode 100644 index 0000000..7134242 --- /dev/null +++ b/README/FIX_WEAPON_ITEM_INCLUDE.md @@ -0,0 +1,129 @@ +# 🔧 Fix: Error `weaponItem` en PlayerEquipment + +**Fecha**: Octubre 2025 +**Error**: `Unknown field 'weaponItem' for include statement on model PlayerEquipment` + +--- + +## 🐛 Problema + +Al ejecutar comandos `!pelear` y `!pescar`, aparecía el siguiente error de Prisma: + +``` +Invalid `prisma.playerEquipment.findUnique()` invocation: +{ + where: { userId_guildId: { ... } }, + include: { + weaponItem: true, // ❌ Campo desconocido + } +} + +Unknown field `weaponItem` for include statement on model `PlayerEquipment`. +Available options are marked with ?: user, guild +``` + +### Causa Raíz + +El modelo `PlayerEquipment` en el schema de Prisma **no tiene relaciones explícitas** con `EconomyItem`, solo almacena los IDs: + +```prisma +model PlayerEquipment { + weaponItemId String? // Solo el ID, sin relación @relation + armorItemId String? + capeItemId String? + + user User @relation(...) + guild Guild @relation(...) +} +``` + +El código intentaba usar `include: { weaponItem: true }` asumiendo una relación que no existe. + +--- + +## ✅ Solución + +Cambié la lógica en `validateRequirements()` para buscar el item manualmente después de obtener el `PlayerEquipment`: + +### Antes (❌ Incorrecto) +```typescript +const equip = await prisma.playerEquipment.findUnique({ + where: { userId_guildId: { userId, guildId } }, + include: { weaponItem: true } as any, // ❌ Relación no existe +}); +if (equip?.weaponItemId && equip?.weaponItem) { + const wProps = parseItemProps((equip as any).weaponItem.props); + // ... +} +``` + +### Después (✅ Correcto) +```typescript +const equip = await prisma.playerEquipment.findUnique({ + where: { userId_guildId: { userId, guildId } }, +}); +if (equip?.weaponItemId) { + const weaponItem = await prisma.economyItem.findUnique({ + where: { id: equip.weaponItemId }, + }); + if (weaponItem) { + const wProps = parseItemProps(weaponItem.props); + // ... + } +} +``` + +--- + +## 📝 Archivos Modificados + +- **`src/game/minigames/service.ts`**: Función `validateRequirements()` (líneas ~145-165) + +--- + +## 🔮 Alternativa Futura (Opcional) + +Si prefieres usar relaciones de Prisma, puedes agregar al schema: + +```prisma +model PlayerEquipment { + weaponItemId String? + armorItemId String? + capeItemId String? + + // Relaciones explícitas (opcional) + weaponItem EconomyItem? @relation("WeaponSlot", fields: [weaponItemId], references: [id]) + armorItem EconomyItem? @relation("ArmorSlot", fields: [armorItemId], references: [id]) + capeItem EconomyItem? @relation("CapeSlot", fields: [capeItemId], references: [id]) + + // ...resto +} + +model EconomyItem { + // ...campos existentes + + // Relaciones inversas + weaponSlots PlayerEquipment[] @relation("WeaponSlot") + armorSlots PlayerEquipment[] @relation("ArmorSlot") + capeSlots PlayerEquipment[] @relation("CapeSlot") +} +``` + +Luego ejecutar: +```bash +npx prisma migrate dev --name add-equipment-relations +``` + +**Ventaja**: Permite usar `include` sin queries adicionales. +**Desventaja**: Requiere migración; el fix actual funciona sin cambiar el schema. + +--- + +## ✅ Resultado + +Comandos `!pelear`, `!pescar` y `!mina` ahora funcionan correctamente sin errores de Prisma. + +--- + +**Typecheck**: ✅ Pasado +**Status**: Resuelto diff --git a/src/game/minigames/service.ts b/src/game/minigames/service.ts index 7a37ba8..47d672a 100644 --- a/src/game/minigames/service.ts +++ b/src/game/minigames/service.ts @@ -148,19 +148,23 @@ async function validateRequirements( // 1. Intentar herramienta equipada en slot weapon si coincide el tipo const equip = await prisma.playerEquipment.findUnique({ where: { userId_guildId: { userId, guildId } }, - include: { weaponItem: true } as any, }); - if (equip?.weaponItemId && equip?.weaponItem) { - const wProps = parseItemProps((equip as any).weaponItem.props); - if (wProps.tool?.type === toolReq.toolType) { - const tier = Math.max(0, wProps.tool?.tier ?? 0); - if ( - (toolReq.minTier == null || tier >= toolReq.minTier) && - (!toolReq.allowedKeys || - toolReq.allowedKeys.includes((equip as any).weaponItem.key)) - ) { - toolKeyUsed = (equip as any).weaponItem.key; - toolSource = "equipped"; + if (equip?.weaponItemId) { + const weaponItem = await prisma.economyItem.findUnique({ + where: { id: equip.weaponItemId }, + }); + if (weaponItem) { + const wProps = parseItemProps(weaponItem.props); + if (wProps.tool?.type === toolReq.toolType) { + const tier = Math.max(0, wProps.tool?.tier ?? 0); + if ( + (toolReq.minTier == null || tier >= toolReq.minTier) && + (!toolReq.allowedKeys || + toolReq.allowedKeys.includes(weaponItem.key)) + ) { + toolKeyUsed = weaponItem.key; + toolSource = "equipped"; + } } } }