All of your functions are getMoney.
You literally have no removeMoney, nor addMoney. Just use this (replace everything):
ESX = nil
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
-- Helper function for getting player money
function getMoney(source)
local xPlayer = ESX.GetPlayerFromId(source)
local getmoney = xPlayer.getMoney()
return getmoney
end
-- Helper function for removing player money
function removeMoney(source, amount)
local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.removeMoney(amount)
end
-- Helper function for adding player money
function addMoney(source, amount)
local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.addMoney(amount)
end
-- Helper function for getting player name
function getName(source)
return GetPlayerName(source)
end
-- Helper function for notifying players
function notifyPlayer(source, msg)
TriggerClientEvent('chatMessage', source, "[RACE]", {255,64,64}, msg)
end
LOL derrrr, thank you so much, and i feel dumb now, haha. iâve been staring at different scripts for a few hours now, my brain just did not see that.
Why checkpoints can only be placed on highways, away from highways or other places, it will not be able to place checkpoints, the latest version has been used.
A new version is available with commands to save and load recorded checkpoints. The default implementation provided in port_sv.lua stores data in a JSON file on the server but can be modified to use a database if desired.
With the latest version you can modify lines 318-321 to the following which will disable using path nodes for checkpoints. It will still work for street races however without it itâs very easy to have checkpoints placed in weird spots.
-- Get closest vehicle node to waypoint coordinates and remove waypoint
local waypointCoords = GetBlipInfoIdCoord(GetFirstBlipInfoId(8))
local temp, zCoord = GetGroundZFor_3dCoord(waypointCoords.x, waypointCoords.y, 0.0, 1)
local coords = vector3(waypointCoords.x, waypointCoords.y, zCoord)
SetWaypointOff()
Iâll look into adding an optional argument for /race record to enable/disable using path nodes for recording so you donât need to edit the code.
Can you provide some more details on the exact case that causes this issue? If you create a race as the only player do you still get the error?
Just looking at the code I think the only way you could hit that error is if a race was created and the coordinates of the player who created it were nil (since everything just gets passed through and the server doesnât modify them)
local startCoords = GetEntityCoords(GetPlayerPed(-1))
The code to get the coords is pretty straight forward so Iâm surprised youâre having an issue (I havenât seen this error not anyone else so far). Are you sure youâre using the latest version and havenât changed any files other than port_sv.lua?
Are you able to create races using the original port_sv file? Are there any errors output in the server console? Try replacing your races_cl.lua file with this version and copy/capture the error and print statements.
-- DEFINITIONS AND CONSTANTS
local RACE_STATE_NONE = 0
local RACE_STATE_JOINED = 1
local RACE_STATE_RACING = 2
local RACE_STATE_RECORDING = 3
local RACE_CHECKPOINT_TYPE = 45
local RACE_CHECKPOINT_FINISH_TYPE = 9
-- Races and race status
local races = {}
local raceStatus = {
state = RACE_STATE_NONE,
index = 0,
checkpoint = 0
}
-- Recorded checkpoints
local recordedCheckpoints = {}
-- Main command for races
RegisterCommand("race", function(source, args)
if args[1] == "clear" or args[1] == "leave" then
-- If player is part of a race, clean up map and send leave event to server
if raceStatus.state == RACE_STATE_JOINED or raceStatus.state == RACE_STATE_RACING then
cleanupRace()
TriggerServerEvent('StreetRaces:leaveRace_sv', raceStatus.index)
end
-- Reset state
raceStatus.index = 0
raceStatus.checkpoint = 0
raceStatus.state = RACE_STATE_NONE
elseif args[1] == "record" then
-- Clear waypoint, cleanup recording and set flag to start recording
SetWaypointOff()
cleanupRecording()
raceStatus.state = RACE_STATE_RECORDING
elseif args[1] == "save" then
-- Check name was provided and checkpoints are recorded
local name = args[2]
if name ~= nil and #recordedCheckpoints > 0 then
-- Send event to server to save checkpoints
TriggerServerEvent('StreetRaces:saveRace_sv', name, recordedCheckpoints)
end
elseif args[1] == "delete" then
-- Check name was provided and send event to server to delete saved race
local name = args[2]
if name ~= nil then
TriggerServerEvent('StreetRaces:deleteRace_sv', name)
end
elseif args[1] == "list" then
-- Send event to server to list saved races
TriggerServerEvent('StreetRaces:listRaces_sv')
elseif args[1] == "load" then
-- Check name was provided and send event to server to load saved race
local name = args[2]
if name ~= nil then
TriggerServerEvent('StreetRaces:loadRace_sv', name)
end
elseif args[1] == "start" then
-- Parse arguments and create race
local amount = tonumber(args[2])
if amount then
-- Get optional start delay argument and starting coordinates
local startDelay = tonumber(args[3])
startDelay = startDelay and startDelay*1000 or config_cl.joinDuration
local startCoords = GetEntityCoords(GetPlayerPed(-1))
-- Create a race using checkpoints or waypoint if none set
if #recordedCheckpoints > 0 then
-- Create race using custom checkpoints
TriggerServerEvent('StreetRaces:createRace_sv', amount, startDelay, startCoords, recordedCheckpoints)
elseif IsWaypointActive() then
-- Create race using waypoint as the only checkpoint
local waypointCoords = GetBlipInfoIdCoord(GetFirstBlipInfoId(8))
local retval, nodeCoords = GetClosestVehicleNode(waypointCoords.x, waypointCoords.y, waypointCoords.z, 1)
table.insert(recordedCheckpoints, {blip = nil, coords = nodeCoords})
TriggerServerEvent('StreetRaces:createRace_sv', amount, startDelay, startCoords, recordedCheckpoints)
end
-- DEBUG PRINT
print(("[StreetRaces]/race start\n" ..
"amount = %d\n" ..
"startDelay = %d\n" ..
"startCoords = %f, %f, %f\n" ..
"#recordedCheckpoints = %d"):format(amount, startDelay, startCoords.x, startCoords.y, startCoords.z, #recordedCheckpoints))
-- Set state to none to cleanup recording blips while waiting to join
raceStatus.state = RACE_STATE_NONE
end
elseif args[1] == "cancel" then
-- Send cancel event to server
TriggerServerEvent('StreetRaces:cancelRace_sv')
else
return
end
end)
-- Client event for when a race is created
RegisterNetEvent("StreetRaces:createRace_cl")
AddEventHandler("StreetRaces:createRace_cl", function(index, amount, startDelay, startCoords, checkpoints)
-- Create race struct and add to array
local race = {
amount = amount,
started = false,
startTime = GetGameTimer() + startDelay,
startCoords = startCoords,
checkpoints = checkpoints
}
races[index] = race
-- DEBUG PRINT
print(("[StreetRaces]createRace_cl\n" ..
"amount = %d\n" ..
"startDelay = %d\n" ..
"startCoords = %f, %f, %f\n" ..
"#checkpoints = %d"):format(amount, startDelay, startCoords.x, startCoords.y, startCoords.z, #checkpoints))
end)
-- Client event for loading a race
RegisterNetEvent("StreetRaces:loadRace_cl")
AddEventHandler("StreetRaces:loadRace_cl", function(checkpoints)
-- Cleanup recording, save checkpoints and set state to recording
cleanupRecording()
recordedCheckpoints = checkpoints
raceStatus.state = RACE_STATE_RECORDING
-- Add map blips
for index, checkpoint in pairs(recordedCheckpoints) do
checkpoint.blip = AddBlipForCoord(checkpoint.coords.x, checkpoint.coords.y, checkpoint.coords.z)
SetBlipColour(checkpoint.blip, config_cl.checkpointBlipColor)
SetBlipAsShortRange(checkpoint.blip, true)
ShowNumberOnBlip(checkpoint.blip, index)
end
-- Clear waypoint and add route for first checkpoint blip
SetWaypointOff()
SetBlipRoute(checkpoints[1].blip, true)
SetBlipRouteColour(checkpoints[1].blip, config_cl.checkpointBlipColor)
end)
-- Client event for when a race is joined
RegisterNetEvent("StreetRaces:joinedRace_cl")
AddEventHandler("StreetRaces:joinedRace_cl", function(index)
-- Set index and state to joined
raceStatus.index = index
raceStatus.state = RACE_STATE_JOINED
-- Add map blips
local race = races[index]
local checkpoints = race.checkpoints
for index, checkpoint in pairs(checkpoints) do
checkpoint.blip = AddBlipForCoord(checkpoint.coords.x, checkpoint.coords.y, checkpoint.coords.z)
SetBlipColour(checkpoint.blip, config_cl.checkpointBlipColor)
SetBlipAsShortRange(checkpoint.blip, true)
ShowNumberOnBlip(checkpoint.blip, index)
end
-- Clear waypoint and add route for first checkpoint blip
SetWaypointOff()
SetBlipRoute(checkpoints[1].blip, true)
SetBlipRouteColour(checkpoints[1].blip, config_cl.checkpointBlipColor)
end)
-- Client event for when a race is removed
RegisterNetEvent("StreetRaces:removeRace_cl")
AddEventHandler("StreetRaces:removeRace_cl", function(index)
-- Check if index matches active race
if index == raceStatus.index then
-- Cleanup map blips and checkpoints
cleanupRace()
-- Reset racing state
raceStatus.index = 0
raceStatus.checkpoint = 0
raceStatus.state = RACE_STATE_NONE
elseif index < raceStatus.index then
-- Decrement raceStatus.index to match new index after removing race
raceStatus.index = raceStatus.index - 1
end
-- Remove race from table
table.remove(races, index)
end)
-- Main thread
Citizen.CreateThread(function()
-- Loop forever and update every frame
while true do
Citizen.Wait(0)
-- Get player and check if they're in a vehicle
local player = GetPlayerPed(-1)
if IsPedInAnyVehicle(player, false) then
-- Get player position and vehicle
local position = GetEntityCoords(player)
local vehicle = GetVehiclePedIsIn(player, false)
-- Player is racing
if raceStatus.state == RACE_STATE_RACING then
-- Initialize first checkpoint if not set
local race = races[raceStatus.index]
if raceStatus.checkpoint == 0 then
-- Increment to first checkpoint
raceStatus.checkpoint = 1
local checkpoint = race.checkpoints[raceStatus.checkpoint]
-- Create checkpoint when enabled
if config_cl.checkpointRadius > 0 then
local checkpointType = raceStatus.checkpoint < #race.checkpoints and RACE_CHECKPOINT_TYPE or RACE_CHECKPOINT_FINISH_TYPE
checkpoint.checkpoint = CreateCheckpoint(checkpointType, checkpoint.coords.x, checkpoint.coords.y, checkpoint.coords.z, 0, 0, 0, config_cl.checkpointRadius, 255, 255, 0, 127, 0)
SetCheckpointCylinderHeight(checkpoint.checkpoint, config_cl.checkpointHeight, config_cl.checkpointHeight, config_cl.checkpointRadius)
end
-- Set blip route for navigation
SetBlipRoute(checkpoint.blip, true)
SetBlipRouteColour(checkpoint.blip, config_cl.checkpointBlipColor)
else
-- Check player distance from current checkpoint
local checkpoint = race.checkpoints[raceStatus.checkpoint]
if GetDistanceBetweenCoords(position.x, position.y, position.z, checkpoint.coords.x, checkpoint.coords.y, 0, false) < config_cl.checkpointProximity then
-- Passed the checkpoint, delete map blip and checkpoint
RemoveBlip(checkpoint.blip)
if config_cl.checkpointRadius > 0 then
DeleteCheckpoint(checkpoint.checkpoint)
end
-- Check if at finish line
if raceStatus.checkpoint == #(race.checkpoints) then
-- Play finish line sound
PlaySoundFrontend(-1, "ScreenFlash", "WastedSounds")
-- Send finish event to server
local currentTime = (GetGameTimer() - race.startTime)
TriggerServerEvent('StreetRaces:finishedRace_sv', raceStatus.index, currentTime)
-- Reset state
raceStatus.index = 0
raceStatus.state = RACE_STATE_NONE
else
-- Play checkpoint sound
PlaySoundFrontend(-1, "RACE_PLACED", "HUD_AWARDS")
-- Increment checkpoint counter and get next checkpoint
raceStatus.checkpoint = raceStatus.checkpoint + 1
local nextCheckpoint = race.checkpoints[raceStatus.checkpoint]
-- Create checkpoint when enabled
if config_cl.checkpointRadius > 0 then
local checkpointType = raceStatus.checkpoint < #race.checkpoints and RACE_CHECKPOINT_TYPE or RACE_CHECKPOINT_FINISH_TYPE
nextCheckpoint.checkpoint = CreateCheckpoint(checkpointType, nextCheckpoint.coords.x, nextCheckpoint.coords.y, nextCheckpoint.coords.z, 0, 0, 0, config_cl.checkpointRadius, 255, 255, 0, 127, 0)
SetCheckpointCylinderHeight(nextCheckpoint.checkpoint, config_cl.checkpointHeight, config_cl.checkpointHeight, config_cl.checkpointRadius)
end
-- Set blip route for navigation
SetBlipRoute(nextCheckpoint.blip, true)
SetBlipRouteColour(nextCheckpoint.blip, config_cl.checkpointBlipColor)
end
end
end
-- Draw HUD when it's enabled
if config_cl.hudEnabled then
-- Draw time and checkpoint HUD above minimap
local timeSeconds = (GetGameTimer() - race.startTime)/1000.0
local timeMinutes = math.floor(timeSeconds/60.0)
timeSeconds = timeSeconds - 60.0*timeMinutes
Draw2DText(config_cl.hudPosition.x, config_cl.hudPosition.y, ("~y~%02d:%06.3f"):format(timeMinutes, timeSeconds), 0.7)
local checkpoint = race.checkpoints[raceStatus.checkpoint]
local checkpointDist = math.floor(GetDistanceBetweenCoords(position.x, position.y, position.z, checkpoint.coords.x, checkpoint.coords.y, 0, false))
Draw2DText(config_cl.hudPosition.x, config_cl.hudPosition.y + 0.04, ("~y~CHECKPOINT %d/%d (%dm)"):format(raceStatus.checkpoint, #race.checkpoints, checkpointDist), 0.5)
end
-- Player has joined a race
elseif raceStatus.state == RACE_STATE_JOINED then
-- Check countdown to race start
local race = races[raceStatus.index]
local currentTime = GetGameTimer()
local count = race.startTime - currentTime
if count <= 0 then
-- Race started, set racing state and unfreeze vehicle position
raceStatus.state = RACE_STATE_RACING
raceStatus.checkpoint = 0
FreezeEntityPosition(vehicle, false)
elseif count <= config_cl.freezeDuration then
-- Display countdown text and freeze vehicle position
Draw2DText(0.5, 0.4, ("~y~%d"):format(math.ceil(count/1000.0)), 3.0)
FreezeEntityPosition(vehicle, true)
else
-- Draw 3D start time and join text
local temp, zCoord = GetGroundZFor_3dCoord(race.startCoords.x, race.startCoords.y, 9999.9, 1)
Draw3DText(race.startCoords.x, race.startCoords.y, zCoord+1.0, ("Race for ~g~$%d~w~ starting in ~y~%d~w~s"):format(race.amount, math.ceil(count/1000.0)))
Draw3DText(race.startCoords.x, race.startCoords.y, zCoord+0.80, "Joined")
end
-- Player is not in a race
else
-- Loop through all races
for index, race in pairs(races) do
-- Get current time and player proximity to start
local currentTime = GetGameTimer()
local proximity = GetDistanceBetweenCoords(position.x, position.y, position.z, race.startCoords.x, race.startCoords.y, race.startCoords.z, true)
-- When in proximity and race hasn't started draw 3D text and prompt to join
if proximity < config_cl.joinProximity and currentTime < race.startTime then
-- Draw 3D text
local count = math.ceil((race.startTime - currentTime)/1000.0)
local temp, zCoord = GetGroundZFor_3dCoord(race.startCoords.x, race.startCoords.y, 9999.9, 0)
Draw3DText(race.startCoords.x, race.startCoords.y, zCoord+1.0, ("Race for ~g~$%d~w~ starting in ~y~%d~w~s"):format(race.amount, count))
Draw3DText(race.startCoords.x, race.startCoords.y, zCoord+0.80, "Press [~g~E~w~] to join")
-- Check if player enters the race and send join event to server
if IsControlJustReleased(1, config_cl.joinKeybind) then
TriggerServerEvent('StreetRaces:joinRace_sv', index)
break
end
end
end
end
end
end
end)
-- Checkpoint recording thread
Citizen.CreateThread(function()
-- Loop forever and record checkpoints every 100ms
while true do
Citizen.Wait(100)
-- When recording flag is set, save checkpoints
if raceStatus.state == RACE_STATE_RECORDING then
-- Create new checkpoint when waypoint is set
if IsWaypointActive() then
-- Get closest vehicle node to waypoint coordinates and remove waypoint
local waypointCoords = GetBlipInfoIdCoord(GetFirstBlipInfoId(8))
local retval, coords = GetClosestVehicleNode(waypointCoords.x, waypointCoords.y, waypointCoords.z, 1)
SetWaypointOff()
-- Check if coordinates match any existing checkpoints
for index, checkpoint in pairs(recordedCheckpoints) do
if GetDistanceBetweenCoords(coords.x, coords.y, coords.z, checkpoint.coords.x, checkpoint.coords.y, checkpoint.coords.z, false) < 1.0 then
-- Matches existing checkpoint, remove blip and checkpoint from table
RemoveBlip(checkpoint.blip)
table.remove(recordedCheckpoints, index)
coords = nil
-- Update existing checkpoint blips
for i = index, #recordedCheckpoints do
ShowNumberOnBlip(recordedCheckpoints[i].blip, i)
end
break
end
end
-- Add new checkpoint
if (coords ~= nil) then
-- Add numbered checkpoint blip
local blip = AddBlipForCoord(coords.x, coords.y, coords.z)
SetBlipColour(blip, config_cl.checkpointBlipColor)
SetBlipAsShortRange(blip, true)
ShowNumberOnBlip(blip, #recordedCheckpoints+1)
-- Add checkpoint to array
table.insert(recordedCheckpoints, {blip = blip, coords = coords})
end
end
else
-- Not recording, do cleanup
cleanupRecording()
end
end
end)
-- Helper function to clean up race blips, checkpoints and status
function cleanupRace()
-- Cleanup active race
if raceStatus.index ~= 0 then
-- Cleanup map blips and checkpoints
local race = races[raceStatus.index]
local checkpoints = race.checkpoints
for _, checkpoint in pairs(checkpoints) do
if checkpoint.blip then
RemoveBlip(checkpoint.blip)
end
if checkpoint.checkpoint then
DeleteCheckpoint(checkpoint.checkpoint)
end
end
-- Set new waypoint to finish if racing
if raceStatus.state == RACE_STATE_RACING then
local lastCheckpoint = checkpoints[#checkpoints]
SetNewWaypoint(lastCheckpoint.coords.x, lastCheckpoint.coords.y)
end
-- Unfreeze vehicle
local vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)
FreezeEntityPosition(vehicle, false)
end
end
-- Helper function to clean up recording blips
function cleanupRecording()
-- Remove map blips and clear recorded checkpoints
for _, checkpoint in pairs(recordedCheckpoints) do
RemoveBlip(checkpoint.blip)
checkpoint.blip = nil
end
recordedCheckpoints = {}
end
-- Draw 3D text at coordinates
function Draw3DText(x, y, z, text)
-- Check if coords are visible and get 2D screen coords
local onScreen, _x, _y = World3dToScreen2d(x, y, z)
if onScreen then
-- Calculate text scale to use
local dist = GetDistanceBetweenCoords(GetGameplayCamCoords(), x, y, z, 1)
local scale = 1.8*(1/dist)*(1/GetGameplayCamFov())*100
-- Draw text on screen
SetTextScale(scale, scale)
SetTextFont(4)
SetTextProportional(1)
SetTextColour(255, 255, 255, 255)
SetTextDropShadow(0, 0, 0, 0,255)
SetTextDropShadow()
SetTextEdge(4, 0, 0, 0, 255)
SetTextOutline()
SetTextEntry("STRING")
SetTextCentre(1)
AddTextComponentString(text)
DrawText(_x, _y)
end
end
-- Draw 2D text on screen
function Draw2DText(x, y, text, scale)
-- Draw text on screen
SetTextFont(4)
SetTextProportional(7)
SetTextScale(scale, scale)
SetTextColour(255, 255, 255, 255)
SetTextDropShadow(0, 0, 0, 0,255)
SetTextDropShadow()
SetTextEdge(4, 0, 0, 0, 255)
SetTextOutline()
SetTextEntry("STRING")
AddTextComponentString(text)
DrawText(x, y)
end
You should see extra debug info in your console that looks something like this.
Yes you can use this with vRP you just need to implement a few functions in the port_sv.lua file. If you post a vRP version I can link it in my main post.
Hi,
I added ESX api into port_sv.lua but when I type the command, nothing happened. The console prints nothing about errors. I donât know how to solve this!