2025-02-17 12:14:12 -05:00
Version = Version or {}
2025-01-10 16:36:20 -05:00
2025-07-30 14:46:27 -04:00
local function padVersion ( v )
local parts = {}
for n in v : gmatch ( "%d+" ) do
table.insert ( parts , tonumber ( n ))
end
while # parts < 3 do
table.insert ( parts , 0 )
end
return parts
end
2025-07-30 17:31:51 -04:00
local function compareVersions ( v1 , v2 )
2025-07-30 14:46:27 -04:00
local a , b = padVersion ( v1 ), padVersion ( v2 )
for i = 1 , 3 do
2025-07-30 17:31:51 -04:00
if a [ i ] < b [ i ] then
return - 1
elseif a [ i ] > b [ i ] then
return 1
2025-07-30 14:46:27 -04:00
end
end
return 0
end
2025-07-30 17:31:51 -04:00
local function parseVersion ( versionString )
return versionString : match ( '%d+%.%d+%.%d+' ) or versionString
end
local function buildGithubApiUrl ( repoPath )
local username , reponame = repoPath : match ( "([^/]+)/([^/]+)" )
return ( 'https://api.github.com/repos/%s/%s/releases/latest' ): format ( username , reponame )
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 , tebex , actualRepoPath )
if tebex then
return "https://portal.cfx.re/assets/granted-assets"
elseif actualRepoPath and actualRepoPath ~= false then
local repoUser , repoName = actualRepoPath : match ( "([^/]+)/([^/]+)" )
2025-07-30 21:34:46 -04:00
if repoUser and repoName then return ( 'https://github.com/%s/%s/releases/latest' ): format ( repoUser , repoName ) end
2025-07-30 17:31:51 -04:00
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 printError ( message )
print (( '^1[ERROR]^7 %s' ): format ( message ))
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 , tebex , actualRepoPath )
local url = buildPatchNotesUrl ( branch , repoPath )
PerformHttpRequest ( url , function ( noteStatus , noteBody )
2025-07-30 14:46:27 -04:00
if noteStatus == 200 then
local patchData = json.decode ( noteBody )
if not patchData then return end
local allVersions = patchData [ resource ]
if allVersions and type ( allVersions ) == "table" then
2025-07-30 17:31:51 -04:00
local notesToPrint = processVersions ( allVersions , localVersion )
2025-07-30 14:46:27 -04:00
if # notesToPrint > 0 then
2025-07-30 17:31:51 -04:00
local downloadUrl = getDownloadUrl ( repoPath , tebex , actualRepoPath ) or url
printUpdateAvailable ( resource , localVersion , downloadUrl )
printPatchNotes ( notesToPrint )
2025-07-30 14:46:27 -04:00
end
end
elseif branch == "main" then
2025-07-30 17:31:51 -04:00
fetchPatchNotes ( "master" , resource , repoPath , localVersion , tebex , actualRepoPath )
2025-07-30 14:46:27 -04:00
end
end , 'GET' )
end
2025-07-30 17:31:51 -04:00
local function checkSimpleUpdate ( repoPath , resource , localVersion , isTebex )
local url = buildGithubApiUrl ( repoPath )
PerformHttpRequest ( url , function ( status , response )
if status ~= 200 then return end
local latest = parseVersion ( json.decode ( response ). tag_name )
if not latest or latest == localVersion or localVersion : gsub ( '%D' , '' ) >= latest : gsub ( '%D' , '' ) then
return
end
local downloadUrl = isTebex and "https://portal.cfx.re/assets/granted-assets" or json.decode ( response ). html_url
printUpdateAvailable ( resource , localVersion , downloadUrl )
end , 'GET' )
end
local function validateRepoPath ( repoPath )
local username , reponame = repoPath : match ( "([^/]+)/([^/]+)" )
if not username or not reponame then
return false , '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 , ( 'No version metadata found for resource "%s". Ensure fxmanifest.lua contains a valid version string.' ): format ( resource )
end
return parseVersion ( localVersionRaw )
end
2025-07-30 14:46:27 -04:00
--- Checks for updates to a resource by comparing the local version (from fxmanifest.lua) with the latest release on GitHub, and optionally prints patch notes if using the template.
--- Example - Version.VersionChecker("TheOrderFivem/patchnotes", true, true, "community_bridge", "TheOrderFivem/community_bridge")
2025-03-04 17:50:47 -05:00
---@param repoPath string
2025-07-30 17:31:51 -04:00
---@param isTebex boolean
2025-07-30 14:46:27 -04:00
---@param showPatchNotes boolean
---@param actualResourceName string
---@param actualRepoPathIfGithub string this is the githubAccount/repoName if the resource is hosted on github, otherwise it will use the repoPath initially passed, this is not needed for tebex = true
2025-03-04 17:50:47 -05:00
---@return nil
2025-07-30 17:31:51 -04:00
function Version . VersionChecker ( repoPath , isTebex , showPatchNotes , actualResourceName , actualRepoPathIfGithub )
local isValid , username , reponame = validateRepoPath ( repoPath )
if not isValid then return printError ( username ) end
2025-01-10 16:36:20 -05:00
2025-07-30 14:46:27 -04:00
local resource = actualResourceName or reponame
2025-07-30 17:31:51 -04:00
local localVersion , errorMsg = getLocalVersion ( resource )
if not localVersion then return printError ( errorMsg ) end
if not showPatchNotes then return checkSimpleUpdate ( repoPath , resource , localVersion , isTebex ) end
2025-07-30 14:46:27 -04:00
2025-07-30 17:31:51 -04:00
fetchPatchNotes ( "main" , resource , repoPath , localVersion , isTebex , actualRepoPathIfGithub )
2025-01-10 16:36:20 -05:00
end
AddEventHandler ( 'onResourceStart' , function ( resourceName )
if GetCurrentResourceName () ~= resourceName then return end
2025-07-30 14:46:27 -04:00
Version.VersionChecker ( "TheOrderFivem/patchnotes" , false , true , "community_bridge" , "TheOrderFivem/community_bridge" )
2025-05-10 00:01:56 -04:00
end )
2025-07-30 17:31:51 -04:00
return Version