diff --git a/client/src/views/GameInterface/tabs/InventoryTab.jsx b/client/src/views/GameInterface/tabs/InventoryTab.jsx index e13bc7b..e3d2839 100644 --- a/client/src/views/GameInterface/tabs/InventoryTab.jsx +++ b/client/src/views/GameInterface/tabs/InventoryTab.jsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from "react"; +import ReactDOM from "react-dom"; import { useSocket } from "../../../hooks/useSocket"; import GameDataManager from "../../../services/GameDataManager.js"; -import Button from "../../../components/ui/Button"; +import ItemModal from "./components/ItemModal"; import "./styles/InventoryTab.css"; import { getServerUrl } from "../../../config/api.js"; @@ -14,21 +15,8 @@ const InventoryTab = () => { const CONNECT_URL = getServerUrl(); const ASSET_BASE_URL = `${CONNECT_URL}/static/`; - const equipmentSlots = { - personal: [ - { id: "personal_helmet", label: "HELMET" }, - { id: "personal_suit", label: "SUIT" }, - { id: "personal_gloves", label: "GLOVES" }, - { id: "personal_boots", label: "BOOTS" }, - { id: "personal_backpack", label: "BACKPACK" }, - { id: "personal_weapons", label: "WEAPON" }, - ], - ship: [ - { id: "ship_hull", label: "HULL" }, - { id: "ship_shields", label: "SHIELDS" }, - { id: "ship_engines", label: "ENGINES" }, - ], - }; + const manifest = GameDataManager.manifest || {}; + const coreSystems = manifest.core_systems?.categories || {}; const getFullTextureUrl = (path) => { if (!path) return "/assets/no-image.png"; @@ -36,11 +24,10 @@ const InventoryTab = () => { return `${ASSET_BASE_URL}${path}`; }; - const enrichItemData = (serverItem) => { + const enrichItemData = (serverItem, currentSlot = null) => { if (!serverItem || (!serverItem.itemId && !serverItem.id)) return null; const id = serverItem.itemId || serverItem.id; const staticData = GameDataManager.getItem(id); - return { ...serverItem, ...staticData, @@ -48,28 +35,29 @@ const InventoryTab = () => { textureUrl: getFullTextureUrl(staticData?.texture), canEquip: !!staticData?.meta?.equipmentSlot, rarity: staticData?.meta?.rarity || "common", + currentSlot: currentSlot, }; }; useEffect(() => { if (!socket) return; - const refresh = () => { + const refreshData = () => { socket.emit("player:get_inventory"); socket.emit("player:get_equipment"); }; - refresh(); + refreshData(); const handleInventory = (rawItems) => { - setItems(rawItems.map(enrichItemData).filter(Boolean)); + setItems(rawItems.map((item) => enrichItemData(item)).filter(Boolean)); }; const handleEquipment = (rawEquip) => { const mapped = {}; Object.keys(rawEquip).forEach((slot) => { if (rawEquip[slot]) { - mapped[slot] = enrichItemData({ itemId: rawEquip[slot] }); + mapped[slot] = enrichItemData({ itemId: rawEquip[slot] }, slot); } }); setEquipment(mapped); @@ -77,39 +65,70 @@ const InventoryTab = () => { socket.on("player:inventory_data", handleInventory); socket.on("player:equipment_data", handleEquipment); + socket.on("player:item_equipped", refreshData); + socket.on("player:item_unequipped", refreshData); return () => { socket.off("player:inventory_data", handleInventory); socket.off("player:equipment_data", handleEquipment); + socket.off("player:item_equipped", refreshData); + socket.off("player:item_unequipped", refreshData); }; }, [socket]); - const handleItemClick = (item) => { - setSelectedItem(item); - setShowModal(true); - }; - const equipItem = (item) => { const slot = item.meta?.equipmentSlot; - if (slot) { - socket.emit("player:equip_item", { itemId: item.id, slot }); - setShowModal(false); - } + if (slot) socket.emit("player:equip_item", { itemId: item.id, slot }); }; const unequipItem = (slot) => { socket.emit("player:unequip_item", { slot }); }; + const equipmentSlots = { + personal: Object.keys(coreSystems) + .filter( + (key) => + key.startsWith("original:personal_") && + !key.includes("accessory") && + key !== "original:personal_weapons", + ) + .map((key) => ({ + id: key, + label: GameDataManager.t(coreSystems[key].displayName), + })), + weapons: Object.keys(coreSystems) + .filter((key) => key === "original:personal_weapons") + .map((key) => ({ + id: key, + label: GameDataManager.t(coreSystems[key].displayName), + })), + accessories: Object.keys(coreSystems) + .filter((key) => key.includes("personal_accessory")) + .map((key) => ({ + id: key, + label: GameDataManager.t(coreSystems[key].displayName), + })), + ship: Object.keys(coreSystems) + .filter((key) => key.startsWith("original:ship_")) + .map((key) => ({ + id: key, + label: GameDataManager.t(coreSystems[key].displayName), + })), + }; + const renderSlotGroup = (title, groupSlots) => (
{title}
-
+
{groupSlots.map((slot) => (
equipment[slot.id] && unequipItem(slot.id)} + onClick={() => + equipment[slot.id] && + (setSelectedItem(equipment[slot.id]), setShowModal(true)) + } > {slot.label}
{ {equipment[slot.id] ? ( {slot.id} ) : ( @@ -133,88 +151,71 @@ const InventoryTab = () => { return (
-
-

TACTICAL_INVENTORY_V2

-
- - LOAD: {items.length}/50 - -
-
-
-
-
CORE_SYSTEMS
- - {renderSlotGroup("PERSON", equipmentSlots.personal)} - {renderSlotGroup("SHIP", equipmentSlots.ship)} +
+ {renderSlotGroup("SUIT_GEAR", equipmentSlots.personal)} + {renderSlotGroup("WEAPONRY", equipmentSlots.weapons)} + {renderSlotGroup("ACCESSORIES", equipmentSlots.accessories)} +
+ {renderSlotGroup("SHIP_MODULES", equipmentSlots.ship)}
-
-
STORAGE_UNITS
- {items.map((item, idx) => ( -
handleItemClick(item)} - > - item - {item.quantity > 1 && ( - {item.quantity} - )} -
- ))} + {items.map((item, idx) => { + const isEquipped = Object.values(equipment).some( + (e) => e?.id === item.id, + ); + return ( +
{ + setSelectedItem(item); + setShowModal(true); + }} + > + + {isEquipped &&
E
} + {item.quantity > 1 && ( + {item.quantity} + )} +
+ ); + })}
- - {showModal && selectedItem && ( -
setShowModal(false)}> -
e.stopPropagation()}> -
-
- preview -
-

{selectedItem.displayName || selectedItem.id}

-
- -
-

- {selectedItem.description || "No data available."} -

- -
- {selectedItem.stats && - Object.entries(selectedItem.stats).map(([k, v]) => ( -
- - {GameDataManager.getStatName?.(k)?.toUpperCase() || - k.toUpperCase()} - - +{v} -
- ))} -
- - {selectedItem.canEquip && ( - - )} -
-
-
- )} + {showModal && + selectedItem && + ReactDOM.createPortal( + e?.id === selectedItem.id) + } + onClose={() => { + setShowModal(false); + setSelectedItem(null); + }} + onEquip={equipItem} + onUnequip={(slot) => { + const actualSlot = + slot || + Object.keys(equipment).find( + (k) => equipment[k].id === selectedItem.id, + ); + unequipItem(actualSlot); + }} + formatStatName={(n) => GameDataManager.getStatName(n).toUpperCase()} + getStatIcon={(n) => GameDataManager.getStatIcon?.(n)} + />, + document.body, + )}
); }; diff --git a/client/src/views/GameInterface/tabs/components/ItemModal.css b/client/src/views/GameInterface/tabs/components/ItemModal.css index ae9c3b8..39290a0 100644 --- a/client/src/views/GameInterface/tabs/components/ItemModal.css +++ b/client/src/views/GameInterface/tabs/components/ItemModal.css @@ -1,36 +1,28 @@ -/* Ховаємо праву панель на мобілках */ -@media (max-width: 768px) { - .inventory-container { - grid-template-columns: 1fr; /* Тільки одна колонка (сітка) */ - } - .item-details { - display: none; /* Панель справа зникає */ - } -} - -/* Стилі модального вікна */ .modal-overlay { position: fixed; top: 0; left: 0; - height: 100%; + width: 100vw; + height: 100vh; background: rgba(0, 0, 0, 0.85); display: flex; justify-content: center; align-items: center; - z-index: 1000; - padding: 20px; - width: 100%; + z-index: 9999; + backdrop-filter: blur(4px); } .modal-content { - background: var(--card-bg); - border: 1px solid var(--primary-color); - border-radius: 12px; + background: #12151a; + border: 1px solid #00d2ff; + border-radius: 8px; width: 100%; - padding: 40px; + max-width: 400px; + padding: 25px; position: relative; box-shadow: 0 0 30px rgba(0, 210, 255, 0.2); + color: #fff; + font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } .modal-close { @@ -39,7 +31,114 @@ right: 15px; background: none; border: none; - color: #fff; - font-size: 24px; + color: #888; + font-size: 28px; cursor: pointer; + transition: color 0.2s; +} + +.modal-close:hover { + color: #fff; +} + +.details-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 15px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + padding-bottom: 10px; +} + +.item-name { + margin: 0; + font-size: 1.2rem; + text-transform: uppercase; + letter-spacing: 1px; +} + +.rarity-badge { + font-size: 0.7rem; + padding: 2px 8px; + border-radius: 4px; + text-transform: uppercase; + background: rgba(255, 255, 255, 0.1); +} + +.item-name.common { + color: #ffffff; +} +.item-name.uncommon { + color: #1eff00; +} +.item-name.rare { + color: #0070dd; +} +.item-name.epic { + color: #a335ee; +} +.item-name.legendary { + color: #ff8000; +} + +.item-description { + font-size: 0.9rem; + color: #aaa; + line-height: 1.4; + margin-bottom: 20px; +} + +.item-stats-container { + background: rgba(0, 0, 0, 0.3); + padding: 10px; + border-radius: 4px; + margin-bottom: 25px; +} + +.stat-row { + display: flex; + justify-content: space-between; + padding: 5px 0; + font-size: 0.85rem; +} + +.stat-label { + color: #00d2ff; + display: flex; + align-items: center; + gap: 8px; +} + +.stat-value { + color: #fff; + font-weight: bold; +} + +.btn-equip { + width: 100%; + padding: 12px; + background: none; + border: 1px solid #00d2ff; + color: #00d2ff; + cursor: pointer; + text-transform: uppercase; + font-weight: bold; + letter-spacing: 1px; + transition: all 0.2s; +} + +.btn-equip:hover { + background: #00d2ff; + color: #000; + box-shadow: 0 0 15px rgba(0, 210, 255, 0.4); +} + +.btn-equip.unequip { + border-color: #ff4444; + color: #ff4444; +} + +.btn-equip.unequip:hover { + background: #ff4444; + color: #fff; } diff --git a/client/src/views/GameInterface/tabs/styles/InventoryTab.css b/client/src/views/GameInterface/tabs/styles/InventoryTab.css index 0175e71..9243ec2 100644 --- a/client/src/views/GameInterface/tabs/styles/InventoryTab.css +++ b/client/src/views/GameInterface/tabs/styles/InventoryTab.css @@ -1,4 +1,3 @@ -/* Базовий контейнер з обмеженням висоти */ .inv-adaptive-container { display: flex; flex-direction: column; @@ -10,7 +9,6 @@ overflow: hidden; } -/* Header */ .inv-header-compact { display: flex; justify-content: space-between; @@ -18,6 +16,7 @@ border-bottom: 1px solid #1a2638; padding-bottom: 10px; margin-bottom: 5px; + flex-shrink: 0; } .inv-logo { @@ -26,16 +25,17 @@ letter-spacing: 3px; margin: 0; } + .inv-stats-bar { font-size: 11px; color: #4a5d75; } + .text-cyan { color: #00d4ff; font-weight: bold; } -/* Layout Wrapper */ .inv-layout-wrapper { display: flex; flex-direction: row; @@ -44,13 +44,13 @@ min-height: 0; } -/* Спільні стилі панелей */ .inv-panel { background: rgba(10, 15, 24, 0.85); border: 1px solid #1a2638; display: flex; flex-direction: column; box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.5); + min-height: 0; } .panel-label { @@ -61,26 +61,55 @@ letter-spacing: 2px; font-weight: 800; border-bottom: 1px solid #1a2638; + flex-shrink: 0; } -/* Loadout (L) */ .loadout { width: 240px; flex-shrink: 0; + overflow-y: auto; } + +.loadout::-webkit-scrollbar, +.cargo-grid-v2::-webkit-scrollbar { + width: 4px; +} + +.loadout::-webkit-scrollbar-thumb, +.cargo-grid-v2::-webkit-scrollbar-thumb { + background: #1a2638; + border-radius: 2px; +} + +.loadout::-webkit-scrollbar-thumb:hover, +.cargo-grid-v2::-webkit-scrollbar-thumb:hover { + background: #00d4ff; +} + .equip-list-compact { padding: 10px; - overflow-y: auto; display: flex; flex-direction: column; gap: 8px; } +.equip-group { + margin-bottom: 15px; +} + +.group-label { + font-size: 10px; + color: #4a5d75; + margin-bottom: 5px; + padding-left: 5px; + text-transform: uppercase; +} + .equip-row-mini { display: flex; justify-content: space-between; align-items: center; - padding: 8px 12px; + padding: 6px 10px; background: rgba(255, 255, 255, 0.02); border: 1px solid rgba(26, 38, 56, 0.8); transition: 0.2s; @@ -91,37 +120,46 @@ border-color: #00d4ff; background: rgba(0, 212, 255, 0.05); } + .slot-name-tiny { font-size: 9px; color: #4a5d75; + max-width: 140px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .equip-box-mini { - width: 36px; - height: 36px; + width: 32px; + height: 32px; background: #000; border: 1px solid #1a2638; display: flex; align-items: center; justify-content: center; color: #00d4ff; - font-size: 1.1rem; + font-size: 0.9rem; + flex-shrink: 0; } -/* Cargo (R) */ .cargo { flex: 1; + min-width: 0; } + .cargo-grid-v2 { display: grid; - grid-template-columns: repeat(auto-fill, minmax(65px, 1fr)); - grid-auto-rows: 65px; - gap: 10px; + grid-template-columns: repeat(auto-fill, minmax(60px, 1fr)); + gap: 8px; padding: 15px; overflow-y: auto; + flex: 1; } .item-slot { + width: 60px; + height: 60px; background: rgba(5, 8, 12, 0.9); border: 1px solid #1a2638; display: flex; @@ -130,183 +168,68 @@ position: relative; cursor: pointer; transition: 0.2s; + overflow: hidden; +} + +.item-img-grid, +.item-img-mini { + max-width: 90%; + max-height: 90%; + object-fit: contain; } .item-slot:hover { border-color: #00d4ff; background: rgba(0, 212, 255, 0.1); } + .item-slot.active { border-color: #00d4ff; box-shadow: inset 0 0 10px rgba(0, 212, 255, 0.3); } -/* Rarity Colors */ -.item-slot.rare, -.equip-box-mini.rare { - border-bottom: 2px solid #00d4ff; -} -.item-slot.epic, -.equip-box-mini.epic { - border-bottom: 2px solid #a335ee; -} -.item-slot.legendary, -.equip-box-mini.legendary { - border-bottom: 2px solid #ffaa00; +.separator { + height: 1px; + background: #1a2638; + margin: 10px 5px; } -.qty-label { - position: absolute; - bottom: 2px; - right: 5px; - font-size: 10px; - color: #00d4ff; - font-family: monospace; -} -.item-slot.empty { - opacity: 0.15; - cursor: default; -} - -/* Modal Styles */ -.inv-modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.9); - backdrop-filter: blur(8px); - display: flex; - align-items: center; - justify-content: center; - z-index: 2000; -} - -.inv-modal-box { - background: #0a0f18; - border: 1px solid #1a2638; - width: 90%; - max-width: 380px; - box-shadow: 0 0 40px rgba(0, 0, 0, 0.8); -} - -.modal-header-scan { - padding: 20px; - border-bottom: 1px solid #1a2638; - position: relative; -} - -.modal-header-scan.rare { - border-left: 5px solid #00d4ff; -} -.modal-header-scan.legendary { - border-left: 5px solid #ffaa00; -} - -.rarity-text { - font-size: 10px; - color: #4a5d75; - text-transform: uppercase; - margin-bottom: 5px; -} -.modal-header-scan h3 { - margin: 0; - font-size: 1.2rem; - color: #fff; -} - -.close-x { - position: absolute; - top: 15px; - right: 15px; - background: none; - border: none; - color: #4a5d75; - font-size: 24px; - cursor: pointer; -} - -.modal-body-scan { - padding: 20px; -} -.description-text { - font-size: 12px; - color: #8a9cb3; - line-height: 1.5; - margin-bottom: 20px; -} - -.stats-scanner { - background: rgba(0, 0, 0, 0.4); - padding: 12px; - margin-bottom: 20px; -} -.stat-line { - display: flex; - justify-content: space-between; - font-size: 12px; - padding: 6px 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.05); -} -.stat-line .value { - color: #00ff88; -} - -.modal-equip-btn { - width: 100%; - letter-spacing: 2px; - font-weight: 900; -} - -/* Адаптивність під мобільні пристрої */ @media (max-width: 768px) { + .inv-adaptive-container { + height: auto; + overflow-y: visible; + } + .inv-layout-wrapper { flex-direction: column; - overflow-y: auto; + height: auto; } .loadout { width: 100%; - flex: 0 0 auto; - } - - .equip-list-compact { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; + max-height: 300px; } .cargo { - min-height: 450px; - flex: 0 0 auto; - } - - .inv-adaptive-container { - height: 100%; - overflow-y: auto; - padding: 10px; + height: 400px; } } -.cargo-grid-v2 { - display: grid; - grid-template-columns: repeat( - auto-fill, - minmax(60px, 1fr) - ); /* Кожен слот мінімум 60px */ - gap: 8px; - padding: 10px; +.item-slot.equipped-in-storage { + border: 2px solid #00d2ff; + box-shadow: inset 0 0 10px rgba(0, 210, 255, 0.3); + opacity: 0.8; } -.item-slot { - width: 60px; /* Жорсткий розмір слота */ - height: 60px; /* Жорсткий розмір слота */ - position: relative; - display: flex; - align-items: center; - justify-content: center; - background: rgba(0, 0, 0, 0.5); - border: 1px solid #333; - overflow: hidden; /* Обрізаємо все, що виходить за межі 60x60 */ +.equipped-tag { + position: absolute; + top: -5px; + right: -5px; + background: #00d2ff; + color: #000; + font-size: 10px; + font-weight: bold; + padding: 2px 5px; + border-radius: 3px; + z-index: 2; } diff --git a/game-server/src/game/InventoryManager.js b/game-server/src/game/InventoryManager.js index 100e5c4..5fa74cb 100644 --- a/game-server/src/game/InventoryManager.js +++ b/game-server/src/game/InventoryManager.js @@ -11,25 +11,7 @@ class InventoryManager { async getEquipment(playerId) { const player = await Player.findByPk(playerId); - if (!player) return {}; - - const slots = [ - "personal_helmet", - "personal_suit", - "personal_gloves", - "personal_backpack", - "personal_boots", - "personal_weapons", - "ship_hull", - "ship_shields", - "ship_engines", - ]; - - const equipment = {}; - slots.forEach((slot) => { - equipment[slot] = player[`equipped_${slot}`] || null; - }); - return equipment; + return player ? player.equipment : {}; } async equipItem(playerId, itemId, slot) { @@ -44,14 +26,31 @@ class InventoryManager { throw new Error("INVALID_SLOT_FOR_ITEM"); } - const dbField = `equipped_${slot}`.replace("original:", ""); - await Player.update({ [dbField]: itemId }, { where: { id: playerId } }); + const player = await Player.findByPk(playerId); + if (!player) throw new Error("PLAYER_NOT_FOUND"); + + const currentEquip = player.equipment; + currentEquip[slot] = itemId; + + player.equipment = currentEquip; + player.changed("equipment", true); + await player.save(); + return itemInfo; } async unequipItem(playerId, slot) { - const dbField = `equipped_${slot}`; - await Player.update({ [dbField]: null }, { where: { id: playerId } }); + const player = await Player.findByPk(playerId); + if (!player) throw new Error("PLAYER_NOT_FOUND"); + + const currentEquip = player.equipment; + if (currentEquip[slot]) { + delete currentEquip[slot]; + player.equipment = currentEquip; + player.changed("equipment", true); + await player.save(); + } + return true; } } diff --git a/game-server/src/game/SessionManager.js b/game-server/src/game/SessionManager.js index 74e9188..9ed8b67 100644 --- a/game-server/src/game/SessionManager.js +++ b/game-server/src/game/SessionManager.js @@ -1,6 +1,6 @@ class SessionManager { constructor() { - this.sessions = new Map(); // socket.id => session data + this.sessions = new Map(); } addPlayer(socketId, playerRaw) { @@ -15,29 +15,18 @@ class SessionManager { scene: "world", sceneData: null, joinedAt: Date.now(), - equipment: { - personal_helmet: playerRaw.equipped_personal_helmet, - personal_suit: playerRaw.equipped_personal_suit, - personal_gloves: playerRaw.equipped_personal_gloves, - personal_backpack: playerRaw.equipped_personal_backpack, - personal_boots: playerRaw.equipped_personal_boots, - personal_weapons: playerRaw.equipped_personal_weapons, - - ship_hull: playerRaw.equipped_ship_hull, - ship_shields: playerRaw.equipped_ship_shields, - ship_engines: playerRaw.equipped_ship_engines, - ship_weapon_1: playerRaw.equipped_ship_weapon_1, - ship_weapon_2: playerRaw.equipped_ship_weapon_2, - }, + equipment: playerRaw.equipment || {}, }); } updateEquipment(socketId, slot, itemId) { const session = this.sessions.get(socketId); - if (session && session.equipment.hasOwnProperty(slot)) { - session.equipment[slot] = itemId; - } else if (session) { - session.equipment[slot] = itemId; + if (session) { + if (itemId === null) { + delete session.equipment[slot]; + } else { + session.equipment[slot] = itemId; + } } } @@ -47,7 +36,6 @@ class SessionManager { session.scene = sceneName; session.sceneData = data; session.status = sceneName === "dungeon" ? "in_mission" : "active"; - console.log(`[Session] Player ${session.id} switched to ${sceneName}`); } } diff --git a/game-server/src/models/Player.js b/game-server/src/models/Player.js index 9679098..3a0d908 100644 --- a/game-server/src/models/Player.js +++ b/game-server/src/models/Player.js @@ -42,22 +42,17 @@ const Player = sequelize.define("Player", { type: DataTypes.DATE, defaultValue: DataTypes.NOW, }, - - equipped_personal_helmet: { type: DataTypes.STRING }, - equipped_personal_suit: { type: DataTypes.STRING }, - equipped_personal_gloves: { type: DataTypes.STRING }, - equipped_personal_backpack: { type: DataTypes.STRING }, - equipped_personal_boots: { type: DataTypes.STRING }, - equipped_personal_weapons: { type: DataTypes.STRING }, - - equipped_personal_accessory_1: { type: DataTypes.STRING }, - equipped_personal_accessory_2: { type: DataTypes.STRING }, - - equipped_ship_hull: { type: DataTypes.STRING }, - equipped_ship_shields: { type: DataTypes.STRING }, - equipped_ship_engines: { type: DataTypes.STRING }, - equipped_ship_weapon_1: { type: DataTypes.STRING }, - equipped_ship_weapon_2: { type: DataTypes.STRING }, + equipment: { + type: DataTypes.TEXT, + defaultValue: "{}", + get() { + const val = this.getDataValue("equipment"); + return val ? JSON.parse(val) : {}; + }, + set(val) { + this.setDataValue("equipment", JSON.stringify(val)); + }, + }, }); module.exports = Player; diff --git a/game-server/src/sockets/handlers/inventoryHandler.js b/game-server/src/sockets/handlers/inventoryHandler.js index 074ecea..1c4fc0f 100644 --- a/game-server/src/sockets/handlers/inventoryHandler.js +++ b/game-server/src/sockets/handlers/inventoryHandler.js @@ -6,31 +6,20 @@ module.exports = (io, socket) => { if (!userId) return; socket.on("player:get_inventory", async () => { - try { - const items = await inventoryManager.getInventory(userId); - socket.emit("player:inventory_data", items); - } catch (err) { - socket.emit("error", { message: "LOAD_INVENTORY_FAILED" }); - } + const items = await inventoryManager.getInventory(userId); + socket.emit("player:inventory_data", items); }); socket.on("player:get_equipment", async () => { - try { - const equipment = await inventoryManager.getEquipment(userId); - socket.emit("player:equipment_data", equipment); - } catch (err) { - console.error(err); - } + const equipment = await inventoryManager.getEquipment(userId); + socket.emit("player:equipment_data", equipment); }); socket.on("player:equip_item", async ({ itemId, slot }) => { try { const itemInfo = await inventoryManager.equipItem(userId, itemId, slot); - sessionManager.updateEquipment(socket.id, slot, itemId); - socket.emit("player:item_equipped", { slot, itemId }); - socket.broadcast.emit("player:visible_changed", { playerId: userId, slot, @@ -45,7 +34,6 @@ module.exports = (io, socket) => { try { await inventoryManager.unequipItem(userId, slot); sessionManager.updateEquipment(socket.id, slot, null); - socket.emit("player:item_unequipped", { slot }); socket.broadcast.emit("player:visible_changed", { playerId: userId, @@ -53,7 +41,7 @@ module.exports = (io, socket) => { texturePath: null, }); } catch (err) { - console.error(err); + socket.emit("error", { message: "UNEQUIP_FAILED" }); } }); };