Skip to content

Commit

Permalink
Refactored code for clarity, improved error handling, and added licen…
Browse files Browse the repository at this point in the history
…se requirement feature for shop access.

- **Code Cleanup:** Refactored code for better readability and simplicity.
- **Improved Error Handling:** Enhanced error checks for smoother functionality.
- **License Support:** Added the option to require licenses for shop access, with prompts for players to buy them if needed.
  • Loading branch information
yiruzu committed Nov 25, 2024
1 parent 50550c5 commit e9c8de2
Show file tree
Hide file tree
Showing 8 changed files with 444 additions and 114 deletions.
125 changes: 120 additions & 5 deletions bridge/server/custom.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,120 @@
---@diagnostic disable: undefined-field

local Config = require("shared.sh_config")
local Locales = require("shared.sh_locales")

if Config.Framework ~= "custom" then return end

local inShop = {}

--- Retrieves the Player ID for the given source
---@param source number -- Player's source ID
---@return number -- The Player ID
local function GetPlayerId(source)
---@diagnostic disable-next-line: return-type-mismatch
if not source or source == 0 then return nil end
return Your_Framework.GetPlayer(source) -- example
end

--- Checks if the player can carry the specified item and quantity.
---@param source number -- Player's source ID
---@param itemName string -- The name of the item
---@param itemQuantity number -- The quantity of the item
---@return boolean -- True if the player can carry the item, false otherwise
local function CanCarryItem(source, itemName, itemQuantity)
if Config.OxInventory then
return exports.ox_inventory:CanCarryItem(source, itemName, itemQuantity)
else
local Player = GetPlayerId(source)
return Player.CanCarryItem(source, itemName, itemQuantity) -- example
end
end

--- Adds an item to the player's inventory.
---@param source number -- Player's source ID
---@param itemName string -- The name of the item
---@param itemQuantity number -- The quantity of the item
---@return boolean -- True if the item was successfully added, false otherwise
local function AddItem(source, itemName, itemQuantity)
if Config.OxInventory then
return exports.ox_inventory:AddItem(source, itemName, itemQuantity)
else
local Player = GetPlayerId(source)
return Player.AddItem(source, itemName, itemQuantity) -- example
end
end

--- Checks if the player has the specific license.
---@param source number -- Player's source ID
---@param licenseType string -- License type (e.g., "weapon")
---@return boolean -- True if the player has the license, false otherwise
local function HasLicense(source, licenseType)
if not source or source == 0 then return false end
if not licenseType then return false end

local Player = GetPlayerId(source)
if not Player then return false end

return Player.HasLicense(licenseType) -- example
end

--- Buys a specific license for the player.
---@param source number -- Player's source ID
---@param shopData table -- Table with shop data
---@return boolean -- True if the license was successfully bought, false otherwise
---@return string -- Reason for transaction outcome
local function BuyLicense(source, shopData)
if not source or source == 0 then return false, "Invalid source" end
if not shopData or next(shopData) == nil then return false, "Invalid or empty shop data" end
if not inShop[source] then return false, "Not in shop state" end

local Player = GetPlayerId(source)
if not Player then return false, "Player not found" end

local licenseType = shopData.License.Type
local amount = shopData.License.Price

local moneyAvailable = Player.GetMoney("cash") -- example
local bankAvailable = Player.GetMoney("bank") -- example

local accountType
if moneyAvailable >= amount then
accountType = "cash"
elseif bankAvailable >= amount then
accountType = "bank"
else
ServerNotify(source, Locales.License.NoMoney:format(licenseType), "error")
return false, "No money"
end

Player.RemoveMoney(accountType, amount) -- example
Player.AddLicense(licenseType) -- example
ServerNotify(source, Locales.License.PurchaseSuccess:format(licenseType, amount), "info")
return true, "Successfully bought license"
end

if not Config.WeaponAsItem and not Config.OxInventory then
--- Checks if the player already has the specified weapon.
---@param source number -- Player's source ID
---@param weaponName string -- The name of the weapon
---@return boolean -- True if the player has the weapon, false otherwise
function HasWeapon(source, weaponName)
if not source or source == 0 then return false end
local Player = GetPlayerId(source)
return Player.HasWeapon(weaponName) -- example
end

--- Adds a weapon to the player.
---@param source number -- Player's source ID
---@param weaponName string -- The name of the weapon
---@return boolean -- True if the item was successfully added, false otherwise
function AddWeapon(source, weaponName)
if not source or source == 0 then return false end
local Player = GetPlayerId(source)
return Player.AddWeapon(weaponName) -- example
end
end

--- Processes a shop transaction for a player
---@param source number -- Player's source ID
---@param type string -- Transaction type ("bank" or "money")
Expand All @@ -13,31 +123,31 @@ local inShop = {}
---@return string -- Reason for transaction outcome
local function ProcessTransaction(source, type, cartArray)
if not source or source == 0 then return false, "Invalid source" end
if not cartArray or #cartArray == 0 then return false, "Empty cart" end
if not cartArray or #cartArray == 0 then return false, "Invalid or empty cart array" end
if not inShop[source] then return false, "Not in shop state" end

local Player = Your_Framework.GetPlayer(source)
local Player = GetPlayerId(source)
if not Player then return false, "Player not found" end

local accountType = type == "bank" and "bank" or "money"
local totalCartPrice = 0

for _, item in ipairs(cartArray) do
local availableMoney = Player.GetMoney(accountType)
local availableMoney = Player.GetMoney(accountType) -- example
local totalItemPrice = item.price * item.quantity

if availableMoney >= totalItemPrice then
if item.name:sub(1, 7):lower() == "weapon_" and not Config.WeaponAsItem then
if not HasWeapon(source, item.name) then
Player.RemoveMoney(accountType, totalItemPrice)
Player.RemoveMoney(accountType, totalItemPrice) -- example
AddWeapon(source, item.name)
totalCartPrice = totalCartPrice + totalItemPrice
else
ServerNotify(source, Locales.Notification.HasWeapon:format(item.label), "error")
end
else
if CanCarryItem(source, item.name, item.quantity) then
Player.RemoveMoney(accountType, totalItemPrice)
Player.RemoveMoney(accountType, totalItemPrice) -- example
AddItem(source, item.name, item.quantity)
totalCartPrice = totalCartPrice + totalItemPrice
else
Expand All @@ -56,6 +166,11 @@ local function ProcessTransaction(source, type, cartArray)
return false, "No items purchased"
end

lib.callback.register("cloud-shop:server:HasLicense", HasLicense)
lib.callback.register("cloud-shop:server:BuyLicense", function(source, shopData)
local success, reason = BuyLicense(source, shopData)
return success, reason
end)
lib.callback.register("cloud-shop:server:ProcessTransaction", function(source, type, cartArray)
local success, reason = ProcessTransaction(source, type, cartArray)
return success, reason
Expand Down
98 changes: 95 additions & 3 deletions bridge/server/esx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,99 @@ local ESX = exports["es_extended"]:getSharedObject()

local inShop = {}

local function GetPlayerId(source)
if not source or source == 0 then return nil end
return ESX.GetPlayerFromId(source)
end

local function CanCarryItem(source, itemName, itemQuantity)
if Config.OxInventory then
return exports.ox_inventory:CanCarryItem(source, itemName, itemQuantity)
else
local xPlayer = GetPlayerId(source)
if not xPlayer then return false end

return xPlayer.canCarryItem(itemName, itemQuantity)
end
end

local function AddItem(source, itemName, itemQuantity)
if Config.OxInventory then
return exports.ox_inventory:AddItem(source, itemName, itemQuantity)
else
local xPlayer = GetPlayerId(source)
if not xPlayer then return false end

return xPlayer.addInventoryItem(itemName, itemQuantity)
end
end

local function HasLicense(source, licenseType)
if not source or source == 0 then return false end
if not licenseType then return false end

local p = promise.new()
TriggerEvent("esx_license:checkLicense", source, licenseType, function(hasLicense)
p:resolve(hasLicense)
end)

local result = Citizen.Await(p)
return result
end

local function BuyLicense(source, shopData)
if not source or source == 0 then return false, "Invalid source" end
if not shopData or next(shopData) == nil then return false, "Invalid or empty shop data" end
if not inShop[source] then return false, "Not in shop state" end

local xPlayer = GetPlayerId(source)
if not xPlayer then return false, "Player not found" end

local licenseType = shopData.License.Type
local licenseTypeLabel = shopData.License.TypeLabel
local amount = shopData.License.Price

local moneyAvailable = xPlayer.getAccount("money").money
local bankAvailable = xPlayer.getAccount("bank").money

local accountType
if moneyAvailable >= amount then
accountType = "money"
elseif bankAvailable >= amount then
accountType = "bank"
else
ServerNotify(source, Locales.License.NoMoney:format(licenseTypeLabel), "error")
return false, "No money"
end

xPlayer.removeAccountMoney(accountType, amount)
TriggerEvent("esx_license:addLicense", source, licenseType)
ServerNotify(source, Locales.License.PurchaseSuccess:format(licenseTypeLabel, amount), "info")
return true, "Successfully bought license"
end

if not Config.WeaponAsItem and not Config.OxInventory then
function HasWeapon(source, weaponName)
local xPlayer = GetPlayerId(source)
if not xPlayer then return false end

return xPlayer.hasWeapon(weaponName)
end

function AddWeapon(source, weaponName)
local xPlayer = GetPlayerId(source)
if not xPlayer then return false end

return xPlayer.addWeapon(weaponName, 120)
end
end

local function ProcessTransaction(source, type, cartArray)
if not source or source == 0 then return false, "Invalid source" end
if not cartArray or #cartArray == 0 then return false, "Empty cart" end
if not cartArray or #cartArray == 0 then return false, "Invalid or empty cart array" end
if not inShop[source] then return false, "Not in shop state" end

local xPlayer = ESX.GetPlayerFromId(source)
local xPlayer = GetPlayerId(source)
if not xPlayer then return false, "Player not found" end

local accountType = type == "bank" and "bank" or "money"
Expand All @@ -23,7 +110,7 @@ local function ProcessTransaction(source, type, cartArray)
local totalItemPrice = item.price * item.quantity

if availableMoney >= totalItemPrice then
if item.name:sub(1, 7):lower() == "weapon_" and not Config.WeaponAsItem then
if item.name:sub(1, 7):lower() == "weapon_" and not Config.WeaponAsItem and not Config.OxInventory then
if not HasWeapon(source, item.name) then
xPlayer.removeAccountMoney(accountType, totalItemPrice)
AddWeapon(source, item.name)
Expand Down Expand Up @@ -52,6 +139,11 @@ local function ProcessTransaction(source, type, cartArray)
return false, "No items purchased"
end

lib.callback.register("cloud-shop:server:HasLicense", HasLicense)
lib.callback.register("cloud-shop:server:BuyLicense", function(source, shopData)
local success, reason = BuyLicense(source, shopData)
return success, reason
end)
lib.callback.register("cloud-shop:server:ProcessTransaction", function(source, type, cartArray)
local success, reason = ProcessTransaction(source, type, cartArray)
return success, reason
Expand Down
84 changes: 82 additions & 2 deletions bridge/server/qbcore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,87 @@ local QBCore = exports["qb-core"]:GetCoreObject()

local inShop = {}

local function GetPlayerId(source)
if not source or source == 0 then return nil end
return QBCore.Functions.GetPlayer(source)
end

local function CanCarryItem(source, itemName, itemQuantity)
if Config.OxInventory then
return exports.ox_inventory:CanCarryItem(source, itemName, itemQuantity)
else
exports["qb-inventory"]:CanAddItem(source, itemName, itemQuantity)
end
end

local function AddItem(source, itemName, itemQuantity)
if Config.OxInventory then
return exports.ox_inventory:AddItem(source, itemName, itemQuantity)
else
return exports["qb-inventory"]:AddItem(source, itemName, itemQuantity, false, false, "cloud-shop:AddItem")
end
end

local function HasLicense(source, licenseType)
if not source or source == 0 then return false end
if not licenseType then return false end

local Player = GetPlayerId(source)
if not Player then return false end

return Player.PlayerData.metadata.licences[licenseType]
end

local function BuyLicense(source, shopData)
if not source or source == 0 then return false, "Invalid source" end
if not shopData or next(shopData) == nil then return false, "Invalid or empty shop data" end
if not inShop[source] then return false, "Not in shop state" end

local Player = GetPlayerId(source)
if not Player then return false, "Player not found" end

local licenseType = shopData.License.Type
local amount = shopData.License.Price

local moneyAvailable = Player.Functions.GetMoney("cash")
local bankAvailable = Player.Functions.GetMoney("bank")

local accountType
if moneyAvailable >= amount then
accountType = "cash"
elseif bankAvailable >= amount then
accountType = "bank"
else
ServerNotify(source, Locales.License.NoMoney:format(licenseType), "error")
return false, "No money"
end

Player.Functions.RemoveMoney(accountType, amount)

local licenseTable = Player.PlayerData.metadata.licences
licenseTable[licenseType] = true
Player.Functions.SetMetaData("licences", licenseTable)

ServerNotify(source, Locales.License.PurchaseSuccess:format(licenseType, amount), "info")
return true, "Successfully bought license"
end

if not Config.WeaponAsItem and not Config.OxInventory then
function HasWeapon(source, weaponName)
-- add your logic here
end

function AddWeapon(source, weaponName)
-- add your logic here
end
end

local function ProcessTransaction(source, type, cartArray)
if not source or source == 0 then return false, "Invalid source" end
if not cartArray or #cartArray == 0 then return false, "Empty cart" end
if not cartArray or #cartArray == 0 then return false, "Invalid or empty cart array" end
if not inShop[source] then return false, "Not in shop state" end

local Player = QBCore.Functions.GetPlayer(source)
local Player = GetPlayerId(source)
if not Player then return false, "Player not found" end

local accountType = type == "bank" and "bank" or "money"
Expand Down Expand Up @@ -52,6 +127,11 @@ local function ProcessTransaction(source, type, cartArray)
return false, "No items purchased"
end

lib.callback.register("cloud-shop:server:HasLicense", HasLicense)
lib.callback.register("cloud-shop:server:BuyLicense", function(source, shopData)
local success, reason = BuyLicense(source, shopData)
return success, reason
end)
lib.callback.register("cloud-shop:server:ProcessTransaction", function(source, type, cartArray)
local success, reason = ProcessTransaction(source, type, cartArray)
return success, reason
Expand Down
Loading

0 comments on commit e9c8de2

Please sign in to comment.