Fivem scripting
My code suddenly started bugging out please help

client.lua

local object_netID = nil
local objectModel = 'prop_beach_volball01'
local forwardForceIntensity = 20.0
local upwardForceIntensity = 30.0
local gamestate = {['Pickup'] = false, ['Serve'] = false, ['Playing'] = false}
local createdObject = nil
local objectThresholdZ = 0.95 -- The minimum Z-axis value to consider that the object is on the ground
local objectCoord = nil
-- resets/changes the game state
RegisterNetEvent('main-volleyball:client:changegamestate')
AddEventHandler('main-volleyball:client:changegamestate', function(tochange)
    for k, v in pairs(gamestate) do
        gamestate[k] = false
    end
    gamestate[tochange] = true
end)

local function loadModel(model)
    local modelHash = GetHashKey(model)
    RequestModel(modelHash)

    while not HasModelLoaded(modelHash) do
        Citizen.Wait(100)
    end
    return modelHash
end

local function spawn_the_ball()
    local player = PlayerPedId()
    local position = Config.ballpos
    local modelHash = loadModel(objectModel)
    createdObject = CreateObjectNoOffset(modelHash, Config.ballpos.x, Config.ballpos.y, Config.ballpos.z - 1, true, false, true) -- Use CreateObjectNoOffset and set isNetwork and netMissionEntity to true
    ActivatePhysics(createdObject)
    local object_netID = ObjToNet(createdObject)
    TriggerServerEvent('main-volleyball:setObjectNetworkID', object_netID)
    gamestate['Serve'] = true
    attachObjectToPlayerLeftHand()
end
RegisterNetEvent('main-volleyball:client:spawnball', function()
    spawn_the_ball()
end)


local function isPlayerNearObject(object, distanceThreshold)
    local playerCoords = GetEntityCoords(PlayerPedId())
    local objCoords = GetEntityCoords(object)
    local distance = #(playerCoords - objCoords)
    return distance <= distanceThreshold
end

Citizen.CreateThread(function()
    TriggerServerEvent('main-volleyball:requestObjectNetworkID')
    local lastUse = 0
    local cooldown = 2000
    while true do
        Citizen.Wait(0)
        if object_netID then
            createdObject = NetworkGetEntityFromNetworkId(object_netID)
            -- Start of Pickup GameState
            if gamestate['Pickup'] then
                if not NetworkHasControlOfEntity(createdObject) then
                    local timeout = GetGameTimer() + 2000
                    NetworkRequestControlOfEntity(createdObject)
                    while (not NetworkHasControlOfEntity(createdObject)) and (GetGameTimer() < timeout) do
                        Citizen.Wait(0)
                    end
                end
                alert('Press ~INPUT_PICKUP~ to pickup the ball')

                if IsControlJustReleased(0, 38) and isPlayerNearObject(createdObject, 1.5) then
                    TriggerEvent('main-volleyball:client:animation', 'random@domestic', 'pickup_low', 3.0)
                    Citizen.Wait(1000)
                    attachObjectToPlayerLeftHand()
                    gamestate['Pickup'] = false
                    gamestate['Serve'] = true
                end
            end
            -- End of Pickup Gamestate

            -- Start of Serve Gamestate
            if gamestate['Serve'] then
                alert('Press ~INPUT_DETONATE~ to serve')
                if IsControlJustReleased(0, 47) then
                    gamestate['Serve'] = false
                    gamestate['Playing'] = true
                    local currentTime = GetGameTimer()
                    if currentTime > lastUse + cooldown then
                        lastUse = currentTime
                        if not NetworkHasControlOfEntity(createdObject) then
                            local timeout = GetGameTimer() + 2000
                            NetworkRequestControlOfEntity(createdObject)
                            while (not NetworkHasControlOfEntity(createdObject)) and (GetGameTimer() < timeout) do
                                Citizen.Wait(0)
                            end
                        end
                        DetachEntity(createdObject, true, false)
                        ClearPedTasks(PlayerPedId())
                        local playerRotation = GetEntityRotation(PlayerPedId(), 2)
                        local forwardVector = GetEntityForwardVector(PlayerPedId())
                        local forceVector = vector3(
                            forwardVector.x * forwardForceIntensity,
                            forwardVector.y * forwardForceIntensity,
                            upwardForceIntensity
                        )
                        TriggerEvent('main-volleyball:client:animation', 'misscommon@response', 'screw_you', 3.0)
                        ApplyForceToEntity(createdObject, 1, forceVector.x, forceVector.y, forceVector.z, 0.0, 0.0, 0.0, 0, false, true, true, false, true)
                        ClearPedTasks(PlayerPedId())
                    end
                end
            end
            -- End of Serve Gamestate

            -- Start of Playing Gamestate
            if gamestate['Playing'] then
                if isPlayerNearObject(createdObject, 1.5) and IsControlJustReleased(0, 38) then -- 38 is the key code for 'E'
                    local currentTime = GetGameTimer()
                    if currentTime > lastUse + cooldown then
                        lastUse = currentTime
                        if not NetworkHasControlOfEntity(createdObject) then
                            local timeout = GetGameTimer() + 2000
                            NetworkRequestControlOfEntity(createdObject)
                            while (not NetworkHasControlOfEntity(createdObject)) and (GetGameTimer() < timeout) do
                                Citizen.Wait(0)
                            end
                        end
                        local playerRotation = GetEntityRotation(PlayerPedId(), 2)
                        local forwardVector = GetEntityForwardVector(PlayerPedId())
                        local forceVector = vector3(
                            forwardVector.x * forwardForceIntensity,
                            forwardVector.y * forwardForceIntensity,
                            upwardForceIntensity
                        )
                        TriggerEvent('main-volleyball:client:animation', 'amb@prop_human_movie_bulb@base', 'base', 4.0)
                        ApplyForceToEntity(createdObject, 1, forceVector.x, forceVector.y, forceVector.z, 0.0, 0.0, 0.0, 0, false, true, true, false, true)
                    end
                end
            end
            -- End of Playing GameState
        end
    end
end)

RegisterNetEvent('main-volleyball:updateObjectNetworkID')
AddEventHandler('main-volleyball:updateObjectNetworkID', function(netID)
    object_netID = netID
    createdObject = NetworkGetEntityFromNetworkId(object_netID)
end)

-- Function to load animation dictionary in FiveM
function LoadAnimDict(dict)
    while (not HasAnimDictLoaded(dict)) do
        RequestAnimDict(dict)
        Citizen.Wait(5)
    end
end

function attachObjectToPlayerLeftHand()
    local playerPed = PlayerPedId()
    local boneIndex = GetPedBoneIndex(playerPed, 18905) -- 18905 is the bone index for the left hand
    LoadAnimDict('missfam4')
    TaskPlayAnim(playerPed, 'missfam4', 'base', 8.0, -8.0, -1, 51, 0, false, false, false)
    --TriggerEvent('main-volleyball:client:animation', 'missfam4', 'base', 3.0)
    AttachEntityToEntity(createdObject, playerPed, boneIndex, 0.15, 0.18, 0.05, 0.0, 0.0, 0.0, true, true, false, true, 1, true)
    --TriggerServerEvent('main-volleyball:server:inplay')
    Citizen.Wait(2000)
end

Citizen.CreateThread(function()
    while true do
        Citizen.Wait(200) -- Always add a wait in your main loop to prevent freezing
        local playerPed = PlayerPedId()
        local playerCoord = GetEntityCoords(playerPed)
        if DoesEntityExist(createdObject) then
            objectCoord = GetEntityCoords(createdObject)
            --local unusedBool, groundZ = GetGroundZFor_3dCoord(objectCoord.x, objectCoord.y, 99999.0, 1)
            local unusedBool, groundZ = GetGroundZFor_3dCoord(objectCoord.x, objectCoord.y, objectCoord.z)
            if (objectCoord.z - groundZ) <= objectThresholdZ then
                TriggerServerEvent('main-volleyball:server:ballhitground')
            end

        else
            Citizen.Wait(0)
        end

    end
end)


-- Start of Animations

-- Function to load animation dictionary in FiveM
function loadAnimationDict(animationDict)
    RequestAnimDict(animationDict)

    while not HasAnimDictLoaded(animationDict) do
        Citizen.Wait(0)
    end
end


RegisterNetEvent('main-volleyball:client:animation')
AddEventHandler('main-volleyball:client:animation', function(animationDirectory, animationName, speed)
    local playerPed = PlayerPedId()
    if (DoesEntityExist(playerPed) and not IsEntityDead(playerPed)) then
        loadAnimationDict(animationDirectory)
        TaskPlayAnim(playerPed, animationDirectory, animationName, speed, 4.0, 300, 51, 0, false, false, false)
    end
end)


-- End of Animations
-- Commands for joinning/leaving teams would idealy use a diffrent system some sort of NUI
RegisterCommand('joina', function()
    TriggerServerEvent('main-volleyball:server:setteam', 'A', false)
end)
RegisterCommand('joinb', function()
    TriggerServerEvent('main-volleyball:server:setteam', 'B', false)
end)
RegisterCommand('leavea', function()
    toggleui()
    ShowNotification('You have left TeamA')
    TriggerServerEvent('main-volleyball:server:setteam', 'A', true)
end)
RegisterCommand('leaveb', function()
    toggleui()
    ShowNotification('You have left TeamB')
    TriggerServerEvent('main-volleyball:server:setteam', 'B', true)
end)

RegisterNetEvent('main-volleyball:client:inteam', function(inteam, team)
    if inteam then
        toggleui()
        ShowNotification('You have joined Team'.. team)
    else
        ShowNotification('Team'.. team .. ' is full')
    end
end)

-- Toggle the UI 
function toggleui()
    SendNUIMessage({ type = 'toggleUI' })
end
-- Change the score
RegisterNetEvent('main-volleball:update-score')
AddEventHandler('main-volleball:update-score', function(newScore)
    SendNUIMessage({
        type = 'updateScore',
        value = newScore
    })
end)

-- the notifcation to give the player information
function ShowNotification(text)
    SetNotificationTextEntry('STRING')
    AddTextComponentString(text)
    DrawNotification(false, true)
end
-- Draw text on screen function
function drawText(text, x, y, scale, red, green, blue, alpha)
    SetTextFont(4)
    SetTextProportional(0)
    SetTextScale(scale, scale)
    SetTextColour(red, green, blue, alpha)
    SetTextDropShadow(0, 0, 0, 0, 255)
    SetTextEdge(1, 0, 0, 0, 255)
    SetTextDropShadow()
    SetTextOutline()
    SetTextEntry('STRING')
    AddTextComponentString(text)
    DrawText(x, y)
end

-- Function which will be called when the event is triggered
function onVolleyballEvent(game)
    local text = ''
    local red, green, blue = 255, 255, 255

    if game == 'won' then
        text = 'You scored a point!'
        red, blue = 0, 0
    elseif game == 'lost' then
        text = 'The opponent Scored a point!'
        green, blue = 0, 0
    end

    --local screenWidth, screenHeight = GetScreenResolution()
    local screenWidth, screenHeight = GetActiveScreenResolution()
    local x = screenWidth / 2 / screenWidth
    local y = screenHeight / 2 / screenHeight
    local scale = 0.8

    -- Show message for 5 seconds
    local endTime = GetGameTimer() + 5000
    while GetGameTimer() < endTime do
        drawText(text, x, y, scale, red, green, blue, 255)
        Wait(0)
    end
end

RegisterNetEvent('main-volleyball:client:drawtext')
AddEventHandler('main-volleyball:client:drawtext', function(game)
    onVolleyballEvent(game)
end)


function alert(text)
    SetTextComponentFormat('STRING')
    AddTextComponentString(text)
    DisplayHelpTextFromStringLabel(0, 0, 1, -1)
end



server.lua

-- setting up variables
local object_netID = nil
local teams = {['A']= 0, ['B']= 0}
local score = {['TeamA'] = 0, ['TeamB'] = 0}
-- checking teams for both players
local placeholder = 0
-- Ground Players ids the player ids of people who are 
local playerIds = {} -- table to keep track of player ids who triggered the event
-- True for testing change back to false
local inplay = true
local selectedteam = nil


-- start of court detection

local boxZoneCorners = {
    vector2(-1263.52, -1665.18),
    vector2(-1274.91, -1649.15),
    vector2(-1265.62, -1642.32),
    vector2(-1254.02, -1658.61)
}
function IsPointInZone(x, y, Zone)
    local inside = false
    local j = #Zone
    for i = 1, #Zone do
        local xi, yi = Zone[i].x, Zone[i].y
        local xj, yj = Zone[j].x, Zone[j].y

        if (yi > y) ~= (yj > y) and (x < (xj - xi) * (y - yi) / (yj - yi) + xi) then
        inside = not inside
        end
        j = i
    end
    return inside
end

-- end of court detection


Citizen.CreateThread(function()
    while true do
        Citizen.Wait(2000)
        placeholder = 0
        if teams['A'] ~= 0 and teams['B'] ~= 0 then
            for k,v in pairs(teams) do
                local ped = GetPlayerPed(v)
                local pedCoords = GetEntityCoords(ped)
                if IsPointInZone(pedCoords.x, pedCoords.y, boxZoneCorners) then
                    --print('Ped is inside the box Zone'.. ped)
                    placeholder = placeholder + 1
                --else
                --    print('Ped is outside the box Zone'.. ped)
                end
            end
            if placeholder == 2 then
                local randomTeam = math.random(100) -- generates a random number to decide who starts
                if randomTeam >= 50 then
                    selectedteam = teams['A']
                    oppositeSide = teams['B']
                else 
                    selectedteam = teams['B']
                    oppositeSide = teams['A']
                end
                TriggerClientEvent('main-volleyball:client:spawnball', selectedteam)
                TriggerClientEvent('main-volleyball:client:changegamestate', oppositeSide, 'Playing')
            end
        end
    end
end)


-- Updating the score and triggering the up for the the clients playing
local function scorechange(team)
    for k,v in pairs(score) do
        if k == team then
            score[k] = v + 1
            if score[k] >= 3 then
                resetscore()
            else
                local formattedScore = score['TeamA'] .. ' - ' .. score['TeamB']
                for k,v in pairs(teams) do
                    TriggerClientEvent('main-volleball:update-score', v, formattedScore)
                end
            end
        end
    end
end


-- reset the score for everyone will need to be changed if multiple instances are added
local function resetscore()
    for k,v in pairs(score) do
        score[k] = 0
    end
    TriggerClientEvent('main-volleball:update-score', -1, '0 - 0')
end

-- Server event to add players to team
RegisterServerEvent('main-volleyball:server:setteam')
AddEventHandler('main-volleyball:server:setteam', function(team, leave)
    if leave then
        teams[team] = 0
    else
        for k,v in pairs(teams) do
            if k == team then
                if v == 0 then
                    TriggerClientEvent('main-volleyball:client:inteam', source, true, team)
                    teams[k] = source
                else
                    TriggerClientEvent('main-volleyball:client:inteam', source, false, team)
                end
            end
        end
    end
end)




RegisterServerEvent('main-volleyball:setObjectNetworkID')
AddEventHandler('main-volleyball:setObjectNetworkID', function(netID)
    object_netID = netID
    for k,v in pairs(teams) do
        TriggerClientEvent('main-volleyball:updateObjectNetworkID', v, netID)
    end
end)

RegisterServerEvent('main-volleyball:requestObjectNetworkID')
AddEventHandler('main-volleyball:requestObjectNetworkID', function()
    local src = source
    if object_netID then
        TriggerClientEvent('main-volleyball:updateObjectNetworkID', src, object_netID)
    end
end)


RegisterNetEvent('main-volleyball:server:inplay')
AddEventHandler('main-volleyball:server:inplay', function()
    inplay = true
end)
-- functions
function calculateLineEquation(pointA, pointB)
    local A = pointB.y - pointA.y
    local B = pointA.x - pointB.x
    local C = pointB.x * pointA.y - pointA.x * pointB.y

    return {A = A, B = B, C = C}
end
-- line equation
-- line points to detect what side the volleyball is on
local linePointA = vector2(-1259.57, -1650.41)
local linePointB = vector2(-1269.49, -1657.43)
local lineEquation = calculateLineEquation(linePointA, linePointB)
function detectSideOfLine(line, pedCoordx, pedCoordy)
    local expressionValue = line.A * pedCoordx + line.B * pedCoordy + line.C

    if expressionValue > 0 then
        return 'A'
    elseif expressionValue < 0 then
        return 'B'
    else
        return 'Online'
    end
end

RegisterServerEvent('main-volleyball:server:ballhitground')
AddEventHandler('main-volleyball:server:ballhitground', function()
    if inplay then
        local playerId = source -- get the id of the player who triggered the event
        if not playerIds[playerId] then
            playerIds[#playerIds+1] = {id}
            -- check if two different players triggered the event
            if #playerIds >= 2 then
                inplay = false
                playerIds = {}
                -- run detection if the ball was within the Zone if so detect what side of the court the ball is on
                local ball = NetworkGetEntityFromNetworkId(object_netID)
                local ballCoords = GetEntityCoords(ball)
                local side = detectSideOfLine(lineEquation, ballCoords.x, ballCoords.y)
                if IsPointInZone(ballCoords.x, ballCoords.y, boxZoneCorners) then
                    if side == 'A' then oppositeSide = 'B' else oppositeSide = 'A' end
                    scorechange('Team'.. oppositeSide)
                    for k,v in pairs(teams) do
                        if k == oppositeSide then
                            TriggerClientEvent('main-volleyball:client:drawtext', v, 'won')
                            TriggerClientEvent('main-volleyball:client:changegamestate', v, 'Pickup')

                        else
                            TriggerClientEvent('main-volleyball:client:drawtext', v, 'lost')
                        end
                    end
                else
                    scorechange('Team'.. side)
                    for k,v in pairs(teams) do
                        if k == side then
                            TriggerClientEvent('main-volleyball:client:drawtext', v, 'won')
                            TriggerClientEvent('main-volleyball:client:changegamestate', v, 'Pickup')
                        else
                            TriggerClientEvent('main-volleyball:client:drawtext', v, 'lost')
                        end
                    end
                end
            end
        end
    end
end)