├── README.md ├── client └── main.lua ├── fxmanifest.lua ├── items.txt ├── jobs.txt └── server └── main.lua /README.md: -------------------------------------------------------------------------------- 1 | # sd-creator 2 | 3 | It's relatively simple. 4 | 5 | Admins can use '/createitem' to see an ox_lib dialog/input and set item details. After confirming, it writes to items.txt in the resource's root. Similarly, with '/createjob', admins can define job settings and grades, which saves to jobs.txt. 6 | 7 | My discord is @ https://discord.gg/samueldev and my store is @ https://fivem.samueldev.shop 8 | 9 | # Preview 10 | https://streamable.com/n01zq6 11 | 12 | # Dependencies 13 | - ox_lib 14 | - qb-core 15 | -------------------------------------------------------------------------------- /client/main.lua: -------------------------------------------------------------------------------- 1 | local function registerItemDialog() 2 | local input = lib.inputDialog("Register a New Item", { 3 | {type = 'input', label = 'Item code', placeholder = 'yachtcodes', description = 'Unique code identifier for the item.', required = true}, 4 | {type = 'input', label = 'Name', placeholder = 'yachtcodes', description = 'Internal name of the item.', required = true}, 5 | {type = 'input', label = 'Label', placeholder = 'Yacht Access Codes', description = 'Display name for the item.', required = true}, 6 | {type = 'number', label = 'Weight', placeholder = '200', description = 'Numeric weight value of the item. (in grams)', required = true}, 7 | {type = 'input', label = 'Type', placeholder = 'item/weapon', description = 'Category or type of the item.', required = true}, 8 | {type = 'input', label = 'Image Path', placeholder = 'yachtcodes.png / yachtcodes.jpg', description = 'Item image name', required = true}, 9 | {type = 'checkbox', label = 'Is unique?', checked = true}, 10 | {type = 'checkbox', label = 'Is useable?', checked = true}, 11 | {type = 'checkbox', label = 'Should Close?', checked = true}, 12 | {type = 'input', label = 'Combinable', placeholder = 'casinocodes', description = 'Other items this can be combined with. Leave empty if not combinable.'}, 13 | {type = 'textarea', label = 'Description', placeholder = 'The first half of codes for the Yacht', description = 'Detailed description about the item.', required = true, min = 1, max = 4, autosize = true} 14 | }) 15 | return input 16 | end 17 | 18 | local function registerJobDialog() 19 | return lib.inputDialog("Register a New Job", { 20 | {type = 'input', label = 'Job Code', placeholder = 'jobcode', description = 'Unique name for the job', required = true}, 21 | {type = 'input', label = 'Job Label', placeholder = 'Job Label', description = 'Public name for the job', required = true}, 22 | {type = 'input', label = 'Type', placeholder = 'jobtype', description = 'Category or type of the job.'}, 23 | {type = 'checkbox', label = 'Default Duty?', description = 'Is this job a default duty?', checked = true}, 24 | {type = 'checkbox', label = 'Off Duty Pay?', description = 'Does this job get off-duty pay?', checked = false}, 25 | }) 26 | end 27 | 28 | local function registerJobGradeDialog() 29 | return lib.inputDialog("Add a Job Grade (Press 'Cancel' once done)", { 30 | {type = 'input', label = 'Grade Code', placeholder = '0', description = 'Numeric grade for the job position (ex. 0 for recruit, 1 for officer, etc.)', required = true}, 31 | {type = 'input', label = 'Grade Name', placeholder = 'Grade Name', description = 'Name of the job grade (ex. Recruit, Officer, etc.)', required = true}, 32 | {type = 'checkbox', label = 'Is Boss?', description = 'Is this grade considered a boss position?', checked = false}, 33 | {type = 'number', label = 'Payment', placeholder = '50', description = 'Payment amount for this grade', required = true}, 34 | }) 35 | end 36 | 37 | RegisterNetEvent('sd-itemcreator:client:openItemMenu', function() 38 | local input = registerItemDialog() 39 | if not input then return end 40 | 41 | -- Trigger server side event to save the data 42 | TriggerServerEvent('sd-itemcreator:server:saveItem', input) 43 | end) 44 | 45 | RegisterNetEvent('sd-jobcreator:client:openJobMenu', function(src) 46 | local jobInput = registerJobDialog() 47 | if not jobInput then return end -- If the user cancelled the dialog 48 | 49 | local grades = {} 50 | while true do 51 | local gradeInput = registerJobGradeDialog() 52 | if not gradeInput then break end -- If the user cancelled the grade dialog 53 | 54 | local gradeCode = gradeInput[1] 55 | local gradeDetails = { 56 | name = gradeInput[2], 57 | isboss = gradeInput[3], 58 | payment = gradeInput[4] 59 | } 60 | grades[gradeCode] = gradeDetails 61 | end 62 | 63 | local jobData = { 64 | code = jobInput[1], 65 | label = jobInput[2], 66 | type = jobInput[3], 67 | defaultDuty = jobInput[4], 68 | offDutyPay = jobInput[5], 69 | grades = grades 70 | } 71 | 72 | -- Trigger server side event to save the job data 73 | TriggerServerEvent('sd-jobcreator:server:saveJob', jobData) 74 | end) -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'cerulean' 2 | game 'gta5' 3 | 4 | name "Item Creator" 5 | author "Made with love by Samuel#0008" 6 | version "1.0" 7 | 8 | shared_scripts { 9 | '@ox_lib/init.lua', 10 | } 11 | 12 | client_scripts { 13 | 'client/main.lua', 14 | } 15 | 16 | server_scripts { 17 | 'server/main.lua', 18 | } 19 | 20 | lua54 'yes' -------------------------------------------------------------------------------- /items.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /jobs.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/main.lua: -------------------------------------------------------------------------------- 1 | QBCore = exports['qb-core']:GetCoreObject() 2 | 3 | -- Command for item creation 4 | QBCore.Commands.Add('createItem', '', {}, false, function(source, args) 5 | local src = source 6 | TriggerClientEvent('sd-itemcreator:client:openItemMenu', src, src) 7 | end,'admin') 8 | 9 | -- Command for job creation 10 | QBCore.Commands.Add('createJob', '', {}, false, function(source, args) 11 | local src = source 12 | TriggerClientEvent('sd-jobcreator:client:openJobMenu', src, src) 13 | end,'admin') 14 | 15 | -- Validate item input 16 | local function validateItem(item) 17 | for i = 1, 6 do 18 | if not item[i] or item[i] == "" then 19 | return false 20 | end 21 | end 22 | return true 23 | end 24 | 25 | -- Save item to file 26 | local function saveItemToFile(item) 27 | local resourcePath = GetResourcePath(GetCurrentResourceName()) 28 | local filePath = resourcePath .. "/items.txt" 29 | local file = io.open(filePath, "a") 30 | 31 | if file then 32 | file:write(string.format( 33 | "['%s'] = {['name'] = '%s', ['label'] = '%s', ['weight'] = %d, ['type'] = '%s', ['image'] = '%s', ['unique'] = %s, ['useable'] = %s, ['shouldClose'] = %s, ['combinable'] = %s, ['description'] = '%s'},\n", 34 | item[1], item[2], item[3], item[4], item[5], item[6], tostring(item[7]), tostring(item[8]), tostring(item[9]), item[10] or 'nil', item[11] 35 | )) 36 | file:close() 37 | else 38 | print("Error: Failed to open items.txt for writing.") 39 | end 40 | end 41 | 42 | RegisterServerEvent('sd-itemcreator:server:saveItem', function(item) 43 | if validateItem(item) then 44 | saveItemToFile(item) 45 | print("Item registered and saved to items.txt!") 46 | else 47 | print("Item validation failed.") 48 | end 49 | end) 50 | 51 | local function validateJob(job) 52 | return job.code and job.label and job.type 53 | end 54 | 55 | -- Save job to file 56 | local function saveJobToFile(job) 57 | local resourcePath = GetResourcePath(GetCurrentResourceName()) 58 | local filePath = resourcePath .. "/jobs.txt" 59 | local file = io.open(filePath, "a") 60 | 61 | if file then 62 | -- Get grade keys and sort them 63 | local gradeKeys = {} 64 | for grade, _ in pairs(job.grades) do 65 | table.insert(gradeKeys, tonumber(grade)) 66 | end 67 | table.sort(gradeKeys) 68 | 69 | local gradeStrings = {} 70 | for _, grade in ipairs(gradeKeys) do 71 | local details = job.grades[tostring(grade)] 72 | local bossString = details.isboss and ", isboss = true" or "" 73 | table.insert(gradeStrings, string.format("\t\t['%s'] = {\n\t\t\tname = '%s'%s,\n\t\t\tpayment = %d\n\t\t},", 74 | tostring(grade), details.name, bossString, details.payment)) 75 | end 76 | local grades = table.concat(gradeStrings, "\n") 77 | 78 | file:write(string.format( 79 | "\t['%s'] = {\n\t\tlabel = '%s',\n\t\ttype = '%s',\n\t\tdefaultDuty = %s,\n\t\toffDutyPay = %s,\n\t\tgrades = {\n%s\n\t\t},\n\t},\n", 80 | job.code, job.label, job.type, tostring(job.defaultDuty), tostring(job.offDutyPay), grades 81 | )) 82 | file:close() 83 | else 84 | print("Error: Failed to open jobs.txt for writing.") 85 | end 86 | end 87 | 88 | RegisterServerEvent('sd-jobcreator:server:saveJob', function(job) 89 | if validateJob(job) then 90 | saveJobToFile(job) 91 | print("Job registered and saved to jobs.txt!") 92 | else 93 | print("Job validation failed.") 94 | end 95 | end) --------------------------------------------------------------------------------