local positions = {} local presets = {} -- Load positions from database local function LoadPositionsFromDB() local result = MySQL.query.await('SELECT * FROM weapon_positions') if result then for _, data in ipairs(result) do local weaponData = { coords = vector3(data.position_x, data.position_y, data.position_z), rot = vector3(data.rotation_x, data.rotation_y, data.rotation_z), boneId = data.bone_id } if data.is_preset == 1 then presets[data.weapon_name] = weaponData else if not positions[data.identifier] then positions[data.identifier] = {} end positions[data.identifier][data.weapon_name] = weaponData end end end end -- Save position to database local function SavePositionToDB(identifier, weaponName, position, rotation, boneId, isPreset) MySQL.query.await('INSERT INTO weapon_positions (identifier, weapon_name, position_x, position_y, position_z, rotation_x, rotation_y, rotation_z, bone_id, is_preset) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE position_x = VALUES(position_x), position_y = VALUES(position_y), position_z = VALUES(position_z), rotation_x = VALUES(rotation_x), rotation_y = VALUES(rotation_y), rotation_z = VALUES(rotation_z), bone_id = VALUES(bone_id)', { identifier, weaponName, position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, boneId, isPreset and 1 or 0 }) end -- Delete position from database local function DeletePositionFromDB(identifier, weaponName) MySQL.query.await('DELETE FROM weapon_positions WHERE identifier = ? AND weapon_name = ?', { identifier, weaponName }) end -- Load data when resource starts CreateThread(function() LoadPositionsFromDB() end) lib.callback.register('force-sling:callback:getCachedPositions', function(source) local src = source local identifier = GetPlayerIdentifier(src) return positions[identifier] or {} end) lib.callback.register('force-sling:callback:getCachedPresets', function(source) return presets end) lib.callback.register('force-sling:callback:isPlayerAdmin', function(source) local src = source -- Add your admin check logic here return {isAdmin = true} end) lib.callback.register('force-sling:callback:resetWeaponPositions', function(source, weapon) local src = source local identifier = GetPlayerIdentifier(src) if weapon then if positions[identifier] then positions[identifier][weapon] = nil DeletePositionFromDB(identifier, weapon) end else positions[identifier] = {} MySQL.query.await('DELETE FROM weapon_positions WHERE identifier = ? AND is_preset = 0', {identifier}) end return positions[identifier] or {} end) RegisterNetEvent('force-sling:server:saveWeaponPosition') AddEventHandler('force-sling:server:saveWeaponPosition', function(position, rotation, weapon, weaponName, boneId, isPreset) local src = source local identifier = GetPlayerIdentifier(src) local data = { coords = position, rot = rotation, boneId = boneId } if isPreset then presets[weaponName] = data SavePositionToDB('preset', weaponName, position, rotation, boneId, true) else if not positions[identifier] then positions[identifier] = {} end positions[identifier][weaponName] = data SavePositionToDB(identifier, weaponName, position, rotation, boneId, false) end end) -- Helper function to get player identifier function GetPlayerIdentifier(source) local identifiers = GetPlayerIdentifiers(source) -- Modify this based on your framework (e.g., for QBCore or ESX) for _, identifier in pairs(identifiers) do if string.find(identifier, 'license:') then return identifier end end return nil end