added inventory manager and .env for the client
This commit is contained in:
parent
7302a54cd7
commit
42ae328b56
@ -4,7 +4,7 @@ import axios from "axios";
|
|||||||
export const AuthContext = createContext();
|
export const AuthContext = createContext();
|
||||||
|
|
||||||
export const AuthProvider = ({ children }) => {
|
export const AuthProvider = ({ children }) => {
|
||||||
const API_URL = "http://localhost:3000/api/auth";
|
const API_URL = `${import.meta.env.API_URL}/api/auth`;
|
||||||
|
|
||||||
const [user, setUser] = useState(() => {
|
const [user, setUser] = useState(() => {
|
||||||
const savedUser = localStorage.getItem("user");
|
const savedUser = localStorage.getItem("user");
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useSocket } from "../../../hooks/useSocket";
|
|||||||
import GameDataManager from "../../../services/GameDataManager.js";
|
import GameDataManager from "../../../services/GameDataManager.js";
|
||||||
import Button from "../../../components/ui/Button";
|
import Button from "../../../components/ui/Button";
|
||||||
import "./styles/InventoryTab.css";
|
import "./styles/InventoryTab.css";
|
||||||
|
import { getServerUrl } from "../../../config/api.js";
|
||||||
|
|
||||||
const InventoryTab = () => {
|
const InventoryTab = () => {
|
||||||
const { socket } = useSocket();
|
const { socket } = useSocket();
|
||||||
@ -10,19 +11,24 @@ const InventoryTab = () => {
|
|||||||
const [equipment, setEquipment] = useState({});
|
const [equipment, setEquipment] = useState({});
|
||||||
const [selectedItem, setSelectedItem] = useState(null);
|
const [selectedItem, setSelectedItem] = useState(null);
|
||||||
const [showModal, setShowModal] = useState(false);
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const CONNECT_URL = getServerUrl();
|
||||||
|
const ASSET_BASE_URL = `${CONNECT_URL}/static/`;
|
||||||
|
|
||||||
const ASSET_BASE_URL = "http://localhost:5003/static/";
|
const equipmentSlots = {
|
||||||
|
personal: [
|
||||||
const slots = [
|
{ id: "personal_helmet", label: "HELMET" },
|
||||||
"helmet",
|
{ id: "personal_suit", label: "SUIT" },
|
||||||
"armor",
|
{ id: "personal_gloves", label: "GLOVES" },
|
||||||
"weapon",
|
{ id: "personal_boots", label: "BOOTS" },
|
||||||
"pants",
|
{ id: "personal_backpack", label: "BACKPACK" },
|
||||||
"boots",
|
{ id: "personal_weapons", label: "WEAPON" },
|
||||||
"hands",
|
],
|
||||||
"accessory",
|
ship: [
|
||||||
"shipHull",
|
{ id: "ship_hull", label: "HULL" },
|
||||||
];
|
{ id: "ship_shields", label: "SHIELDS" },
|
||||||
|
{ id: "ship_engines", label: "ENGINES" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
const getFullTextureUrl = (path) => {
|
const getFullTextureUrl = (path) => {
|
||||||
if (!path) return "/assets/no-image.png";
|
if (!path) return "/assets/no-image.png";
|
||||||
@ -95,6 +101,36 @@ const InventoryTab = () => {
|
|||||||
socket.emit("player:unequip_item", { slot });
|
socket.emit("player:unequip_item", { slot });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderSlotGroup = (title, groupSlots) => (
|
||||||
|
<div className="equip-group">
|
||||||
|
<div className="group-label">{title}</div>
|
||||||
|
<div className="equip-list-compact">
|
||||||
|
{groupSlots.map((slot) => (
|
||||||
|
<div
|
||||||
|
key={slot.id}
|
||||||
|
className={`equip-row-mini ${equipment[slot.id] ? "occupied" : ""}`}
|
||||||
|
onClick={() => equipment[slot.id] && unequipItem(slot.id)}
|
||||||
|
>
|
||||||
|
<span className="slot-name-tiny">{slot.label}</span>
|
||||||
|
<div
|
||||||
|
className={`equip-box-mini ${equipment[slot.id]?.rarity || ""}`}
|
||||||
|
>
|
||||||
|
{equipment[slot.id] ? (
|
||||||
|
<img
|
||||||
|
src={equipment[slot.id].textureUrl}
|
||||||
|
alt={slot.id}
|
||||||
|
className="item-img-mini"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span className="plus">+</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inv-adaptive-container">
|
<div className="inv-adaptive-container">
|
||||||
<div className="inv-header-compact">
|
<div className="inv-header-compact">
|
||||||
@ -109,30 +145,9 @@ const InventoryTab = () => {
|
|||||||
<div className="inv-layout-wrapper">
|
<div className="inv-layout-wrapper">
|
||||||
<section className="inv-panel loadout">
|
<section className="inv-panel loadout">
|
||||||
<div className="panel-label">CORE_SYSTEMS</div>
|
<div className="panel-label">CORE_SYSTEMS</div>
|
||||||
<div className="equip-list-compact">
|
|
||||||
{slots.map((slot) => (
|
{renderSlotGroup("PERSON", equipmentSlots.personal)}
|
||||||
<div
|
{renderSlotGroup("SHIP", equipmentSlots.ship)}
|
||||||
key={slot}
|
|
||||||
className={`equip-row-mini ${equipment[slot] ? "occupied" : ""}`}
|
|
||||||
onClick={() => equipment[slot] && unequipItem(slot)}
|
|
||||||
>
|
|
||||||
<span className="slot-name-tiny">{slot.toUpperCase()}</span>
|
|
||||||
<div
|
|
||||||
className={`equip-box-mini ${equipment[slot]?.rarity || ""}`}
|
|
||||||
>
|
|
||||||
{equipment[slot] ? (
|
|
||||||
<img
|
|
||||||
src={equipment[slot].textureUrl}
|
|
||||||
alt={slot}
|
|
||||||
className="item-img-mini"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span className="plus">+</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="inv-panel cargo">
|
<section className="inv-panel cargo">
|
||||||
@ -179,7 +194,8 @@ const InventoryTab = () => {
|
|||||||
Object.entries(selectedItem.stats).map(([k, v]) => (
|
Object.entries(selectedItem.stats).map(([k, v]) => (
|
||||||
<div key={k} className="stat-line">
|
<div key={k} className="stat-line">
|
||||||
<span className="label">
|
<span className="label">
|
||||||
{GameDataManager.getStatName(k).toUpperCase()}
|
{GameDataManager.getStatName?.(k)?.toUpperCase() ||
|
||||||
|
k.toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
<span className="value">+{v}</span>
|
<span className="value">+{v}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,39 +1,72 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import './ItemModal.css';
|
import "./ItemModal.css";
|
||||||
|
|
||||||
const ItemModal = ({ item, onClose, onEquip, getStatIcon, formatStatName }) => {
|
const ItemModal = ({
|
||||||
|
item,
|
||||||
|
onClose,
|
||||||
|
onEquip,
|
||||||
|
onUnequip,
|
||||||
|
isEquipped,
|
||||||
|
getStatIcon,
|
||||||
|
formatStatName,
|
||||||
|
}) => {
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="modal-overlay" onClick={onClose}>
|
<div className="modal-overlay" onClick={onClose}>
|
||||||
<div className="modal-content" onClick={e => e.stopPropagation()}>
|
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
|
||||||
<button className="modal-close" onClick={onClose}>×</button>
|
<button className="modal-close" onClick={onClose}>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
|
||||||
<div className="details-view">
|
<div className="details-view">
|
||||||
<div className="details-header">
|
<div className="details-header">
|
||||||
<h4 className={`item-name ${item.rarity}`}>{item.name}</h4>
|
<h4 className={`item-name ${item.rarity}`}>
|
||||||
|
{item.displayName || item.name}
|
||||||
|
</h4>
|
||||||
<span className={`rarity-badge ${item.rarity}`}>{item.rarity}</span>
|
<span className={`rarity-badge ${item.rarity}`}>{item.rarity}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="item-description">{item.description}</p>
|
<p className="item-description">{item.description}</p>
|
||||||
|
|
||||||
<div className="item-stats-container">
|
<div className="item-stats-container">
|
||||||
<div className="stat-row quality-row">
|
{item.stats &&
|
||||||
<span className="stat-label"><i className="fas fa-medal"></i> Quality</span>
|
Object.entries(item.stats).map(([statName, value]) => (
|
||||||
<span className={`stat-value ${item.rarity}`}>{item.rarity.toUpperCase()}</span>
|
<div key={statName} className="stat-row">
|
||||||
</div>
|
<span className="stat-label">
|
||||||
{item.stats && <div className="stat-divider"></div>}
|
<i className={getStatIcon?.(statName)}></i>{" "}
|
||||||
{item.stats && Object.entries(item.stats).map(([statName, value]) => (
|
{formatStatName
|
||||||
<div key={statName} className="stat-row">
|
? formatStatName(statName)
|
||||||
<span className="stat-label"><i className={getStatIcon(statName)}></i> {formatStatName(statName)}</span>
|
: statName.toUpperCase()}
|
||||||
<span className="stat-value">+{value}</span>
|
</span>
|
||||||
</div>
|
<span className="stat-value">+{value}</span>
|
||||||
))}
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button className="btn-equip" onClick={() => { onEquip(item); onClose(); }}>
|
{isEquipped ? (
|
||||||
Equip System
|
<button
|
||||||
</button>
|
className="btn-equip unequip"
|
||||||
|
onClick={() => {
|
||||||
|
onUnequip(item.currentSlot);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
DISCONNECT_SYSTEM
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
item.canEquip && (
|
||||||
|
<button
|
||||||
|
className="btn-equip"
|
||||||
|
onClick={() => {
|
||||||
|
onEquip(item);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
INITIALIZE_EQUIP
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,18 +7,17 @@ const ServerSection = ({ onBack, onSelect }) => {
|
|||||||
const [servers, setServers] = useState([]);
|
const [servers, setServers] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [joiningId, setJoiningId] = useState(null);
|
const [joiningId, setJoiningId] = useState(null);
|
||||||
const [searchTerm, setSearchTerm] = useState(""); // Стан для пошуку
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
|
||||||
const fetchServers = async () => {
|
const fetchServers = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const API_URL = import.meta.env.API_URL;
|
||||||
"http://localhost:3000/api/servers/list",
|
const response = await axios.get(`${API_URL}/api/servers/list`);
|
||||||
);
|
|
||||||
|
|
||||||
const elapsedTime = Date.now() - startTime;
|
const elapsedTime = Date.now() - startTime;
|
||||||
const remainingTime = Math.max(0, 2000 - elapsedTime); // Трохи зменшив штучну затримку
|
const remainingTime = Math.max(0, 2000 - elapsedTime);
|
||||||
await new Promise((resolve) => setTimeout(resolve, remainingTime));
|
await new Promise((resolve) => setTimeout(resolve, remainingTime));
|
||||||
|
|
||||||
setServers(response.data);
|
setServers(response.data);
|
||||||
@ -59,7 +58,6 @@ const ServerSection = ({ onBack, onSelect }) => {
|
|||||||
fetchServers();
|
fetchServers();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Фільтрація серверів на основі searchTerm
|
|
||||||
const filteredServers = servers.filter((server) =>
|
const filteredServers = servers.filter((server) =>
|
||||||
searchTerm.length > 0
|
searchTerm.length > 0
|
||||||
? server.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
? server.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
|||||||
59
game-server/src/game/InventoryManager.js
Normal file
59
game-server/src/game/InventoryManager.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const { Player, Inventory } = require("../models");
|
||||||
|
const DatapackLoader = require("./DatapackLoader");
|
||||||
|
|
||||||
|
class InventoryManager {
|
||||||
|
async getInventory(playerId) {
|
||||||
|
return await Inventory.findAll({
|
||||||
|
where: { playerId },
|
||||||
|
attributes: ["itemId", "quantity"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
async equipItem(playerId, itemId, slot) {
|
||||||
|
const hasItem = await Inventory.findOne({ where: { playerId, itemId } });
|
||||||
|
if (!hasItem) throw new Error("ITEM_NOT_FOUND");
|
||||||
|
|
||||||
|
const itemInfo = DatapackLoader.getItem(itemId);
|
||||||
|
if (!itemInfo) throw new Error("INVALID_ITEM_DATA");
|
||||||
|
|
||||||
|
const allowedSlot = itemInfo.meta?.equipmentSlot;
|
||||||
|
if (allowedSlot !== slot) {
|
||||||
|
throw new Error("INVALID_SLOT_FOR_ITEM");
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbField = `equipped_${slot}`.replace("original:", "");
|
||||||
|
await Player.update({ [dbField]: itemId }, { where: { id: playerId } });
|
||||||
|
return itemInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
async unequipItem(playerId, slot) {
|
||||||
|
const dbField = `equipped_${slot}`;
|
||||||
|
await Player.update({ [dbField]: null }, { where: { id: playerId } });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new InventoryManager();
|
||||||
@ -16,19 +16,31 @@ class SessionManager {
|
|||||||
sceneData: null,
|
sceneData: null,
|
||||||
joinedAt: Date.now(),
|
joinedAt: Date.now(),
|
||||||
equipment: {
|
equipment: {
|
||||||
weapon: playerRaw.equippedWeapon,
|
personal_helmet: playerRaw.equipped_personal_helmet,
|
||||||
armor: playerRaw.equippedArmor,
|
personal_suit: playerRaw.equipped_personal_suit,
|
||||||
engine: playerRaw.equippedEngine,
|
personal_gloves: playerRaw.equipped_personal_gloves,
|
||||||
shield: playerRaw.equippedShield,
|
personal_backpack: playerRaw.equipped_personal_backpack,
|
||||||
helmet: playerRaw.equippedHelmet,
|
personal_boots: playerRaw.equipped_personal_boots,
|
||||||
boots: playerRaw.equippedBoots,
|
personal_weapons: playerRaw.equipped_personal_weapons,
|
||||||
hands: playerRaw.equippedHands,
|
|
||||||
pants: playerRaw.equippedPants,
|
ship_hull: playerRaw.equipped_ship_hull,
|
||||||
accessory: playerRaw.equippedAccessory,
|
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,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setPlayerScene(socketId, sceneName, data = null) {
|
setPlayerScene(socketId, sceneName, data = null) {
|
||||||
const session = this.sessions.get(socketId);
|
const session = this.sessions.get(socketId);
|
||||||
if (session) {
|
if (session) {
|
||||||
@ -43,13 +55,6 @@ class SessionManager {
|
|||||||
return this.sessions.get(socketId);
|
return this.sessions.get(socketId);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEquipment(socketId, slot, itemId) {
|
|
||||||
const session = this.sessions.get(socketId);
|
|
||||||
if (session) {
|
|
||||||
session.equipment[slot] = itemId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatus(socketId, newStatus, location = null) {
|
updateStatus(socketId, newStatus, location = null) {
|
||||||
const session = this.sessions.get(socketId);
|
const session = this.sessions.get(socketId);
|
||||||
if (session) {
|
if (session) {
|
||||||
|
|||||||
@ -42,14 +42,22 @@ const Player = sequelize.define("Player", {
|
|||||||
type: DataTypes.DATE,
|
type: DataTypes.DATE,
|
||||||
defaultValue: DataTypes.NOW,
|
defaultValue: DataTypes.NOW,
|
||||||
},
|
},
|
||||||
equippedWeapon: { type: DataTypes.STRING },
|
|
||||||
equippedArmor: { type: DataTypes.STRING },
|
equipped_personal_helmet: { type: DataTypes.STRING },
|
||||||
equippedEngine: { type: DataTypes.STRING },
|
equipped_personal_suit: { type: DataTypes.STRING },
|
||||||
equippedAccessory: { type: DataTypes.STRING },
|
equipped_personal_gloves: { type: DataTypes.STRING },
|
||||||
equippedHelmet: { type: DataTypes.STRING },
|
equipped_personal_backpack: { type: DataTypes.STRING },
|
||||||
equippedBoots: { type: DataTypes.STRING },
|
equipped_personal_boots: { type: DataTypes.STRING },
|
||||||
equippedHands: { type: DataTypes.STRING },
|
equipped_personal_weapons: { type: DataTypes.STRING },
|
||||||
equippedPants: { 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 },
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = Player;
|
module.exports = Player;
|
||||||
|
|||||||
@ -1,82 +1,35 @@
|
|||||||
const { Player, Inventory } = require("../../models");
|
const inventoryManager = require("../../game/InventoryManager");
|
||||||
const sessionManager = require("../../game/SessionManager");
|
const sessionManager = require("../../game/SessionManager");
|
||||||
|
|
||||||
module.exports = (io, socket) => {
|
module.exports = (io, socket) => {
|
||||||
const userId = socket.user?.id;
|
const userId = socket.user?.id;
|
||||||
|
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
socket.on("player:get_inventory", async () => {
|
socket.on("player:get_inventory", async () => {
|
||||||
try {
|
try {
|
||||||
const userItems = await Inventory.findAll({
|
const items = await inventoryManager.getInventory(userId);
|
||||||
where: { playerId: userId },
|
socket.emit("player:inventory_data", items);
|
||||||
attributes: ["itemId", "quantity"],
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit("player:inventory_data", userItems);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Inventory Fetch Error:", err.message);
|
socket.emit("error", { message: "LOAD_INVENTORY_FAILED" });
|
||||||
socket.emit("error", { message: "Failed to load inventory" });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("player:get_equipment", async () => {
|
socket.on("player:get_equipment", async () => {
|
||||||
try {
|
try {
|
||||||
const player = await Player.findByPk(userId);
|
const equipment = await inventoryManager.getEquipment(userId);
|
||||||
if (!player) return;
|
|
||||||
|
|
||||||
const slots = [
|
|
||||||
"Weapon",
|
|
||||||
"Armor",
|
|
||||||
"Helmet",
|
|
||||||
"Boots",
|
|
||||||
"Hands",
|
|
||||||
"Pants",
|
|
||||||
"Engine",
|
|
||||||
"Accessory",
|
|
||||||
];
|
|
||||||
const equipment = {};
|
|
||||||
|
|
||||||
slots.forEach((slot) => {
|
|
||||||
const itemId = player[`equipped${slot}`];
|
|
||||||
equipment[slot.toLowerCase()] = itemId || null;
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit("player:equipment_data", equipment);
|
socket.emit("player:equipment_data", equipment);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Equipment Fetch Error:", err.message);
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("player:equip_item", async ({ itemId, slot }) => {
|
socket.on("player:equip_item", async ({ itemId, slot }) => {
|
||||||
try {
|
try {
|
||||||
const hasItem = await Inventory.findOne({
|
const itemInfo = await inventoryManager.equipItem(userId, itemId, slot);
|
||||||
where: { playerId: userId, itemId: itemId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!hasItem) {
|
|
||||||
return socket.emit("error", { message: "You don't own this item" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const DatapackLoader = require("../../game/DatapackLoader");
|
|
||||||
const itemInfo = DatapackLoader.getItem(itemId);
|
|
||||||
if (!itemInfo) return;
|
|
||||||
|
|
||||||
if (slot === "weapon" && itemInfo.type !== "weapon")
|
|
||||||
return socket.emit("error", { message: "Not a weapon" });
|
|
||||||
if (
|
|
||||||
["helmet", "armor", "boots", "pants", "hands"].includes(slot) &&
|
|
||||||
itemInfo.type !== "armour"
|
|
||||||
) {
|
|
||||||
return socket.emit("error", { message: "Not armor" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const slotField = `equipped${slot.charAt(0).toUpperCase() + slot.slice(1)}`;
|
|
||||||
await Player.update({ [slotField]: itemId }, { where: { id: userId } });
|
|
||||||
|
|
||||||
sessionManager.updateEquipment(socket.id, slot, itemId);
|
sessionManager.updateEquipment(socket.id, slot, itemId);
|
||||||
|
|
||||||
socket.emit("player:item_equipped", { slot, itemId: itemId });
|
socket.emit("player:item_equipped", { slot, itemId });
|
||||||
|
|
||||||
socket.broadcast.emit("player:visible_changed", {
|
socket.broadcast.emit("player:visible_changed", {
|
||||||
playerId: userId,
|
playerId: userId,
|
||||||
@ -84,21 +37,23 @@ module.exports = (io, socket) => {
|
|||||||
texturePath: itemInfo.texture,
|
texturePath: itemInfo.texture,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Equip Error:", err.message);
|
socket.emit("error", { message: err.message });
|
||||||
socket.emit("error", { message: "Equip failed" });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("player:unequip_item", async ({ slot }) => {
|
socket.on("player:unequip_item", async ({ slot }) => {
|
||||||
try {
|
try {
|
||||||
const slotField = `equipped${slot.charAt(0).toUpperCase() + slot.slice(1)}`;
|
await inventoryManager.unequipItem(userId, slot);
|
||||||
await Player.update({ [slotField]: null }, { where: { id: userId } });
|
|
||||||
|
|
||||||
sessionManager.updateEquipment(socket.id, slot, null);
|
sessionManager.updateEquipment(socket.id, slot, null);
|
||||||
|
|
||||||
socket.emit("player:item_unequipped", { slot });
|
socket.emit("player:item_unequipped", { slot });
|
||||||
|
socket.broadcast.emit("player:visible_changed", {
|
||||||
|
playerId: userId,
|
||||||
|
slot,
|
||||||
|
texturePath: null,
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Unequip Error:", err.message);
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user