542 lines
21 KiB
Lua
542 lines
21 KiB
Lua
|
|
local Races = {}
|
||
|
|
local AvailableRaces = {}
|
||
|
|
local LastRaces = {}
|
||
|
|
local NotFinished = {}
|
||
|
|
|
||
|
|
-- Functions
|
||
|
|
|
||
|
|
local function SecondsToClock(seconds)
|
||
|
|
seconds = tonumber(seconds)
|
||
|
|
if seconds > 0 then
|
||
|
|
local hours = string.format("%02.f", math.floor(seconds / 3600))
|
||
|
|
local mins = string.format("%02.f", math.floor(seconds / 60 - (hours * 60)))
|
||
|
|
local secs = string.format("%02.f", math.floor(seconds - hours * 3600 - mins * 60))
|
||
|
|
return hours..":"..mins..":"..secs
|
||
|
|
end
|
||
|
|
return "00:00:00"
|
||
|
|
end
|
||
|
|
|
||
|
|
local function IsWhitelisted(citizenId)
|
||
|
|
for _, cid in pairs(Config.WhitelistedCreators) do
|
||
|
|
if cid == citizenId then
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
local player = exports.qbx_core:GetPlayerByCitizenId(citizenId)
|
||
|
|
local perms = exports.qbx_core:GetPermission(player.PlayerData.source)
|
||
|
|
return perms == "admin" or perms == "god"
|
||
|
|
end
|
||
|
|
|
||
|
|
local function IsNameAvailable(raceName)
|
||
|
|
for RaceId in pairs(Races) do
|
||
|
|
if Races[RaceId].RaceName == raceName then
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
local function HasOpenedRace(citizenId)
|
||
|
|
for _, v in pairs(AvailableRaces) do
|
||
|
|
if v.SetupCitizenId == citizenId then
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
local function GetOpenedRaceKey(raceId)
|
||
|
|
for k, v in pairs(AvailableRaces) do
|
||
|
|
if v.RaceId == raceId then
|
||
|
|
return k
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function GetCurrentRace(citizenId)
|
||
|
|
for raceId in pairs(Races) do
|
||
|
|
for cid in pairs(Races[raceId].Racers) do
|
||
|
|
if cid == citizenId then
|
||
|
|
return raceId
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function GetRaceId(name)
|
||
|
|
for k, v in pairs(Races) do
|
||
|
|
if v.RaceName == name then
|
||
|
|
return k
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function GenerateRaceId()
|
||
|
|
local raceId = "LR-" .. math.random(0, 9999999)
|
||
|
|
while Races[raceId] do
|
||
|
|
raceId = "LR-" .. math.random(0, 9999999)
|
||
|
|
end
|
||
|
|
return raceId
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Events
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:FinishPlayer', function(RaceData, TotalTime, TotalLaps, BestLap)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(src)
|
||
|
|
local AvailableKey = GetOpenedRaceKey(RaceData.RaceId)
|
||
|
|
local PlayersFinished = 0
|
||
|
|
local AmountOfRacers = 0
|
||
|
|
|
||
|
|
for _, v in pairs(Races[RaceData.RaceId].Racers) do
|
||
|
|
if v.Finished then
|
||
|
|
PlayersFinished += 1
|
||
|
|
end
|
||
|
|
AmountOfRacers += 1
|
||
|
|
end
|
||
|
|
|
||
|
|
BestLap = TotalLaps < 2 and TotalTime or BestLap
|
||
|
|
if LastRaces[RaceData.RaceId] then
|
||
|
|
LastRaces[RaceData.RaceId][#LastRaces[RaceData.RaceId] + 1] = {
|
||
|
|
TotalTime = TotalTime,
|
||
|
|
BestLap = BestLap,
|
||
|
|
Holder = {
|
||
|
|
Player.PlayerData.charinfo.firstname,
|
||
|
|
Player.PlayerData.charinfo.lastname
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
LastRaces[RaceData.RaceId] = {}
|
||
|
|
LastRaces[RaceData.RaceId][#LastRaces[RaceData.RaceId] + 1] = {
|
||
|
|
TotalTime = TotalTime,
|
||
|
|
BestLap = BestLap,
|
||
|
|
Holder = {
|
||
|
|
Player.PlayerData.charinfo.firstname,
|
||
|
|
Player.PlayerData.charinfo.lastname
|
||
|
|
}
|
||
|
|
}
|
||
|
|
end
|
||
|
|
if Races[RaceData.RaceId].Records and table.type(Races[RaceData.RaceId].Records) ~= 'empty' then
|
||
|
|
if BestLap < Races[RaceData.RaceId].Records.Time then
|
||
|
|
Races[RaceData.RaceId].Records = {
|
||
|
|
Time = BestLap,
|
||
|
|
Holder = {
|
||
|
|
Player.PlayerData.charinfo.firstname,
|
||
|
|
Player.PlayerData.charinfo.lastname
|
||
|
|
}
|
||
|
|
}
|
||
|
|
MySQL.update('UPDATE lapraces SET records = ? WHERE raceid = ?', {json.encode(Races[RaceData.RaceId].Records), RaceData.RaceId})
|
||
|
|
TriggerClientEvent('qb-phone:client:RaceNotify', src, locale('phonenotif.wonWR', RaceData.RaceName, SecondsToClock(BestLap)))
|
||
|
|
end
|
||
|
|
else
|
||
|
|
Races[RaceData.RaceId].Records = {
|
||
|
|
Time = BestLap,
|
||
|
|
Holder = {
|
||
|
|
Player.PlayerData.charinfo.firstname,
|
||
|
|
Player.PlayerData.charinfo.lastname
|
||
|
|
}
|
||
|
|
}
|
||
|
|
MySQL.update('UPDATE lapraces SET records = ? WHERE raceid = ?', {json.encode(Races[RaceData.RaceId].Records), RaceData.RaceId})
|
||
|
|
TriggerClientEvent('qb-phone:client:RaceNotify', src, locale('phonenotif.wonWR2', RaceData.RaceName, SecondsToClock(BestLap)))
|
||
|
|
end
|
||
|
|
AvailableRaces[AvailableKey].RaceData = Races[RaceData.RaceId]
|
||
|
|
TriggerClientEvent('qb-lapraces:client:PlayerFinishs', -1, RaceData.RaceId, PlayersFinished, Player)
|
||
|
|
if PlayersFinished == AmountOfRacers then
|
||
|
|
if NotFinished and table.type(NotFinished) ~= 'empty' and NotFinished[RaceData.RaceId] and table.type(NotFinished[RaceData.RaceId]) ~= 'empty' then
|
||
|
|
for _, v in pairs(NotFinished[RaceData.RaceId]) do
|
||
|
|
LastRaces[RaceData.RaceId][#LastRaces[RaceData.RaceId] + 1] = {
|
||
|
|
TotalTime = v.TotalTime,
|
||
|
|
BestLap = v.BestLap,
|
||
|
|
Holder = v.Holder
|
||
|
|
}
|
||
|
|
end
|
||
|
|
end
|
||
|
|
Races[RaceData.RaceId].LastLeaderboard = LastRaces[RaceData.RaceId]
|
||
|
|
Races[RaceData.RaceId].Racers = {}
|
||
|
|
Races[RaceData.RaceId].Started = false
|
||
|
|
Races[RaceData.RaceId].Waiting = false
|
||
|
|
table.remove(AvailableRaces, AvailableKey)
|
||
|
|
LastRaces[RaceData.RaceId] = nil
|
||
|
|
NotFinished[RaceData.RaceId] = nil
|
||
|
|
end
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:CreateLapRace', function(RaceName)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(src)
|
||
|
|
if Player and IsWhitelisted(Player.PlayerData.citizenid) then
|
||
|
|
if IsNameAvailable(RaceName) then
|
||
|
|
TriggerClientEvent('qb-lapraces:client:StartRaceEditor', source, RaceName)
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.namealreadyused'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.notauthorized', locale('general.createraces')), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:JoinRace', function(RaceData)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(src)
|
||
|
|
local RaceId = RaceData.RaceId
|
||
|
|
local AvailableKey = GetOpenedRaceKey(RaceId)
|
||
|
|
local CurrentRace = GetCurrentRace(Player.PlayerData.citizenid)
|
||
|
|
if CurrentRace then
|
||
|
|
local AmountOfRacers = 0
|
||
|
|
local PreviousRaceKey = GetOpenedRaceKey(CurrentRace)
|
||
|
|
for _ in pairs(Races[CurrentRace].Racers) do
|
||
|
|
AmountOfRacers += 1
|
||
|
|
end
|
||
|
|
Races[CurrentRace].Racers[Player.PlayerData.citizenid] = nil
|
||
|
|
if AmountOfRacers - 1 == 0 then
|
||
|
|
Races[CurrentRace].Racers = {}
|
||
|
|
Races[CurrentRace].Started = false
|
||
|
|
Races[CurrentRace].Waiting = false
|
||
|
|
table.remove(AvailableRaces, PreviousRaceKey)
|
||
|
|
exports.qbx_core:Notify(src, locale('error.raceended'), 'error')
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', src, Races[CurrentRace])
|
||
|
|
else
|
||
|
|
AvailableRaces[PreviousRaceKey].RaceData = Races[CurrentRace]
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', src, Races[CurrentRace])
|
||
|
|
end
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
end
|
||
|
|
Races[RaceId].Waiting = true
|
||
|
|
Races[RaceId].Racers[Player.PlayerData.citizenid] = {
|
||
|
|
Checkpoint = 0,
|
||
|
|
Lap = 1,
|
||
|
|
Finished = false
|
||
|
|
}
|
||
|
|
AvailableRaces[AvailableKey].RaceData = Races[RaceId]
|
||
|
|
TriggerClientEvent('qb-lapraces:client:JoinRace', src, Races[RaceId], AvailableRaces[AvailableKey].Laps)
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
local creatorsource = exports.qbx_core:GetPlayerByCitizenId(AvailableRaces[AvailableKey].SetupCitizenId).PlayerData.source
|
||
|
|
if creatorsource ~= Player.PlayerData.source then
|
||
|
|
TriggerClientEvent('qb-phone:client:RaceNotify', creatorsource, locale('phonenotif.joinedrace',string.sub(Player.PlayerData.charinfo.firstname, 1, 1), Player.PlayerData.charinfo.lastname))
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:LeaveRace', function(RaceData)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(src)
|
||
|
|
local RaceName = RaceData.RaceData and RaceData.RaceData.RaceName or RaceData.RaceName
|
||
|
|
local RaceId = GetRaceId(RaceName)
|
||
|
|
local AvailableKey = GetOpenedRaceKey(RaceData.RaceId)
|
||
|
|
local creatorsource = exports.qbx_core:GetPlayerByCitizenId(AvailableRaces[AvailableKey].SetupCitizenId)?.PlayerData.source
|
||
|
|
if creatorsource ~= Player.PlayerData.source then
|
||
|
|
TriggerClientEvent('qb-phone:client:RaceNotify', creatorsource, locale('phonenotif.LeaveRace',string.sub(Player.PlayerData.charinfo.firstname, 1, 1), Player.PlayerData.charinfo.lastname))
|
||
|
|
end
|
||
|
|
local AmountOfRacers = 0
|
||
|
|
for _ in pairs(Races[RaceData.RaceId].Racers) do
|
||
|
|
AmountOfRacers += 1
|
||
|
|
end
|
||
|
|
if NotFinished[RaceData.RaceId] then
|
||
|
|
NotFinished[RaceData.RaceId][#NotFinished[RaceData.RaceId] + 1] = {
|
||
|
|
TotalTime = locale('general.DNF'),
|
||
|
|
BestLap = locale('general.DNF'),
|
||
|
|
Holder = {
|
||
|
|
Player.PlayerData.charinfo.firstname,
|
||
|
|
Player.PlayerData.charinfo.lastname
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
NotFinished[RaceData.RaceId] = {}
|
||
|
|
NotFinished[RaceData.RaceId][#NotFinished[RaceData.RaceId] + 1] = {
|
||
|
|
TotalTime = locale('general.DNF'),
|
||
|
|
BestLap = locale('general.DNF'),
|
||
|
|
Holder = {
|
||
|
|
Player.PlayerData.charinfo.firstname,
|
||
|
|
Player.PlayerData.charinfo.lastname
|
||
|
|
}
|
||
|
|
}
|
||
|
|
end
|
||
|
|
Races[RaceId].Racers[Player.PlayerData.citizenid] = nil
|
||
|
|
if AmountOfRacers - 1 == 0 then
|
||
|
|
if NotFinished and table.type(NotFinished) ~= 'empty' and NotFinished[RaceId] and table.type(NotFinished[RaceId]) ~= 'empty' then
|
||
|
|
for _, v in pairs(NotFinished[RaceId]) do
|
||
|
|
if LastRaces[RaceId] then
|
||
|
|
LastRaces[RaceId][#LastRaces[RaceId]+1] = {
|
||
|
|
TotalTime = v.TotalTime,
|
||
|
|
BestLap = v.BestLap,
|
||
|
|
Holder = v.Holder
|
||
|
|
}
|
||
|
|
else
|
||
|
|
LastRaces[RaceId] = {}
|
||
|
|
LastRaces[RaceId][#LastRaces[RaceId] + 1] = {
|
||
|
|
TotalTime = v.TotalTime,
|
||
|
|
BestLap = v.BestLap,
|
||
|
|
Holder = v.Holder
|
||
|
|
}
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
Races[RaceId].LastLeaderboard = LastRaces[RaceId]
|
||
|
|
Races[RaceId].Racers = {}
|
||
|
|
Races[RaceId].Started = false
|
||
|
|
Races[RaceId].Waiting = false
|
||
|
|
table.remove(AvailableRaces, AvailableKey)
|
||
|
|
exports.qbx_core:Notify(src, locale('error.raceended'), 'error')
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', src, Races[RaceId])
|
||
|
|
LastRaces[RaceId] = nil
|
||
|
|
NotFinished[RaceId] = nil
|
||
|
|
else
|
||
|
|
AvailableRaces[AvailableKey].RaceData = Races[RaceId]
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', src, Races[RaceId])
|
||
|
|
end
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:SetupRace', function(RaceId, Laps)
|
||
|
|
local Player = exports.qbx_core:GetPlayer(source)
|
||
|
|
if Races[RaceId] then
|
||
|
|
if not Races[RaceId].Waiting then
|
||
|
|
if not Races[RaceId].Started then
|
||
|
|
Races[RaceId].Waiting = true
|
||
|
|
AvailableRaces[#AvailableRaces + 1] = {
|
||
|
|
RaceData = Races[RaceId],
|
||
|
|
Laps = Laps,
|
||
|
|
RaceId = RaceId,
|
||
|
|
SetupCitizenId = Player.PlayerData.citizenid
|
||
|
|
}
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
SetTimeout(5 * 60 * 1000, function()
|
||
|
|
if Races[RaceId].Waiting then
|
||
|
|
local AvailableKey = GetOpenedRaceKey(RaceId)
|
||
|
|
for cid in pairs(Races[RaceId].Racers) do
|
||
|
|
local RacerData = exports.qbx_core:GetPlayerByCitizenId(cid)
|
||
|
|
if RacerData then
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', RacerData.PlayerData.source, Races[RaceId])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
table.remove(AvailableRaces, AvailableKey)
|
||
|
|
Races[RaceId].LastLeaderboard = {}
|
||
|
|
Races[RaceId].Racers = {}
|
||
|
|
Races[RaceId].Started = false
|
||
|
|
Races[RaceId].Waiting = false
|
||
|
|
LastRaces[RaceId] = nil
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.alreadyrunning'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.alreadyrunning'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.notexist'), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:CancelRace', function(raceId)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(source)
|
||
|
|
local AvailableKey = GetOpenedRaceKey(raceId)
|
||
|
|
|
||
|
|
exports.qbx_core:Notify(src, locale('error.stoppingrace',raceId), 'error')
|
||
|
|
|
||
|
|
if AvailableKey then
|
||
|
|
if AvailableRaces[AvailableKey].SetupCitizenId == Player.PlayerData.citizenid then
|
||
|
|
for cid in pairs(Races[raceId].Racers) do
|
||
|
|
local RacerData = exports.qbx_core:GetPlayerByCitizenId(cid)
|
||
|
|
if RacerData then
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', RacerData.PlayerData.source, Races[raceId])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
table.remove(AvailableRaces, AvailableKey)
|
||
|
|
Races[raceId].LastLeaderboard = {}
|
||
|
|
Races[raceId].Racers = {}
|
||
|
|
Races[raceId].Started = false
|
||
|
|
Races[raceId].Waiting = false
|
||
|
|
LastRaces[raceId] = nil
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(src, locale('error.racenotopen', raceId), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:UpdateRaceState', function(RaceId, Started, Waiting)
|
||
|
|
Races[RaceId].Waiting = Waiting
|
||
|
|
Races[RaceId].Started = Started
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:UpdateRacerData', function(RaceId, Checkpoint, Lap, Finished)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(src)
|
||
|
|
local CitizenId = Player.PlayerData.citizenid
|
||
|
|
|
||
|
|
Races[RaceId].Racers[CitizenId].Checkpoint = Checkpoint
|
||
|
|
Races[RaceId].Racers[CitizenId].Lap = Lap
|
||
|
|
Races[RaceId].Racers[CitizenId].Finished = Finished
|
||
|
|
|
||
|
|
TriggerClientEvent('qb-lapraces:client:UpdateRaceRacerData', -1, RaceId, Races[RaceId])
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:StartRace', function(RaceId)
|
||
|
|
local src = source
|
||
|
|
local MyPlayer = exports.qbx_core:GetPlayer(src)
|
||
|
|
local AvailableKey = GetOpenedRaceKey(RaceId)
|
||
|
|
|
||
|
|
if RaceId then
|
||
|
|
if AvailableRaces[AvailableKey].SetupCitizenId == MyPlayer.PlayerData.citizenid then
|
||
|
|
AvailableRaces[AvailableKey].RaceData.Started = true
|
||
|
|
AvailableRaces[AvailableKey].RaceData.Waiting = false
|
||
|
|
for CitizenId in pairs(Races[RaceId].Racers) do
|
||
|
|
local Player = exports.qbx_core:GetPlayerByCitizenId(CitizenId)
|
||
|
|
if Player then
|
||
|
|
TriggerClientEvent('qb-lapraces:client:RaceCountdown', Player.PlayerData.source)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(src, locale('error.notcreator'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(src, locale('error.notinarace'), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-lapraces:server:SaveRace', function(RaceData)
|
||
|
|
local src = source
|
||
|
|
local Player = exports.qbx_core:GetPlayer(src)
|
||
|
|
local RaceId = GenerateRaceId()
|
||
|
|
local Checkpoints = {}
|
||
|
|
for k, v in pairs(RaceData.Checkpoints) do
|
||
|
|
Checkpoints[k] = {
|
||
|
|
offset = v.offset,
|
||
|
|
coords = v.coords
|
||
|
|
}
|
||
|
|
end
|
||
|
|
Races[RaceId] = {
|
||
|
|
RaceName = RaceData.RaceName,
|
||
|
|
Checkpoints = Checkpoints,
|
||
|
|
Records = {},
|
||
|
|
Creator = Player.PlayerData.citizenid,
|
||
|
|
RaceId = RaceId,
|
||
|
|
Started = false,
|
||
|
|
Waiting = false,
|
||
|
|
Distance = math.ceil(RaceData.RaceDistance),
|
||
|
|
Racers = {},
|
||
|
|
LastLeaderboard = {}
|
||
|
|
}
|
||
|
|
MySQL.insert('INSERT INTO lapraces (name, checkpoints, creator, distance, raceid) VALUES (?, ?, ?, ?, ?)', {RaceData.RaceName, json.encode(Checkpoints), Player.PlayerData.citizenid, RaceData.RaceDistance, GenerateRaceId()})
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- Callbacks
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:GetRacingLeaderboards', function()
|
||
|
|
return Races
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:GetRaces', function()
|
||
|
|
return AvailableRaces
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:GetListedRaces', function()
|
||
|
|
return Races
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:GetRacingData', function(_, RaceId)
|
||
|
|
return Races[RaceId]
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:HasCreatedRace', function(source)
|
||
|
|
return HasOpenedRace(exports.qbx_core:GetPlayer(source).PlayerData.citizenid)
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:IsAuthorizedToCreateRaces', function(source, TrackName)
|
||
|
|
return IsWhitelisted(exports.qbx_core:GetPlayer(source).PlayerData.citizenid), IsNameAvailable(TrackName)
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:CanRaceSetup', function(_, cb)
|
||
|
|
return Config.RaceSetupAllowed
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.callback.register('qb-lapraces:server:GetTrackData', function(_, RaceId)
|
||
|
|
local result = MySQL.query.await('SELECT * FROM players WHERE citizenid = ?', {Races[RaceId].Creator})
|
||
|
|
if result and result[1] then
|
||
|
|
result[1].charinfo = json.decode(result[1].charinfo)
|
||
|
|
return Races[RaceId], result[1]
|
||
|
|
end
|
||
|
|
|
||
|
|
return Races[RaceId], {
|
||
|
|
charinfo = {
|
||
|
|
firstname = locale('general.unknown'),
|
||
|
|
lastname = locale('general.unknown')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- Commands
|
||
|
|
|
||
|
|
lib.addCommand('cancelrace', {help = locale('commands.cancelrace')}, function(source, args)
|
||
|
|
local Player = exports.qbx_core:GetPlayer(source)
|
||
|
|
|
||
|
|
if IsWhitelisted(Player.PlayerData.citizenid) then
|
||
|
|
local RaceName = table.concat(args, " ")
|
||
|
|
if RaceName then
|
||
|
|
local RaceId = GetRaceId(RaceName)
|
||
|
|
if Races[RaceId].Started then
|
||
|
|
local AvailableKey = GetOpenedRaceKey(RaceId)
|
||
|
|
for cid in pairs(Races[RaceId].Racers) do
|
||
|
|
local RacerData = exports.qbx_core:GetPlayerByCitizenId(cid)
|
||
|
|
if RacerData then
|
||
|
|
TriggerClientEvent('qb-lapraces:client:LeaveRace', RacerData.PlayerData.source, Races[RaceId])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
table.remove(AvailableRaces, AvailableKey)
|
||
|
|
Races[RaceId].LastLeaderboard = {}
|
||
|
|
Races[RaceId].Racers = {}
|
||
|
|
Races[RaceId].Started = false
|
||
|
|
Races[RaceId].Waiting = false
|
||
|
|
LastRaces[RaceId] = nil
|
||
|
|
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.notstarted'), 'error')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.notauthorized', locale('general.dothis')), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
lib.addCommand('togglesetup', {help = locale('commands.togglesetup')}, function(source)
|
||
|
|
local Player = exports.qbx_core:GetPlayer(source)
|
||
|
|
if IsWhitelisted(Player.PlayerData.citizenid) then
|
||
|
|
Config.RaceSetupAllowed = not Config.RaceSetupAllowed
|
||
|
|
if not Config.RaceSetupAllowed then
|
||
|
|
exports.qbx_core:Notify(source, locale('error.nomoreraces'), 'error')
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('success.cancreate'), 'success')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(source, locale('error.notauthorized', locale('general.dothis')), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- Threads
|
||
|
|
|
||
|
|
CreateThread(function()
|
||
|
|
local races = MySQL.query.await('SELECT * FROM lapraces', {})
|
||
|
|
if races and races[1] then
|
||
|
|
for _, v in pairs(races) do
|
||
|
|
local Records = v.records and json.decode(v.records) or {}
|
||
|
|
Races[v.raceid] = {
|
||
|
|
RaceName = v.name,
|
||
|
|
Checkpoints = json.decode(v.checkpoints),
|
||
|
|
Records = Records,
|
||
|
|
Creator = v.creator,
|
||
|
|
RaceId = v.raceid,
|
||
|
|
Started = false,
|
||
|
|
Waiting = false,
|
||
|
|
Distance = v.distance,
|
||
|
|
LastLeaderboard = {},
|
||
|
|
Racers = {}
|
||
|
|
}
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|