Functions

Information regarding boii_base server player functions

create_player(source, unique_id, char_id, data)

Function to create player object for the user using the provided character data

local function create_player(source, unique_id, char_id, data)
    local self = {}
    self.source = source
    self.unique_id = unique_id
    self.char_id = char_id
    self.identity = data.identity
    self.balances = data.balances
    self.jobs = data.jobs
    self.paychecks = data.paychecks
    self.skills = data.skills
    self.inventory = data.inventory
    self.statuses = data.statuses
    self.booleans = data.booleans
    self.licences = data.licences
    self.genetics = data.genetics
    self.barber = data.barber
    self.clothing = data.clothing
    self.tattoos = data.tattoos
    self.position = data.position

    -- function to set players updated data on client
    function self:set_data(data_types, save_to_db)
        local data_table = {}
        local data_map = {
            unique_id = self.unique_id,
            char_id = self.char_id,
            identity = self.identity,
            balances = self.balances,
            jobs = self.jobs,
            paychecks = self.paychecks,
            skills = self.skills,
            inventory = self.inventory,
            statuses = self.statuses,
            booleans = self.booleans,
            licences = self.licences,
            genetics = self.genetics,
            barber = self.barber,
            clothing = self.clothing,
            tattoos = self.tattoos,
            position = self.position
        }
        if data_types[1] == 'all' then
            data_table = data_map
        else
            for _, data_type in ipairs(data_types) do
                if data_map[data_type] then
                    data_table[data_type] = data_map[data_type]
                end
            end
        end
        TriggerClientEvent('boii_base:cl:set_data', self.source, data_table)
        if save_to_db then
            self:save_data()
        end
    end

    -- function to modify balance
    function self:modify_balance(balance, action, amount, from)
        if not self.balances[balance] then print('invalid balance type') return end
        local current_amount = self.balances[balance].amount
        if action == 'add' then
            self.balances[balance].amount = current_amount + amount
        elseif action == 'remove' then
            self.balances[balance].amount = current_amount - amount
        elseif action == 'set' then
            self.balances[balance].amount = amount
        else 
            print('invalid action type') 
            return 
        end
        if self.balances[balance].amount < 0 and not self.balances[balance].negative_allowed then
            self.balances[balance].amount = 0
        end
        self:set_data({'balances'}, true)
    end

    -- function to add a paycheck
    function self:add_pending_paycheck(job_id, amount, info)
        if not self.paychecks[job_id] then
            self.paychecks[job_id] = {}
        end
        local formated_timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
        self.paychecks[job_id][#self.paychecks[job_id]+1] = { amount = amount, timestamp = formated_timestamp }
        self:set_data({'paychecks'}, true)
    end

    -- function to set a players jobs
    function self:set_job(new_job_id, grade_id)
        local job_data = boii.get_job_data(new_job_id)
        if not job_data then print("Error: The job with ID", new_job_id, "does not exist.") return false end
        if not job_data.grades[grade_id] then print("Error: The grade with ID", grade_id, "does not exist for job", new_job_id) return false end
        local secondary_count = 0
        local has_primary = false
        for job_id, job_details in pairs(self.jobs) do
            if job_details.type == 'secondary' then
                secondary_count = secondary_count + 1
            elseif job_details.type == 'primary' then
                has_primary = true
            end
        end
        if job_data.type == "primary" and has_primary and not self.jobs[new_job_id] then 
            for job_id, job_details in pairs(self.jobs) do
                if job_details.type == 'primary' then
                    self.jobs[job_id] = nil
                    break
                end
            end
        end
        if job_data.type == "secondary" and not self.jobs[new_job_id] and secondary_count >= shared_data.jobs.max_secondary_jobs then print("Error: Maximum number of secondary jobs reached.") return false end
        if self.jobs[new_job_id] then
            if self.jobs[new_job_id].grade ~= job_data.grades[grade_id].grade then
                self.jobs[new_job_id].grade = job_data.grades[grade_id].grade
                self.jobs[new_job_id].grade_label = job_data.grades[grade_id].label
                self.jobs[new_job_id].salary = job_data.grades[grade_id].pay
            end
        else
            self.jobs[new_job_id] = {
                id = job_data.id,
                label = job_data.label,
                type = job_data.type,
                category = job_data.category,
                salary = job_data.grades[grade_id].pay,
                grade_label = job_data.grades[grade_id].label,
                grade = job_data.grades[grade_id].grade,
                on_duty = false
            }
        end
        self:set_data({'jobs'}, true)
        return true
    end
    
    -- function to get inventory weight
    function self:get_total_inventory_weight()
        local total_weight = 0
        for item_id, item in pairs(self.inventory.items) do
            local item_data = boii.get_item_data(item_id)
            if item_data then
                total_weight = total_weight + (item_data.weight * item.quantity)
            else
                print("No data found for item_id: " .. item_id)
            end
        end
        return total_weight
    end

    -- function to find the first available empty slot in the inventory
    function self:get_empty_slot()
        local max_slots = self.inventory.slots
        local occupied_slots = {}
        for _, item in pairs(self.inventory.items) do
            if item.slot then
                occupied_slots[item.slot] = true
            end
        end
        for i = 1, max_slots do
            if not occupied_slots[i] then
                return i
            end
        end
        return nil
    end

    -- function to modify inventory items
    function self:modify_inventory(item_id, action, amount)
        if type(amount) ~= "number" or amount < 0 then print("Invalid item amount.") return end
        local item_data = boii.get_item_data(item_id)
        if not item_data then  print("Item doesnt exist: " .. item_id) return end
        if not self.inventory.items[item_id] then
            self.inventory.items[item_id] = item_data
            self.inventory.items[item_id].quantity = 0
            self.inventory.items[item_id].hotbar = false
            local empty_slot = self:get_empty_slot()
            if empty_slot then
                self.inventory.items[item_id].slot = empty_slot
            else
                print("No empty slot available in inventory.")
                return
            end
        end
        local new_quantity = 0
        if action == 'add' then
            if item_data.unique and amount > 1 then
                print("Cannot add more than one of a unique item.")
                return
            elseif item_data.unique and self.inventory.items[item_id].quantity == 1 then
                print("Unique item already in inventory.")
                return
            end
            new_quantity = self.inventory.items[item_id].quantity + amount
            if (self:get_total_inventory_weight() + item_data.weight * amount) > self.inventory.weight then
                print("Item addition exceeds weight limit.")
                return
            end
        elseif action == 'remove' then
            new_quantity = self.inventory.items[item_id].quantity - amount
            if new_quantity < 0 then print("Not enough items to remove.") return end
        else 
            print('Invalid action type: ' .. action)
            return 
        end
        self.inventory.items[item_id].quantity = new_quantity
        if self.inventory.items[item_id].quantity == 0 then
            self.inventory.items[item_id] = nil
        end
        self:set_data({'inventory'}, true)
    end

    -- function to save players data to the database
    function self:save_data()
        local query = 'UPDATE players SET identity = ?, balances = ?, jobs = ?, paychecks = ?, skills = ?, inventory = ?, statuses = ?, booleans = ?, licences = ?, genetics = ?, barber = ?, clothing = ?, tattoos = ?, position = ? WHERE unique_id = ? AND char_id = ?'
        local params = {json.encode(self.identity), json.encode(self.balances), json.encode(self.jobs), json.encode(self.paychecks), json.encode(self.skills), json.encode(self.inventory), json.encode(self.statuses), json.encode(self.booleans), json.encode(self.licences), json.encode(self.genetics), json.encode(self.barber), json.encode(self.clothing), json.encode(self.tattoos), json.encode(self.position), self.unique_id, self.char_id}
        MySQL.Async.execute(query, params, function(rows_changed)
            if rows_changed > 0 then
                print('data saved successfully')
            else
                print('data save failed')
            end
        end)
    end
    
    self:set_data({'all'})
    boii.connected_users[source] = self
    TriggerEvent('boii_base:sv:player_joined', self)
    return self
end

Using Self Functions

To use self functions you need to use our utlity get_user() function like so

local _src = source
local player = boii.get_user(_src)

self:set_data(data_types, save_to_db)

Function to set a players data and sync to the client. You can update an individual data type like so;

player.statuses.health = 0

player:set_data({'statuses'}) -- does not save to database

player:set_data({'statuses'}, true) -- saves to database

You can also update all datatypes at once by sending 'all'

player:set_data({'all'}) -- does not save to database

player:set_data({'all'}, true) -- saves to database

self:modify_balance(balance, action, amount, from)

Function to modify balance you can use this to add or remove money from one of your balance types, "from" is simply a logging marker.

player:modify_balance('bank', 'add', 1000, "Add Money") -- add money to bank

player:modify_balance('bank', 'remove', 1000, "Remove Money") -- remove money from bank

self:add_pending_paycheck(job_id, amount, info)

Function to add a new pay check for a job, these are added periodically depending on the pay_frequency and direct_pay options within the shared jobs data or you can use this function to add a manual pay check.

player:add_pending_paycheck('lspd', 1000, 'Arrest bonus!') 

self:set_job(new_job_id, grade_id)

Function to update the players job and grade. The framework uses a multi-job setup where players can have 1 primary job and multiple secondary jobs. If a job type primary is set this will update this existing primary job. If job type secondary is set this will add a new secondary job to the character up until the max_secondary_jobs value is reached. You can adjust this in shared/jobs

player:set_job('lspd', 'recruit')

self:get_total_inventory_weight()

Helper function to get total inventory weight of character, this will most likely be removed and placed into inventory functions for now it is here

self:get_empty_slot()

Helper function to place item in next empty slot in the inventory, this will most likely be removed and placed into inventory functions also.

self:modify_inventory(item_id, action, amount)

Function to modify a players inventory items. If the item does not already exist a new item will be added, if the item does exist the quantity will be increased/lowered by the amount.

player:modify_inventory('burger', 'add', 1) -- add an item

player:modify_inventory('burger', 'remove', 1) -- remove an item

self:save_data()

Function to save the entire encoded data set of the object to the database. This is done automatically through the set_data function provided save_to_db is true

self:save_data() -- save data

self:set_data({'all'}, true) -- saving all data through set_data function

Last updated