Files
2025-08-05 16:05:47 -04:00

169 lines
6.8 KiB
Lua

Version = Version or {}
local function parseVersion(versionString)
return versionString and versionString:match('%d+%.%d+%.%d+') or versionString
end
local function padVersion(version)
local parts = {}
for num in version:gmatch("%d+") do
table.insert(parts, tonumber(num))
end
while #parts < 3 do
table.insert(parts, 0)
end
return parts
end
local function compareVersions(v1, v2)
local a, b = padVersion(v1), padVersion(v2)
for i = 1, 3 do
if a[i] < b[i] then
return -1
elseif a[i] > b[i] then
return 1
end
end
return 0
end
local function buildPatchNotesUrl(branch, repoPath)
local username, reponame = repoPath:match("([^/]+)/([^/]+)")
return ('https://raw.githubusercontent.com/%s/%s/%s/resources.json'):format(username, reponame, branch)
end
local function getDownloadUrl(repoPath, isTebex, actualRepoPath)
if isTebex then
return "https://portal.cfx.re/assets/granted-assets"
elseif actualRepoPath then
local username, reponame = actualRepoPath:match("([^/]+)/([^/]+)")
if username and reponame then return ('https://github.com/%s/%s/releases/latest'):format(username, reponame) end
end
return nil
end
local function printUpdateAvailable(resource, localVersion, downloadUrl)
print(('^1An update is available for %s (current version: %s)\r\n - ^5Please download the latest version from %s^7'):format(resource, localVersion, downloadUrl))
end
local function printPatchNotes(notesToPrint)
print('^3Patch Notes:^7')
for _, entry in ipairs(notesToPrint) do
print(('^2Version %s:^7'):format(entry.version))
for _, line in ipairs(entry.notes) do
print((' - %s'):format(line))
end
end
end
local function validateRepoPath(repoPath)
local username, reponame = repoPath:match("([^/]+)/([^/]+)")
if not username or not reponame then return false, print('Invalid repository format. Expected format: username/reponame') end
return true, username, reponame
end
local function getLocalVersion(resource)
local localVersionRaw = GetResourceMetadata(resource, "version", 0)
if not localVersionRaw then
return nil, print('No version metadata found for resource "%s". Ensure fxmanifest.lua contains a valid version string.'):format(resource)
end
local version = parseVersion(localVersionRaw)
if not version then return nil, print('Invalid version format for resource "%s". Expected format: "x.x.x"'):format(resource) end
return version
end
local function processVersions(allVersions, localVersion)
local notesToPrint = {}
for versionStr, notes in pairs(allVersions) do
if compareVersions(versionStr, localVersion) > 0 and type(notes) == "table" then
table.insert(notesToPrint, { version = versionStr, notes = notes })
end
end
table.sort(notesToPrint, function(a, b)
return compareVersions(a.version, b.version) < 0
end)
return notesToPrint
end
local function fetchPatchNotes(branch, resource, repoPath, localVersion)
local url = buildPatchNotesUrl(branch, repoPath)
PerformHttpRequest(url, function(noteStatus, noteBody)
if noteStatus == 200 then
local patchData = json.decode(noteBody)
if not patchData then return end
local resourceData = patchData[resource]
if resourceData and type(resourceData) == "table" then
local actualRepoPath = resourceData.repo or resourceData.actualRepoPath
local isTebex = not actualRepoPath -- If no repo path, it's Tebex
local allVersions = resourceData.versions or resourceData -- Support both new and old format
local notesToPrint = processVersions(allVersions, localVersion)
if #notesToPrint > 0 then
local downloadUrl = getDownloadUrl(repoPath, isTebex, actualRepoPath) or url
printUpdateAvailable(resource, localVersion, downloadUrl)
printPatchNotes(notesToPrint)
end
end
elseif branch == "main" then
-- Fallback to master branch if main doesn't exist
fetchPatchNotes("master", resource, repoPath, localVersion)
end
end, 'GET')
end
--- Pass a github username and repo name to check for the latest version of the resource.
--- Tebex is a optional boolean to determine if the message should be for a escrowed resource or not.
--- Example: Version.VersionChecker("TheOrderFivem/community_bridge", false)
--- @param repoPath string
--- @param tebex boolean | nil
--- @return nil
function Version.VersionChecker(repoPath, tebex)
local username, reponame = repoPath:match("([^/]+)/([^/]+)")
local resource = reponame and repoPath:match("([^/]+)$")
if not username or not reponame or not resource then return print('^1Invalid repository format. Expected format: "username/reponame"^0') end
local version = GetResourceMetadata(resource, "version", 0)
if not version then return end
version = version:match('%d+%.%d+%.%d+')
if not version then return end
PerformHttpRequest(('https://api.github.com/repos/%s/%s/releases/latest'):format(username, reponame),
function(status, response)
if status ~= 200 then return end
local latest = json.decode(response).tag_name:match('%d+%.%d+%.%d+')
if not latest or latest == version or version:gsub('%D', '') >= latest:gsub('%D', '') then return end
local url = tebex and "https://portal.cfx.re/assets/granted-assets" or json.decode(response).html_url
print(('^1An update is available for %s (current version: %s)\r\n - ^5Please download the latest version from %s^7'):format(resource, version, url))
end,
'GET')
end
--- Advanced version checker with patch notes support
--- Reads Tebex information and repo path directly from the resources.json file
--- @param repoPath string GitHub repository path for patch notes in format "username/reponame"
--- @param resourceName string The actual resource name to check
--- @return nil
function Version.AdvancedVersionChecker(repoPath, resourceName)
local isValid, username, reponame = validateRepoPath(repoPath)
if not isValid then return print(('^1[ERROR]^7 %s'):format(username)) end
local resource = resourceName
local localVersion, errorMsg = getLocalVersion(resource)
if not localVersion then return print(('^1[ERROR]^7 %s'):format(username)) end
fetchPatchNotes("main", resource, repoPath, localVersion)
end
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
-- Version.VersionChecker("TheOrderFivem/community_bridge", false)
Version.AdvancedVersionChecker("TheOrderFivem/patchnotes", resourceName)
end)
return Version