QBCore = exports[Config.qbPrefix.."-core"]:GetCoreObject() Webhook = '' function getMoney(type, xPlayer) local moneyCount = 0 if type == "cash" then moneyCount = xPlayer.PlayerData.money.cash else moneyCount = xPlayer.PlayerData.money.bank end return moneyCount end function addMoney(type, value, xPlayer) xPlayer.Functions.AddMoney(type, value) end function removeMoney(type, value, xPlayer) xPlayer.Functions.RemoveMoney(type, value) end function addItem(xPlayer, item, amount, data) xPlayer.Functions.AddItem(item, tonumber(amount)) end function removeItem(xPlayer, item, amount) xPlayer.Functions.RemoveItem(item, tonumber(amount)) end function canCarryIt(item, amount, xPlayer) if Config.UseOx_inventory then return exports.ox_inventory:CanCarryItem(xPlayer.PlayerData.source, item, amount) end local totalWeight = QBCore.Player.GetTotalWeight(xPlayer.PlayerData.items) local itemInfo = QBCore.Shared.Items[item:lower()] if not itemInfo then TriggerClientEvent('QBCore:Notify', xPlayer.PlayerData.source, 'This item doesn\'t exits', 'error') return end amount = tonumber(amount) if (totalWeight + (itemInfo['weight'] * amount)) <= 120000 then return true else return false end end function hasPermission(source) local staff = false for k,v in ipairs(Config.AdminGroups) do if QBCore.Functions.HasPermission(source, v) then staff = true break end end return staff end function MySQLexecute(query, values, func) return MySQL.query(query, values, func) end function MySQLfetchAll(query, values, func) return MySQL.query(query, values, func) end function giveXP(xPlayer, xp, workbench) if Config.SameLevelForAllTables then MySQLexecute('UPDATE players SET '..Config.xpColumnsName..' = xp+@xp WHERE citizenid = @identifier', { ['@identifier'] = xPlayer.PlayerData.citizenid, ['@xp'] = Config.DoubleXP and xp*2 or xp, }, function (result) TriggerClientEvent(Config.EventPrefix..':updateXP', xPlayer.PlayerData.source) end) else MySQLexecute('UPDATE players SET '..Config.xpColumnsName..' = JSON_SET(xp, @table, JSON_EXTRACT(xp, @table) + @xp) WHERE citizenid = @identifier', { ['@identifier'] = xPlayer.PlayerData.citizenid, ['@xp'] = Config.DoubleXP and xp*2 or xp, ['@table'] = "$."..workbench, }, function (result) TriggerClientEvent(Config.EventPrefix..':updateXP', xPlayer.PlayerData.source) end) end end QBCore.Functions.CreateCallback(Config.EventPrefix..":inv2", function(source, cb, item, isMoney) local xPlayer = QBCore.Functions.GetPlayer(source) local itemS = {} if isMoney == "false" then isMoney = false elseif isMoney == "true" then isMoney = true end if isMoney then local playerMoney = getMoney(item, xPlayer) itemS.name = item itemS.amount = playerMoney else itemS = xPlayer.Functions.GetItemByName(item) if itemS == nil then itemS = { name = item, amount = 0 } end if itemS.count ~= nil then itemS.amount = itemS.count end end cb(itemS) end) QBCore.Functions.CreateCallback(Config.EventPrefix..":maxCraft", function(source, cb, recipe, maxCraftAmount, isDisassemble, itemC, itmNeeded) local _source = source local xPlayer = QBCore.Functions.GetPlayer(_source) local maxCraft = maxCraftAmount local itemAmt = 0 if not isDisassemble then for k,v in ipairs(recipe) do local item = {} local itemCount = 0 if v[4] then itemCount = getMoney(v[1], xPlayer) else item = xPlayer.Functions.GetItemByName(v[1]) if item == nil then item = { name = v[1], amount = 0 } end if item.count ~= nil then item.amount = item.count end itemCount = item.amount end if itemCount > 0 then local possibleToCraft = itemCount/tonumber(v[2]) if possibleToCraft > 0 then if maxCraft > possibleToCraft then maxCraft = possibleToCraft end else maxCraft = 0 break end else maxCraft = 0 break end end else local item = xPlayer.Functions.GetItemByName(itemC) if item == nil then item = { name = itemC, amount = 0 } end if item.count ~= nil then item.amount = item.count end itemAmt = item.amount if itemAmt > 0 then local possibleToCraft = itemAmt/tonumber(itmNeeded) if possibleToCraft > 0 then if maxCraft > possibleToCraft then maxCraft = possibleToCraft end else maxCraft = 0 end else maxCraft = 0 end end cb(math.floor(maxCraft), itemAmt) end) local function normalizeRecipe(recipe) local normalized = {} for _, item in ipairs(recipe) do local normalizedItem = { item[1], tonumber(item[2]), item[3] == "true" or item[3] == true, item[4] == "true" or item[4] == true } table.insert(normalized, normalizedItem) end return normalized end local function compareRecipes(recipe1, recipe2) if #recipe1 ~= #recipe2 then return false end for i, item1 in ipairs(recipe1) do local item2 = recipe2[i] if item1[1] ~= item2[1] and item1[2] <= item2[2] then return false end end return true end function craftExistsInWorkbench(workbenchID, itemID, recipe) for _, workbench in pairs(Config.Crafting) do if workbench.tableID == workbenchID then for _, craft in pairs(workbench.crafts) do if Config.Crafts[craft] == nil then print("Craft "..craft.." does not exist in Config.Crafts") return false end if Config.Crafts[craft].item == itemID then local normalizedCraftRecipe = normalizeRecipe(Config.Crafts[craft].recipe) local normalizedInputRecipe = normalizeRecipe(recipe) if compareRecipes(normalizedCraftRecipe, normalizedInputRecipe) then return true end end end end end return false end QBCore.Functions.CreateCallback(Config.EventPrefix..":CanCraftItem", function(source, cb, itemID, recipe, itemName, amount, isItem, workbench, timeCraft, CraftQueues, xp, pc, isDis, itemData) local xPlayer = QBCore.Functions.GetPlayer(source) local canCraft = true if not craftExistsInWorkbench(workbench, itemID, recipe) then canCraft = false end if not isDis then for k,v in pairs(recipe) do if v[4] == "false" then local item = xPlayer.Functions.GetItemByName(v[1]) if item == nil then item = { name = v[1], amount = 0 } end if item.count ~= nil then item.amount = item.count end if item.amount < v[2] then canCraft = false end else local playerMoney = getMoney(v[1], xPlayer) if playerMoney < v[2] then canCraft = false end end end else local item = xPlayer.Functions.GetItemByName(itemID) if item == nil then item = { name = itemID, amount = 0 } end if item.count ~= nil then item.amount = item.count end if tonumber(item.amount) < tonumber(amount) then canCraft = false end end if canCraft then if not isDis then for k,v in pairs(recipe) do if v[3] == "true" then if v[4] == "true" then removeMoney(v[1], v[2], xPlayer) else removeItem(xPlayer, v[1], v[2]) end end end else removeItem(xPlayer, itemID, tonumber(amount)) end local queue = CraftQueues if queue ~= nil and queue[workbench] ~= nil then queue[workbench][#queue[workbench]+1] = { item = itemID, recipe = recipe, amount = amount, isItem = isItem, time = timeCraft, itemName = itemName[itemID], isDone = false, isPending = true, randomID = math.random(100000000, 999999999), xp = xp, sucPC = pc, suc = true, isDis = isDis, data = itemData } MySQLexecute('UPDATE players SET '..Config.craftQueryColumnName..' = @okokcrafts WHERE citizenid = @identifier', { ['@identifier'] = xPlayer.PlayerData.citizenid, ['@okokcrafts'] = json.encode(queue), }, function (result) TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('added_to_queue').title, interp(_L('added_to_queue').text, {s1 = itemName[itemID]}), _L('added_to_queue').time, _L('added_to_queue').type) if Webhook ~= "" then data = { playerid = xPlayer.PlayerData.source, type = "start-craft", item = itemName[itemID], amount = amount, } discordWebhook(data) end cb(queue) end) else if queue == nil then queue = {} end queue[workbench] = {} queue[workbench] = { [1] = { item = itemID, recipe = recipe, amount = amount, isItem = isItem, time = timeCraft, itemName = itemName[itemID], isDone = false, isPending = true, randomID = math.random(100000000, 999999999), xp = xp, sucPC = pc, suc = true, isDis = isDis, data = itemData } } MySQLexecute('UPDATE players SET '..Config.craftQueryColumnName..' = @okokcrafts WHERE citizenid = @identifier', { ['@identifier'] = xPlayer.PlayerData.citizenid, ['@okokcrafts'] = json.encode(queue), }, function (result) TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('added_to_queue').title, interp(_L('added_to_queue').text, {s1 = itemName[itemID]}), _L('added_to_queue').time, _L('added_to_queue').type) if Webhook ~= "" then data = { playerid = xPlayer.PlayerData.source, type = "start-craft", item = itemName[itemID], amount = amount, } discordWebhook(data) end cb(queue) end) end else TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('cant_craft').title, interp(_L('cant_craft').text, {s1 = itemName[itemID]}), _L('cant_craft').time, _L('cant_craft').type) cb(false) end end) RegisterServerEvent(Config.EventPrefix..':claimAll') AddEventHandler(Config.EventPrefix..':claimAll', function(workbench, AllQueues) local xPlayer = QBCore.Functions.GetPlayer(source) local gotQueue = false local CraftsQueue = {} MySQLfetchAll('SELECT okokcrafts FROM players WHERE citizenid = @identifier', { ['@identifier'] = xPlayer.PlayerData.citizenid, }, function (result) if result[1] ~= nil then local data = json.decode(result[1].okokcrafts) if data ~= nil then CraftsQueue = data gotQueue = true end end end) while not gotQueue do Citizen.Wait(100) end local queue = CraftsQueue[workbench] local v = queue[1] if v ~= nil then if v.isDone then if v.suc then if not v.isDis then local canCarry = false if v.isItem then if canCarryIt(v.item, v.amount, xPlayer) then addItem(xPlayer, v.item, v.amount, v.data) canCarry = true end else if canCarryIt(v.item, v.amount, xPlayer) then addItem(xPlayer, v.item, v.amount) canCarry = true end end if canCarry then if Webhook ~= "" then data = { playerid = xPlayer.PlayerData.source, type = "claim-craft", item = v.itemName, amount = v.amount, } discordWebhook(data) end if Config.UseXP then giveXP(xPlayer, v.xp, workbench) end TriggerClientEvent(Config.EventPrefix..':removeItemsFromQueue', xPlayer.PlayerData.source, 1, workbench) else TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('cant_carry').title, _L('cant_carry').text, _L('cant_carry').time, _L('cant_carry').type) TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('claimed_all_items').title, _L('claimed_all_items').text, _L('claimed_all_items').time, _L('claimed_all_items').type) TriggerClientEvent(Config.EventPrefix..':resetClaimAllButton', xPlayer.PlayerData.source) end else local canCarry = true for k2,v2 in ipairs(v.recipe) do if v2[4] == "false" or v2[4] == false then if not canCarryIt(v2[1], v2[2], xPlayer) then canCarry = false end end end if canCarry then for k2,v2 in ipairs(v.recipe) do if v2[4] == "true" or v2[4] == true then addMoney(v2[1], v2[2], xPlayer) else addItem(xPlayer, v2[1], v2[2]) end end if Webhook ~= "" then data = { playerid = xPlayer.PlayerData.source, type = "claim-craft", item = v.itemName, amount = v.amount, } discordWebhook(data) end if Config.UseXP then giveXP(xPlayer, v.xp, workbench) end TriggerClientEvent(Config.EventPrefix..':removeItemsFromQueue', xPlayer.PlayerData.source, 1, workbench) else TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('cant_carry').title, _L('cant_carry').text, _L('cant_carry').time, _L('cant_carry').type) TriggerClientEvent(Config.EventPrefix..':notification', xPlayer.PlayerData.source, _L('claimed_all_items').title, _L('claimed_all_items').text, _L('claimed_all_items').time, _L('claimed_all_items').type) TriggerClientEvent(Config.EventPrefix..':resetClaimAllButton', xPlayer.PlayerData.source) end end else if Webhook ~= "" then data = { playerid = xPlayer.PlayerData.source, type = "failed-craft", item = v.itemName, amount = v.amount, } discordWebhook(data) end if Config.GiveXPOnCraftFailed and Config.UseXP then if Config.UseXP then giveXP(xPlayer, v.xp, workbench) end end TriggerClientEvent(Config.EventPrefix..':removeItemsFromQueue', xPlayer.PlayerData.source, 1, workbench) end end end end) -------------------------- IDENTIFIERS function ExtractIdentifiers(id) local identifiers = { steam = "", ip = "", discord = "", license = "", xbl = "", live = "" } for i = 0, GetNumPlayerIdentifiers(id) - 1 do local playerID = GetPlayerIdentifier(id, i) if string.find(playerID, "steam") then identifiers.steam = playerID elseif string.find(playerID, "ip") then identifiers.ip = playerID elseif string.find(playerID, "discord") then identifiers.discord = playerID elseif string.find(playerID, "license") then identifiers.license = playerID elseif string.find(playerID, "xbl") then identifiers.xbl = playerID elseif string.find(playerID, "live") then identifiers.live = playerID end end return identifiers end -------------------------- WEBHOOK function discordWebhook(data) local color = '65352' local category = 'default' local item = '' local amount = '' local identifierlist = ExtractIdentifiers(data.playerid) local identifier = identifierlist.license:gsub("license2:", "") local discord = "<@"..identifierlist.discord:gsub("discord:", "")..">" if data.type == 'start-craft' then color = Config.StartCraftWebhookColor category = 'Started a craft' item = data.item amount = data.amount elseif data.type == 'cancel-craft' then color = Config.CancelWebhookColor category = 'Canceled a craft' item = data.item amount = data.amount elseif data.type == 'claim-craft' then color = Config.ClaimCraftWebhookColor category = 'Claimed' item = data.item amount = data.amount elseif data.type == 'failed-craft' then color = Config.FailedCraftWebhookColor category = 'Failed a craft' item = data.item amount = data.amount end local information = { { ["color"] = color, ["author"] = { ["icon_url"] = Config.IconURL, ["name"] = Config.ServerName..' - Logs', }, ["title"] = 'CRAFTING', ["description"] = '**Action:** '..category..'\n**Item:** '..item..'\n**Amount:** '..amount..'\n\n**ID:** '..data.playerid..'\n**Identifier:** '..identifier..'\n**Discord:** '..discord, ["footer"] = { ["text"] = os.date(Config.DateFormat), } } } PerformHttpRequest(Webhook, function(err, text, headers) end, 'POST', json.encode({username = Config.BotName, embeds = information}), {['Content-Type'] = 'application/json'}) end