From b7217ae613a2c4265a6f1b930df376602f71c7be Mon Sep 17 00:00:00 2001 From: AlphaX Date: Sat, 28 Dec 2024 18:55:20 +0100 Subject: [PATCH 1/8] Create /locker command --- DiscordBot/commands/User/locker.js | 219 +++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 DiscordBot/commands/User/locker.js diff --git a/DiscordBot/commands/User/locker.js b/DiscordBot/commands/User/locker.js new file mode 100644 index 0000000..174f4de --- /dev/null +++ b/DiscordBot/commands/User/locker.js @@ -0,0 +1,219 @@ +const { MessageAttachment } = require("discord.js"); +const { createCanvas, loadImage } = require("canvas"); +const axios = require("axios"); +const User = require("../../../model/user.js"); +const Profiles = require("../../../model/profiles.js"); +const fs = require("fs"); +const config = require("../../../Config/config.json"); + +module.exports = { + commandInfo: { + name: "locker", + description: "Displays specific items from your locker as an image.", + options: [ + { + name: "category", + description: "Select the category of items to display.", + type: 3, + required: true, + choices: [ + { name: "Skins", value: "skins" }, + { name: "Emotes", value: "emotes" }, + { name: "Pickaxes", value: "pickaxes" }, + { name: "Gliders", value: "gliders" }, + { name: "Loading Screens", value: "loading_screens" }, + ], + }, + ], + }, + + execute: async (interaction) => { + await interaction.deferReply({ ephemeral: true }); + + const user = await User.findOne({ discordId: interaction.user.id }).lean(); + if (!user) { + return interaction.editReply({ content: "You do not have a registered account!", ephemeral: true }); + } + + const profile = await Profiles.findOne({ accountId: user.accountId }); + if (!profile || !profile.profiles || !profile.profiles.athena) { + return interaction.editReply({ content: "No locker data found for your account.", ephemeral: true }); + } + + const category = interaction.options.getString("category"); + const items = profile.profiles.athena.items; + let filteredItems = []; + switch (category) { + case "skins": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaCharacter:")); + break; + case "emotes": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaDance:")); + break; + case "pickaxes": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaPickaxe:")); + break; + case "gliders": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaGlider:")); + break; + case "loading_screens": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaLoadingScreen:")); + break; + default: + return interaction.editReply({ content: "Invalid category selected.", ephemeral: true }); + } + + if (filteredItems.length === 0) { + return interaction.editReply({ content: `No items found in your locker for the ${category} category.`, ephemeral: true }); + } + let itemsData = []; + try { + const apiResponse = await axios.get("https://fortnite-api.com/v2/cosmetics/br"); + const allCosmetics = apiResponse.data.data; + + // bEnableLockerLimit false + if (!config.bEnableLockerLimit) { + itemsData = filteredItems.map(id => { + const itemId = id + .replace("AthenaCharacter:", "") + .replace("AthenaDance:", "") + .replace("AthenaPickaxe:", "") + .replace("AthenaGlider:", "") + .replace("AthenaLoadingScreen:", ""); + const cosmetic = allCosmetics.find(item => item.id === itemId || item.id.includes(itemId)); + if (cosmetic) { + const season = cosmetic.introduction && cosmetic.introduction.season ? cosmetic.introduction.season : null; + const chapter = cosmetic.introduction && cosmetic.introduction.chapter ? cosmetic.introduction.chapter : null; + + return { + id: itemId, + name: cosmetic.name, + image: cosmetic.images.icon, + season: season, + chapter: chapter + }; + } + return null; + }).filter(item => item !== null); + } else { + // bEnableLockerLimit true + itemsData = filteredItems.map(id => { + const itemId = id + .replace("AthenaCharacter:", "") + .replace("AthenaDance:", "") + .replace("AthenaPickaxe:", "") + .replace("AthenaGlider:", "") + .replace("AthenaLoadingScreen:", ""); + const cosmetic = allCosmetics.find(item => item.id === itemId || item.id.includes(itemId)); + if (cosmetic) { + const season = cosmetic.introduction && cosmetic.introduction.season ? cosmetic.introduction.season : null; + const chapter = cosmetic.introduction && cosmetic.introduction.chapter ? cosmetic.introduction.chapter : null; + + if (season !== null && chapter !== null) { + if (chapter <= config.bLimitChapter && season <= config.bLimitSeason) { + return { + id: itemId, + name: cosmetic.name, + image: cosmetic.images.icon, + season: season, + chapter: chapter + }; + } + } + } + return null; + }).filter(item => item !== null); + } + } catch (error) { + console.error("Error fetching cosmetics data from Fortnite API:", error); + return interaction.editReply({ content: "Failed to fetch item data from the Fortnite API.", ephemeral: true }); + } + if (itemsData.length === 0) { + return interaction.editReply({ content: `No matching items found for ${category} in the Fortnite API.`, ephemeral: true }); + } + + const itemSize = 150; + const padding = 20; + const itemsPerRow = 5; + const maxRowsPerPage = 6; + + const canvasWidth = itemsPerRow * (itemSize + padding) + padding; + const canvasHeight = maxRowsPerPage * (itemSize + padding) + 100; + + const totalPages = Math.ceil(itemsData.length / (itemsPerRow * maxRowsPerPage)); + const attachments = []; + + for (let page = 0; page < totalPages; page++) { + const canvas = createCanvas(canvasWidth, canvasHeight); + const ctx = canvas.getContext("2d"); + + const gradient = ctx.createLinearGradient(0, 0, canvasWidth, canvasHeight); + gradient.addColorStop(0, "#2C2F33"); + gradient.addColorStop(1, "#23272A"); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, canvasWidth, canvasHeight); + + const logoImage = await loadImage("https://i.imgur.com/2RImwlb.png"); + const logoSize = 50; + const logoX = 20; + + ctx.save(); + ctx.beginPath(); + ctx.arc(logoX + logoSize / 2, logoY + logoSize / 2, logoSize / 2, 0, Math.PI * 2, false); + ctx.closePath(); + ctx.clip(); + ctx.drawImage(logoImage, logoX, logoY, logoSize, logoSize); + ctx.restore(); + + ctx.fillStyle = "#FFFFFF"; + ctx.font = "40px Arial"; + ctx.fillText(`${user.username}'s Locker - Page ${page + 1}/${totalPages}`, 80, 50); + + let startIndex = page * itemsPerRow * maxRowsPerPage; + let endIndex = Math.min(startIndex + itemsPerRow * maxRowsPerPage, itemsData.length); + + let x = padding; + let y = 100; + for (let i = startIndex; i < endIndex; i++) { + const item = itemsData[i]; + + ctx.fillStyle = "#3A3F47"; + ctx.beginPath(); + ctx.moveTo(x + 10, y); + ctx.arcTo(x + itemSize, y, x + itemSize, y + itemSize, 10); + ctx.arcTo(x + itemSize, y + itemSize, x, y + itemSize, 10); + ctx.arcTo(x, y + itemSize, x, y, 10); + ctx.arcTo(x, y, x + itemSize, y, 10); + ctx.closePath(); + ctx.fill(); + + if (item.image) { + try { + const itemImage = await loadImage(item.image); + ctx.drawImage(itemImage, x + 10, y + 10, itemSize - 20, itemSize - 20); + } catch (err) { + console.error(`Error loading image for item ${item.name}:`, err); + } + } + + ctx.fillStyle = "#FFFFFF"; + ctx.font = "20px Arial"; + ctx.fillText(item.name, x + 10, y + itemSize + 20); + + x += itemSize + padding; + if (x + itemSize > canvasWidth) { + x = padding; + y += itemSize + padding + 40; + } + } + const attachment = new MessageAttachment(canvas.toBuffer(), `locker_page_${page + 1}.png`); + attachments.push(attachment); + } + + const chunkSize = 10; + for (let i = 0; i < attachments.length; i += chunkSize) { + const chunk = attachments.slice(i, i + chunkSize); + await interaction.followUp({ content: `Here are more pages of your ${category}:`, files: chunk, ephemeral: true }); + } + }, +}; \ No newline at end of file From 296a2cd6e6fe62aad7e87b34f8d91e69a800d2b5 Mon Sep 17 00:00:00 2001 From: AlphaX Date: Sat, 28 Dec 2024 19:14:12 +0100 Subject: [PATCH 2/8] Update config.json --- Config/config.json | 5 +++++ install_packages.bat | 1 + 2 files changed, 6 insertions(+) diff --git a/Config/config.json b/Config/config.json index 23d4af8..207f1d9 100644 --- a/Config/config.json +++ b/Config/config.json @@ -44,6 +44,11 @@ "bEnableBattlepass": false, "bBattlePassSeason": 2, + "//": "To set the item limit for the /locker command (not required)", + "bEnableLockerLimit": false, + "bLimitChapter": 1, + "bLimitSeason": 7, + "//": "If 'bUseAutoRotate' is enabled it will automatically rotate the item shop using the time you put in 'bRotateTime', you can select the season limit with 'bSeasonLimit' (please only do up to season 10, it might be a bit broken after!), 'bRotateTime' means what time the shop rotates (it is UTC and uses the 24 hour clock, not 12 hour), for 'bItemShopWebhook' you have to generate a webhook to your item shop channel and put the link here, you can select how many cosmetics are in daily: 'bDailyItemsAmount' and featured: 'bFeaturedItemsAmount'", "bUseAutoRotate": false, "bEnableAutoRotateDebugLogs": false, diff --git a/install_packages.bat b/install_packages.bat index 31bb727..5dcb15f 100644 --- a/install_packages.bat +++ b/install_packages.bat @@ -4,4 +4,5 @@ title Reload Backend Package Installer npm i npm install express npm install ws +npm install canvas pause \ No newline at end of file From cc68a232b720a1db554c728b0a5c7296f2054dde Mon Sep 17 00:00:00 2001 From: AlphaX Date: Sat, 28 Dec 2024 19:24:49 +0100 Subject: [PATCH 3/8] Fix small bug --- DiscordBot/commands/User/locker.js | 1 + 1 file changed, 1 insertion(+) diff --git a/DiscordBot/commands/User/locker.js b/DiscordBot/commands/User/locker.js index 174f4de..0c0eb6f 100644 --- a/DiscordBot/commands/User/locker.js +++ b/DiscordBot/commands/User/locker.js @@ -156,6 +156,7 @@ module.exports = { const logoImage = await loadImage("https://i.imgur.com/2RImwlb.png"); const logoSize = 50; const logoX = 20; + const logoY = 20; ctx.save(); ctx.beginPath(); From 05982d378428d388976e746fb508d65342ac5d7f Mon Sep 17 00:00:00 2001 From: AlphaX Date: Sat, 28 Dec 2024 23:05:11 +0100 Subject: [PATCH 4/8] Add other items --- DiscordBot/commands/User/locker.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/DiscordBot/commands/User/locker.js b/DiscordBot/commands/User/locker.js index 0c0eb6f..9c546d4 100644 --- a/DiscordBot/commands/User/locker.js +++ b/DiscordBot/commands/User/locker.js @@ -18,9 +18,12 @@ module.exports = { required: true, choices: [ { name: "Skins", value: "skins" }, + { name: "BackBlings", value: "backblings" }, { name: "Emotes", value: "emotes" }, { name: "Pickaxes", value: "pickaxes" }, { name: "Gliders", value: "gliders" }, + { name: "Warps", value: "warp" }, + { name: "SkyDiveContrail", value: "skydivecontrail" }, { name: "Loading Screens", value: "loading_screens" }, ], }, @@ -47,6 +50,12 @@ module.exports = { case "skins": filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaCharacter:")); break; + case "backblings": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaBackpack:")); + break; + case "emotes": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaDance:")); + break; case "emotes": filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaDance:")); break; @@ -56,6 +65,12 @@ module.exports = { case "gliders": filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaGlider:")); break; + case "warp": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaItemWrap:")); + break; + case "skydivecontrail": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaSkyDiveContrail:")); + break; case "loading_screens": filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaLoadingScreen:")); break; @@ -76,9 +91,12 @@ module.exports = { itemsData = filteredItems.map(id => { const itemId = id .replace("AthenaCharacter:", "") + .replace("AthenaBackpack:", "") .replace("AthenaDance:", "") .replace("AthenaPickaxe:", "") .replace("AthenaGlider:", "") + .replace("AthenaItemWrap:", "") + .replace("AthenaSkyDiveContrail:", "") .replace("AthenaLoadingScreen:", ""); const cosmetic = allCosmetics.find(item => item.id === itemId || item.id.includes(itemId)); if (cosmetic) { @@ -100,9 +118,12 @@ module.exports = { itemsData = filteredItems.map(id => { const itemId = id .replace("AthenaCharacter:", "") + .replace("AthenaBackpack:", "") .replace("AthenaDance:", "") .replace("AthenaPickaxe:", "") .replace("AthenaGlider:", "") + .replace("AthenaItemWrap:", "") + .replace("AthenaSkyDiveContrail:", "") .replace("AthenaLoadingScreen:", ""); const cosmetic = allCosmetics.find(item => item.id === itemId || item.id.includes(itemId)); if (cosmetic) { From 6e404c87ff27cccb0954a86dea3cd7f1fa385c5d Mon Sep 17 00:00:00 2001 From: AlphaX Date: Sun, 29 Dec 2024 21:23:06 +0100 Subject: [PATCH 5/8] Fix Emoji Image --- DiscordBot/commands/User/locker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordBot/commands/User/locker.js b/DiscordBot/commands/User/locker.js index 9c546d4..5a6df7f 100644 --- a/DiscordBot/commands/User/locker.js +++ b/DiscordBot/commands/User/locker.js @@ -106,7 +106,7 @@ module.exports = { return { id: itemId, name: cosmetic.name, - image: cosmetic.images.icon, + image: cosmetic.type.value === "emoji" && cosmetic.images.smallIcon ? cosmetic.images.smallIcon : cosmetic.images.icon, season: season, chapter: chapter }; @@ -135,7 +135,7 @@ module.exports = { return { id: itemId, name: cosmetic.name, - image: cosmetic.images.icon, + image: cosmetic.type.value === "emoji" && cosmetic.images.smallIcon ? cosmetic.images.smallIcon : cosmetic.images.icon, season: season, chapter: chapter }; From db2687e65878a0ddb657663bb48b3026a5917dc1 Mon Sep 17 00:00:00 2001 From: AlphaX Date: Mon, 30 Dec 2024 15:22:08 +0100 Subject: [PATCH 6/8] Add Music to /locker --- DiscordBot/commands/User/locker.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DiscordBot/commands/User/locker.js b/DiscordBot/commands/User/locker.js index 5a6df7f..42c79a6 100644 --- a/DiscordBot/commands/User/locker.js +++ b/DiscordBot/commands/User/locker.js @@ -24,6 +24,7 @@ module.exports = { { name: "Gliders", value: "gliders" }, { name: "Warps", value: "warp" }, { name: "SkyDiveContrail", value: "skydivecontrail" }, + { name: "Music", value: "music" }, { name: "Loading Screens", value: "loading_screens" }, ], }, @@ -71,6 +72,9 @@ module.exports = { case "skydivecontrail": filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaSkyDiveContrail:")); break; + case "music": + filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaMusicPack:")); + break; case "loading_screens": filteredItems = Object.keys(items).filter(id => id.startsWith("AthenaLoadingScreen:")); break; @@ -97,6 +101,7 @@ module.exports = { .replace("AthenaGlider:", "") .replace("AthenaItemWrap:", "") .replace("AthenaSkyDiveContrail:", "") + .replace("AthenaMusicPack:", "") .replace("AthenaLoadingScreen:", ""); const cosmetic = allCosmetics.find(item => item.id === itemId || item.id.includes(itemId)); if (cosmetic) { @@ -124,6 +129,7 @@ module.exports = { .replace("AthenaGlider:", "") .replace("AthenaItemWrap:", "") .replace("AthenaSkyDiveContrail:", "") + .replace("AthenaMusicPack:", "") .replace("AthenaLoadingScreen:", ""); const cosmetic = allCosmetics.find(item => item.id === itemId || item.id.includes(itemId)); if (cosmetic) { @@ -238,4 +244,4 @@ module.exports = { await interaction.followUp({ content: `Here are more pages of your ${category}:`, files: chunk, ephemeral: true }); } }, -}; \ No newline at end of file +}; From 7ab5d52ba133282304b4a8996122848bb23947fd Mon Sep 17 00:00:00 2001 From: AlphaX Date: Tue, 31 Dec 2024 15:53:00 +0100 Subject: [PATCH 7/8] Add /gift commands --- DiscordBot/commands/User/giftitem.js | 169 +++++++++++++++++++++++++++ routes/mcp.js | 2 +- structs/autorotate.js | 10 +- 3 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 DiscordBot/commands/User/giftitem.js diff --git a/DiscordBot/commands/User/giftitem.js b/DiscordBot/commands/User/giftitem.js new file mode 100644 index 0000000..1db923d --- /dev/null +++ b/DiscordBot/commands/User/giftitem.js @@ -0,0 +1,169 @@ +const axios = require('axios'); +const Users = require('../../../model/user.js'); +const Profiles = require('../../../model/profiles.js'); +const fs = require('fs'); +const path = require('path'); +const destr = require('destr'); +const config = require('../../../Config/config.json'); +const uuid = require("uuid"); +const { MessageEmbed } = require('discord.js'); + +module.exports = { + commandInfo: { + name: "additem", + description: "Allows you to gift a daily shop item to a user.", + options: [ + { + name: "user", + description: "The user you want to gift the cosmetic to", + required: true, + type: 6 + }, + { + name: "item", + description: "The name or ID of the daily shop item you want to gift", + required: true, + type: 3 + }, + { + name: "message", + description: "Custom message to include with the gift", + required: false, + type: 3 + } + ] + }, + execute: async (interaction) => { + await interaction.deferReply({ ephemeral: true }); + + const selectedUser = interaction.options.getUser('user'); + const selectedUserId = selectedUser.id; + const user = await Users.findOne({ discordId: selectedUserId }); + + if (!user) { + return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); + } + + const profile = await Profiles.findOne({ accountId: user.accountId }); + if (!profile || !profile.profiles) { + return interaction.editReply({ content: "Could not find the recipient's profile.", ephemeral: true }); + } + + const cosmeticNameOrId = interaction.options.getString('item'); + const customMessage = interaction.options.getString('message') || `Thanks for using Project Reload!`; + + try { + async function fetchCosmeticData(nameOrId) { + try { + const response = await axios.get(`https://fortnite-api.com/v2/cosmetics/br/search?name=${encodeURIComponent(nameOrId)}`); + return response.data?.data || null; + } catch (error) { + console.error("Erreur lors de la récupération des données cosmétiques :", error.message); + return null; + } + } + + const catalogPath = path.join(__dirname, "../../../Config/catalog_config.json"); + const catalog = JSON.parse(fs.readFileSync(catalogPath, "utf8")); + + let foundItem = null; + let itemPrice = 0; + let cosmeticImage = null; + + for (const [sectionName, section] of Object.entries(catalog)) { + if (!section.itemGrants || !Array.isArray(section.itemGrants)) continue; + + const itemNameMatch = section.name?.toLowerCase() === cosmeticNameOrId.toLowerCase(); + const itemIdMatch = section.itemGrants?.some(grant => grant?.toLowerCase() === cosmeticNameOrId.toLowerCase()); + + if (itemNameMatch || itemIdMatch) { + foundItem = section.itemGrants[0]; + itemPrice = section.price; + const cosmeticData = await fetchCosmeticData(section.name || cosmeticNameOrId); + cosmeticImage = cosmeticData?.images?.smallIcon || null; + break; + } + } + + if (!foundItem) { + return interaction.editReply({ content: "The specified item is not available in the daily shop.", ephemeral: true }); + } + + const sender = await Users.findOne({ discordId: interaction.user.id }); + const senderProfile = await Profiles.findOne({ accountId: sender.accountId }); + if (!senderProfile || !senderProfile.profiles) { + return interaction.editReply({ content: "Could not find your profile.", ephemeral: true }); + } + + const senderVbucks = senderProfile.profiles.common_core.items["Currency:MtxPurchased"]?.quantity || 0; + if (senderVbucks < itemPrice) { + return interaction.editReply({ content: "You do not have enough V-Bucks to gift this item.", ephemeral: true }); + } + + if (profile.profiles.athena.items[foundItem]) { + return interaction.editReply({ content: "The user already owns this item.", ephemeral: true }); + } + + await Profiles.findOneAndUpdate( + { accountId: sender.accountId }, + { $inc: { 'profiles.common_core.items.Currency:MtxPurchased.quantity': -itemPrice } } + ); + + const purchaseId = uuid.v4(); + const lootList = [{ + "itemType": foundItem, + "itemGuid": foundItem, + "quantity": 1 + }]; + + const common_core = profile.profiles["common_core"]; + const athena = profile.profiles["athena"]; + + common_core.items[purchaseId] = { + "templateId": `GiftBox:GB_MakeGood`, + "attributes": { + "fromAccountId": interaction.user.username, + "lootList": lootList, + "params": { "userMessage": customMessage }, + "giftedOn": new Date().toISOString() + }, + "quantity": 1 + }; + + athena.items[foundItem] = { + "templateId": foundItem, + "attributes": {}, + "quantity": 1 + }; + + await Profiles.updateOne( + { accountId: user.accountId }, + { + $set: { + 'profiles.common_core': common_core, + 'profiles.athena': athena + } + } + ); + + const embed = new MessageEmbed() + .setTitle("Gift Sent!") + .setDescription(`**${cosmeticNameOrId}** has been gifted to ${selectedUser} for **${itemPrice} V-Bucks**.`) + .setThumbnail(cosmeticImage || 'https://via.placeholder.com/512') + embed.addFields( + { name: 'Message:', value: customMessage, inline: true } + ) + .setColor("BLUE") + .setFooter({ + text: "Reload Backend", + iconURL: "https://i.imgur.com/2RImwlb.png" + }) + .setTimestamp(); + + return interaction.editReply({ embeds: [embed], ephemeral: true }); + } catch (error) { + console.error("Error executing additem command:", error); + return interaction.editReply({ content: "An unexpected error occurred.", ephemeral: true }); + } + } +}; \ No newline at end of file diff --git a/routes/mcp.js b/routes/mcp.js index 0109ab7..f9d7e60 100644 --- a/routes/mcp.js +++ b/routes/mcp.js @@ -141,7 +141,7 @@ app.post("/fortnite/api/game/v2/profile/*/client/ClientQuestLogin", verifyToken, } for (var key in profile.items) { - if (profile.items[key].templateId.toLowerCase().startsWith("quest:athenadaily")) { + if (profile.items[key]?.templateId?.toLowerCase().startsWith("quest:athenadaily")) { QuestCount += 1; } } diff --git a/structs/autorotate.js b/structs/autorotate.js index 2efb0fe..81d1a16 100644 --- a/structs/autorotate.js +++ b/structs/autorotate.js @@ -329,6 +329,7 @@ function updatecfgomg(dailyItems, featuredItems) { dailyItems.forEach((item, index) => { catalogConfig[`daily${index + 1}`] = { itemGrants: formatitemgrantsyk(item), + name: item.name || "Unknown Name", price: notproperpricegen(item) }; }); @@ -336,12 +337,17 @@ function updatecfgomg(dailyItems, featuredItems) { featuredItems.forEach((item, index) => { catalogConfig[`featured${index + 1}`] = { itemGrants: formatitemgrantsyk(item), + name: item.name || "Unknown Name", price: notproperpricegen(item) }; }); - fs.writeFileSync(catalogcfg, JSON.stringify(catalogConfig, null, 2), 'utf-8'); - log.AutoRotation("The item shop has rotated!"); + try { + fs.writeFileSync(catalogcfg, JSON.stringify(catalogConfig, null, 2), 'utf-8'); + log.AutoRotation("The item shop has rotated!"); + } catch (error) { + log.error("Failed to save catalog config file:", error.message || error); + } } async function fetchItemIcon(itemName) { From fbb33a0f851f00a56de5ef2c467f907880407d5a Mon Sep 17 00:00:00 2001 From: AlphaX50 Date: Tue, 31 Dec 2024 18:12:49 +0100 Subject: [PATCH 8/8] Error from me --- DiscordBot/commands/User/giftitem.js | 169 --------------------------- 1 file changed, 169 deletions(-) delete mode 100644 DiscordBot/commands/User/giftitem.js diff --git a/DiscordBot/commands/User/giftitem.js b/DiscordBot/commands/User/giftitem.js deleted file mode 100644 index 1db923d..0000000 --- a/DiscordBot/commands/User/giftitem.js +++ /dev/null @@ -1,169 +0,0 @@ -const axios = require('axios'); -const Users = require('../../../model/user.js'); -const Profiles = require('../../../model/profiles.js'); -const fs = require('fs'); -const path = require('path'); -const destr = require('destr'); -const config = require('../../../Config/config.json'); -const uuid = require("uuid"); -const { MessageEmbed } = require('discord.js'); - -module.exports = { - commandInfo: { - name: "additem", - description: "Allows you to gift a daily shop item to a user.", - options: [ - { - name: "user", - description: "The user you want to gift the cosmetic to", - required: true, - type: 6 - }, - { - name: "item", - description: "The name or ID of the daily shop item you want to gift", - required: true, - type: 3 - }, - { - name: "message", - description: "Custom message to include with the gift", - required: false, - type: 3 - } - ] - }, - execute: async (interaction) => { - await interaction.deferReply({ ephemeral: true }); - - const selectedUser = interaction.options.getUser('user'); - const selectedUserId = selectedUser.id; - const user = await Users.findOne({ discordId: selectedUserId }); - - if (!user) { - return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); - } - - const profile = await Profiles.findOne({ accountId: user.accountId }); - if (!profile || !profile.profiles) { - return interaction.editReply({ content: "Could not find the recipient's profile.", ephemeral: true }); - } - - const cosmeticNameOrId = interaction.options.getString('item'); - const customMessage = interaction.options.getString('message') || `Thanks for using Project Reload!`; - - try { - async function fetchCosmeticData(nameOrId) { - try { - const response = await axios.get(`https://fortnite-api.com/v2/cosmetics/br/search?name=${encodeURIComponent(nameOrId)}`); - return response.data?.data || null; - } catch (error) { - console.error("Erreur lors de la récupération des données cosmétiques :", error.message); - return null; - } - } - - const catalogPath = path.join(__dirname, "../../../Config/catalog_config.json"); - const catalog = JSON.parse(fs.readFileSync(catalogPath, "utf8")); - - let foundItem = null; - let itemPrice = 0; - let cosmeticImage = null; - - for (const [sectionName, section] of Object.entries(catalog)) { - if (!section.itemGrants || !Array.isArray(section.itemGrants)) continue; - - const itemNameMatch = section.name?.toLowerCase() === cosmeticNameOrId.toLowerCase(); - const itemIdMatch = section.itemGrants?.some(grant => grant?.toLowerCase() === cosmeticNameOrId.toLowerCase()); - - if (itemNameMatch || itemIdMatch) { - foundItem = section.itemGrants[0]; - itemPrice = section.price; - const cosmeticData = await fetchCosmeticData(section.name || cosmeticNameOrId); - cosmeticImage = cosmeticData?.images?.smallIcon || null; - break; - } - } - - if (!foundItem) { - return interaction.editReply({ content: "The specified item is not available in the daily shop.", ephemeral: true }); - } - - const sender = await Users.findOne({ discordId: interaction.user.id }); - const senderProfile = await Profiles.findOne({ accountId: sender.accountId }); - if (!senderProfile || !senderProfile.profiles) { - return interaction.editReply({ content: "Could not find your profile.", ephemeral: true }); - } - - const senderVbucks = senderProfile.profiles.common_core.items["Currency:MtxPurchased"]?.quantity || 0; - if (senderVbucks < itemPrice) { - return interaction.editReply({ content: "You do not have enough V-Bucks to gift this item.", ephemeral: true }); - } - - if (profile.profiles.athena.items[foundItem]) { - return interaction.editReply({ content: "The user already owns this item.", ephemeral: true }); - } - - await Profiles.findOneAndUpdate( - { accountId: sender.accountId }, - { $inc: { 'profiles.common_core.items.Currency:MtxPurchased.quantity': -itemPrice } } - ); - - const purchaseId = uuid.v4(); - const lootList = [{ - "itemType": foundItem, - "itemGuid": foundItem, - "quantity": 1 - }]; - - const common_core = profile.profiles["common_core"]; - const athena = profile.profiles["athena"]; - - common_core.items[purchaseId] = { - "templateId": `GiftBox:GB_MakeGood`, - "attributes": { - "fromAccountId": interaction.user.username, - "lootList": lootList, - "params": { "userMessage": customMessage }, - "giftedOn": new Date().toISOString() - }, - "quantity": 1 - }; - - athena.items[foundItem] = { - "templateId": foundItem, - "attributes": {}, - "quantity": 1 - }; - - await Profiles.updateOne( - { accountId: user.accountId }, - { - $set: { - 'profiles.common_core': common_core, - 'profiles.athena': athena - } - } - ); - - const embed = new MessageEmbed() - .setTitle("Gift Sent!") - .setDescription(`**${cosmeticNameOrId}** has been gifted to ${selectedUser} for **${itemPrice} V-Bucks**.`) - .setThumbnail(cosmeticImage || 'https://via.placeholder.com/512') - embed.addFields( - { name: 'Message:', value: customMessage, inline: true } - ) - .setColor("BLUE") - .setFooter({ - text: "Reload Backend", - iconURL: "https://i.imgur.com/2RImwlb.png" - }) - .setTimestamp(); - - return interaction.editReply({ embeds: [embed], ephemeral: true }); - } catch (error) { - console.error("Error executing additem command:", error); - return interaction.editReply({ content: "An unexpected error occurred.", ephemeral: true }); - } - } -}; \ No newline at end of file