1
0
Fork 0
forked from Simnation/Main
Main/resources/[qb]/qb-lapraces/server/main.lua

600 lines
22 KiB
Lua
Raw Normal View History

2025-06-07 08:51:21 +02:00
local QBCore = exports['qb-core']:GetCoreObject()
local Races = {}
local AvailableRaces = {}
local LastRaces = {}
local NotFinished = {}
-- Functions
local function SecondsToClock(seconds)
seconds = tonumber(seconds)
local retval
if seconds <= 0 then
retval = "00:00:00";
else
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));
retval = hours .. ":" .. mins .. ":" .. secs
end
return retval
end
local function IsWhitelisted(CitizenId)
local retval = false
for _, cid in pairs(Config.WhitelistedCreators) do
if cid == CitizenId then
retval = true
break
end
end
local Player = QBCore.Functions.GetPlayerByCitizenId(CitizenId)
local Perms = QBCore.Functions.GetPermission(Player.PlayerData.source)
if Perms == "admin" or Perms == "god" then
retval = true
end
return retval
end
local function IsNameAvailable(RaceName)
local retval = true
for RaceId, _ in pairs(Races) do
if Races[RaceId].RaceName == RaceName then
retval = false
break
end
end
return retval
end
local function HasOpenedRace(CitizenId)
local retval = false
for _, v in pairs(AvailableRaces) do
if v.SetupCitizenId == CitizenId then
retval = true
end
end
return retval
end
local function GetOpenedRaceKey(RaceId)
local retval = nil
for k, v in pairs(AvailableRaces) do
if v.RaceId == RaceId then
retval = k
break
end
end
return retval
end
local function GetCurrentRace(MyCitizenId)
local retval = nil
for RaceId, _ in pairs(Races) do
for cid, _ in pairs(Races[RaceId].Racers) do
if cid == MyCitizenId then
retval = RaceId
break
end
end
end
return retval
end
local function GetRaceId(name)
local retval = nil
for k, v in pairs(Races) do
if v.RaceName == name then
retval = k
break
end
end
return retval
end
local function GenerateRaceId()
local RaceId = "LR-" .. math.random(1111, 9999)
while Races[RaceId] ~= nil do
RaceId = "LR-" .. math.random(1111, 9999)
end
return RaceId
end
-- Events
RegisterNetEvent('qb-lapraces:server:FinishPlayer', function(RaceData, TotalTime, TotalLaps, BestLap)
local src = source
local Player = QBCore.Functions.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 = PlayersFinished + 1
end
AmountOfRacers = AmountOfRacers + 1
end
local BLap
if TotalLaps < 2 then
BLap = TotalTime
else
BLap = BestLap
end
if LastRaces[RaceData.RaceId] ~= nil then
LastRaces[RaceData.RaceId][#LastRaces[RaceData.RaceId]+1] = {
TotalTime = TotalTime,
BestLap = BLap,
Holder = {
[1] = Player.PlayerData.charinfo.firstname,
[2] = Player.PlayerData.charinfo.lastname
}
}
else
LastRaces[RaceData.RaceId] = {}
LastRaces[RaceData.RaceId][#LastRaces[RaceData.RaceId]+1] = {
TotalTime = TotalTime,
BestLap = BLap,
Holder = {
[1] = Player.PlayerData.charinfo.firstname,
[2] = Player.PlayerData.charinfo.lastname
}
}
end
if Races[RaceData.RaceId].Records ~= nil and next(Races[RaceData.RaceId].Records) ~= nil then
if BLap < Races[RaceData.RaceId].Records.Time then
Races[RaceData.RaceId].Records = {
Time = BLap,
Holder = {
[1] = Player.PlayerData.charinfo.firstname,
[2] = 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, 'You have won the WR from ' .. RaceData.RaceName ..
' disconnected with a time of: ' .. SecondsToClock(BLap) .. '!')
end
else
Races[RaceData.RaceId].Records = {
Time = BLap,
Holder = {
[1] = Player.PlayerData.charinfo.firstname,
[2] = 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, 'You have won the WR from ' .. RaceData.RaceName ..
' put down with a time of: ' .. SecondsToClock(BLap) .. '!')
end
AvailableRaces[AvailableKey].RaceData = Races[RaceData.RaceId]
TriggerClientEvent('qb-lapraces:client:PlayerFinishs', -1, RaceData.RaceId, PlayersFinished, Player)
if PlayersFinished == AmountOfRacers then
if NotFinished ~= nil and next(NotFinished) ~= nil and NotFinished[RaceData.RaceId] ~= nil and
next(NotFinished[RaceData.RaceId]) ~= nil then
for _, v in pairs(NotFinished[RaceData.RaceId]) do
LastRaces[RaceData.RaceId][#LastRaces[RaceData.RaceId]+1] = {
TotalTime = v.TotalTime,
BestLap = v.BestLap,
Holder = {
[1] = v.Holder[1],
[2] = v.Holder[2]
}
}
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 = QBCore.Functions.GetPlayer(src)
if IsWhitelisted(Player.PlayerData.citizenid) then
if IsNameAvailable(RaceName) then
TriggerClientEvent('qb-lapraces:client:StartRaceEditor', source, RaceName)
else
TriggerClientEvent('QBCore:Notify', source, 'There is already a race with this name.', 'error')
end
else
TriggerClientEvent('QBCore:Notify', source, 'You have not been authorized to race\'s to create.', 'error')
end
end)
RegisterNetEvent('qb-lapraces:server:JoinRace', function(RaceData)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
local RaceId = RaceData.RaceId
local AvailableKey = GetOpenedRaceKey(RaceId)
local CurrentRace = GetCurrentRace(Player.PlayerData.citizenid)
if CurrentRace ~= nil then
local AmountOfRacers = 0
local PreviousRaceKey = GetOpenedRaceKey(CurrentRace)
for _, _ in pairs(Races[CurrentRace].Racers) do
AmountOfRacers = 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)
TriggerClientEvent('QBCore:Notify', src, 'You were the only one in the race, the race had ended', '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 = QBCore.Functions.GetPlayerByCitizenId(AvailableRaces[AvailableKey].SetupCitizenId).PlayerData
.source
if creatorsource ~= Player.PlayerData.source then
TriggerClientEvent('qb-phone:client:RaceNotify', creatorsource,
string.sub(Player.PlayerData.charinfo.firstname, 1, 1) .. '. ' .. Player.PlayerData.charinfo.lastname ..
' the race has been joined!')
end
end)
RegisterNetEvent('qb-lapraces:server:LeaveRace', function(RaceData)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
local RaceName
if RaceData.RaceData ~= nil then
RaceName = RaceData.RaceData.RaceName
else
RaceName = RaceData.RaceName
end
local RaceId = GetRaceId(RaceName)
local AvailableKey = GetOpenedRaceKey(RaceData.RaceId)
local creatorsource = QBCore.Functions.GetPlayerByCitizenId(AvailableRaces[AvailableKey].SetupCitizenId).PlayerData
.source
if creatorsource ~= Player.PlayerData.source then
TriggerClientEvent('qb-phone:client:RaceNotify', creatorsource,
string.sub(Player.PlayerData.charinfo.firstname, 1, 1) .. '. ' .. Player.PlayerData.charinfo.lastname ..
' the race has been delivered!')
end
local AmountOfRacers = 0
for _, _ in pairs(Races[RaceData.RaceId].Racers) do
AmountOfRacers = AmountOfRacers + 1
end
if NotFinished[RaceData.RaceId] ~= nil then
NotFinished[RaceData.RaceId][#NotFinished[RaceData.RaceId]+1] = {
TotalTime = "DNF",
BestLap = "DNF",
Holder = {
[1] = Player.PlayerData.charinfo.firstname,
[2] = Player.PlayerData.charinfo.lastname
}
}
else
NotFinished[RaceData.RaceId] = {}
NotFinished[RaceData.RaceId][#NotFinished[RaceData.RaceId]+1] = {
TotalTime = "DNF",
BestLap = "DNF",
Holder = {
[1] = Player.PlayerData.charinfo.firstname,
[2] = Player.PlayerData.charinfo.lastname
}
}
end
Races[RaceId].Racers[Player.PlayerData.citizenid] = nil
if (AmountOfRacers - 1) == 0 then
if NotFinished ~= nil and next(NotFinished) ~= nil and NotFinished[RaceId] ~= nil and next(NotFinished[RaceId]) ~=
nil then
for _, v in pairs(NotFinished[RaceId]) do
if LastRaces[RaceId] ~= nil then
LastRaces[RaceId][#LastRaces[RaceId]+1] = {
TotalTime = v.TotalTime,
BestLap = v.BestLap,
Holder = {
[1] = v.Holder[1],
[2] = v.Holder[2]
}
}
else
LastRaces[RaceId] = {}
LastRaces[RaceId][#LastRaces[RaceId]+1] = {
TotalTime = v.TotalTime,
BestLap = v.BestLap,
Holder = {
[1] = v.Holder[1],
[2] = v.Holder[2]
}
}
end
end
end
Races[RaceId].LastLeaderboard = LastRaces[RaceId]
Races[RaceId].Racers = {}
Races[RaceId].Started = false
Races[RaceId].Waiting = false
table.remove(AvailableRaces, AvailableKey)
TriggerClientEvent('QBCore:Notify', src, 'You were the only one in the race.The race had ended.', '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 = QBCore.Functions.GetPlayer(source)
if Races[RaceId] ~= nil 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 = QBCore.Functions.GetPlayerByCitizenId(cid)
if RacerData ~= nil 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
TriggerClientEvent('QBCore:Notify', source, 'The race is already running', 'error')
end
else
TriggerClientEvent('QBCore:Notify', source, 'The race is already running', 'error')
end
else
TriggerClientEvent('QBCore:Notify', source, 'This race does not exist :(', 'error')
end
end)
RegisterNetEvent('qb-lapraces:server:CancelRace', function(raceId)
local src = source
local Player = QBCore.Functions.GetPlayer(source)
local AvailableKey = GetOpenedRaceKey(raceId)
TriggerClientEvent('QBCore:Notify', src, 'Stopping the race: ' .. raceId, 'error')
if AvailableKey ~= nil then
if AvailableRaces[AvailableKey].SetupCitizenId == Player.PlayerData.citizenid then
for cid, _ in pairs(Races[raceId].Racers) do
local RacerData = QBCore.Functions.GetPlayerByCitizenId(cid)
if RacerData ~= nil 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
TriggerClientEvent('QBCore:Notify', src, 'Race not open: ' .. 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 = QBCore.Functions.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 = QBCore.Functions.GetPlayer(src)
local AvailableKey = GetOpenedRaceKey(RaceId)
if RaceId ~= nil 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 = QBCore.Functions.GetPlayerByCitizenId(CitizenId)
if Player ~= nil then
TriggerClientEvent('qb-lapraces:client:RaceCountdown', Player.PlayerData.source)
end
end
TriggerClientEvent('qb-phone:client:UpdateLapraces', -1)
else
TriggerClientEvent('QBCore:Notify', src, 'You are not the creator of the race..', 'error')
end
else
TriggerClientEvent('QBCore:Notify', src, 'You are not in a race..', 'error')
end
end)
RegisterNetEvent('qb-lapraces:server:SaveRace', function(RaceData)
local src = source
local Player = QBCore.Functions.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
QBCore.Functions.CreateCallback('qb-lapraces:server:GetRacingLeaderboards', function(_, cb)
cb(Races)
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:GetRaces', function(_, cb)
cb(AvailableRaces)
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:GetListedRaces', function(_, cb)
cb(Races)
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:GetRacingData', function(_, cb, RaceId)
cb(Races[RaceId])
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:HasCreatedRace', function(source, cb)
cb(HasOpenedRace(QBCore.Functions.GetPlayer(source).PlayerData.citizenid))
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:IsAuthorizedToCreateRaces', function(source, cb, TrackName)
cb(IsWhitelisted(QBCore.Functions.GetPlayer(source).PlayerData.citizenid), IsNameAvailable(TrackName))
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:CanRaceSetup', function(_, cb)
cb(Config.RaceSetupAllowed)
end)
QBCore.Functions.CreateCallback('qb-lapraces:server:GetTrackData', function(_, cb, RaceId)
local result = MySQL.query.await('SELECT * FROM players WHERE citizenid = ?', {Races[RaceId].Creator})
if result[1] ~= nil then
result[1].charinfo = json.decode(result[1].charinfo)
cb(Races[RaceId], result[1])
else
cb(Races[RaceId], {
charinfo = {
firstname = "Unknown",
lastname = "Unknown"
}
})
end
end)
-- Commands
QBCore.Commands.Add("cancelrace", "Cancel going race..", {}, false, function(source, args)
local Player = QBCore.Functions.GetPlayer(source)
if IsWhitelisted(Player.PlayerData.citizenid) then
local RaceName = table.concat(args, " ")
if RaceName ~= nil then
local RaceId = GetRaceId(RaceName)
if Races[RaceId].Started then
local AvailableKey = GetOpenedRaceKey(RaceId)
for cid, _ in pairs(Races[RaceId].Racers) do
local RacerData = QBCore.Functions.GetPlayerByCitizenId(cid)
if RacerData ~= nil 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
TriggerClientEvent('QBCore:Notify', source, 'This race has not started yet.', 'error')
end
end
else
TriggerClientEvent('QBCore:Notify', source, 'You have not been authorized to do this.', 'error')
end
end)
QBCore.Commands.Add("togglesetup", "Turn on / off racing setup", {}, false, function(source, _)
local Player = QBCore.Functions.GetPlayer(source)
if IsWhitelisted(Player.PlayerData.citizenid) then
Config.RaceSetupAllowed = not Config.RaceSetupAllowed
if not Config.RaceSetupAllowed then
TriggerClientEvent('QBCore:Notify', source, 'No more races can be created!', 'error')
else
TriggerClientEvent('QBCore:Notify', source, 'Races can be created again!', 'success')
end
else
TriggerClientEvent('QBCore:Notify', source, 'You have not been authorized to do this.', 'error')
end
end)
-- Threads
CreateThread(function()
local races = MySQL.query.await('SELECT * FROM lapraces', {})
if races[1] ~= nil then
for _, v in pairs(races) do
local Records = {}
if v.records ~= nil then
Records = json.decode(v.records)
end
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)