```lua
local Vector3D = require("vector3d")
local SphereLibrary = {}
local spheres = {}
local nextSphereId = 1
local mathRad = math.rad
local TWO_PI, PI = mathRad(360), mathRad(180)
local MAX_DETAIL_LEVEL = 20
local DEFAULT_DETAIL_LEVEL = 5
local DEFAULT_COLOR = 0xFFFFFF
local MAX_RENDER_DISTANCE = 1000
local debugMode = false
local function clamp(value, min, max)
    if value < min then return min end
    if value > max then return max end
    return value
end

local function isValidPed(ped)
    return ped ~= nil and doesCharExist(ped)
end

local function calculateDistance(pos1, pos2)
    local dx = pos1.x - pos2.x
    local dy = pos1.y - pos2.y
    local dz = pos1.z - pos2.z
    return math.sqrt(dx * dx + dy * dy + dz * dz)
end

local function safeGetCharCoordinates(pPed)
    local success, coords = pcall(getCharCoordinates, pPed)
    if success and type(coords) == "table" and coords.x and coords.y and coords.z then
        return coords
    else
        if debugMode then print("Error: Failed to get character coordinates for pPed:", pPed) end
        return {
            x = 0,
            y = 0,
            z = 0
        }
    end
end

local function isWithinRenderDistance(sphereCenter, cameraPos)
    local distance = calculateDistance(sphereCenter, cameraPos)
    return distance <= MAX_RENDER_DISTANCE
end

local function addVectors(v1, v2)
    return Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
end

local function updatePosition(sphere)
    if sphere.followPlayer then
        if sphere.pPed and isValidPed(sphere.pPed) then
            local coords = safeGetCharCoordinates(sphere.pPed)
            sphere.center = Vector3D(coords.x, coords.y, coords.z)
        else
            if debugMode then print("Warning: Invalid pPed in sphere ID:", sphere.id) end
        end
    end
end

local function calculatePoint(sphere, phi, theta)
    local sinPhi = math.sin(phi)
    local x = sphere.radius * sinPhi * math.cos(theta)
    local y = sphere.radius * sinPhi * math.sin(theta)
    local z = sphere.radius * math.cos(phi)
    return addVectors(Vector3D(x, y, z), sphere.center)
end

local function renderLine(point1, point2, width, color, sphereId)
    local visible1, screenX1, screenY1 = convert3DCoordsToScreenEx(point1.x, point1.y, point1.z)
    local visible2, screenX2, screenY2 = convert3DCoordsToScreenEx(point2.x, point2.y, point2.z)
    if visible1 and visible2 then
        renderDrawLine(screenX1, screenY1, screenX2, screenY2, width, color)
    else
        if debugMode then print(string.format("Line not rendered: Point1 visible=%s, Point2 visible=%s for sphere ID: %s", tostring(visible1), tostring(visible2), sphereId)) end
    end
end

local function renderSphere(sphere)
    local stepTheta = TWO_PI / sphere.detailLevel
    local stepPhi = PI / sphere.detailLevel
    local numThetaSteps = sphere.detailLevel
    local numPhiSteps = sphere.detailLevel
    for i = 0, numThetaSteps do
        local theta = i * stepTheta
        for j = 1, numPhiSteps - 1 do
            local phi = j * stepPhi
            local point1 = calculatePoint(sphere, phi, theta)
            local point2 = calculatePoint(sphere, phi, theta + stepTheta)
            local point3 = calculatePoint(sphere, phi + stepPhi, theta)
            renderLine(point1, point2, 1, sphere.color, sphere.id)
            renderLine(point1, point3, 1, sphere.color, sphere.id)
        end
    end
end

local function isPointInSphere(point, center, radius)
    if type(point.x) ~= "number" or type(center.x) ~= "number" or type(point.y) ~= "number" or type(center.y) ~= "number" or type(point.z) ~= "number" or type(center.z) ~= "number" then
        if debugMode then print("Error: Non-numeric coordinates provided to isPointInSphere.") end
        return false
    end

    local dx, dy, dz = point.x - center.x, point.y - center.y, point.z - center.z
    return (dx * dx + dy * dy + dz * dz) <= (radius * radius)
end

function SphereLibrary.collectEntitiesInSphere(sphereId)
    local sphere = spheres[sphereId]
    if not sphere then
        print(string.format("Warning: Invalid sphereId '%s' provided to collectEntitiesInSphere.", sphereId))
        return {
            objects = {},
            players = {},
            cars = {}
        }
    end

    local entitiesInside = {
        objects = {},
        players = {},
        cars = {}
    }

    local function addEntities(getAllEntities, getCoords, getId, entityKey)
        local allEntities = getAllEntities()
        if type(allEntities) ~= "table" then
            print(string.format("Error: %s did not return a table.", tostring(getAllEntities)))
            return
        end

        for _, entity in ipairs(allEntities) do
            local coords = getCoords(entity)
            if not coords then
                if debugMode then print(string.format("Warning: Failed to get coordinates for entity in '%s'.", entityKey)) end
            else
                local entityPoint = Vector3D(coords.x, coords.y, coords.z)
                if isPointInSphere(entityPoint, sphere.center, sphere.radius) then
                    local success, entityId = pcall(getId, entity)
                    if success and entityId then
                        table.insert(entitiesInside[entityKey], entityId)
                    elseif debugMode then
                        print(string.format("Error: Failed to get ID for entity in '%s'.", entityKey))
                    end
                end
            end
        end
    end

    addEntities(getAllObjects, getObjectCoordinates, sampGetObjectSampIdByHandle, "objects")
    addEntities(getAllChars, getCharCoordinates, sampGetPlayerIdByCharHandle, "players")
    addEntities(getAllVehicles, getCarCoordinates, sampGetVehicleIdByCarHandle, "cars")
    if next(entitiesInside.objects) == nil and next(entitiesInside.players) == nil and next(entitiesInside.cars) == nil and debugMode then print(string.format("Info: No entities found within sphere ID: %s.", sphereId)) end
    return entitiesInside
end

function SphereLibrary.createSphere(playerPed, radius, followPlayer, centerX, centerY, centerZ, detailLevel, color)
    if type(radius) ~= "number" or radius <= 0 then error("Invalid radius provided to createSphere. Must be a positive number.") end
    if followPlayer and not isValidPed(playerPed) then error("Invalid playerPed provided to createSphere.") end
    centerX = (type(centerX) == "number") and centerX or 0
    centerY = (type(centerY) == "number") and centerY or 0
    centerZ = (type(centerZ) == "number") and centerZ or 0
    detailLevel = (type(detailLevel) == "number" and detailLevel > 0) and clamp(math.floor(detailLevel), 1, MAX_DETAIL_LEVEL) or DEFAULT_DETAIL_LEVEL
    color = (type(color) == "number") and color or DEFAULT_COLOR
    local sphereId = nextSphereId
    nextSphereId = nextSphereId + 1
    spheres[sphereId] = {
        id = sphereId,
        pPed = playerPed,
        radius = radius,
        followPlayer = followPlayer,
        center = Vector3D(centerX, centerY, centerZ),
        detailLevel = detailLevel,
        color = color
    }

    if debugMode then print(string.format("Sphere created with ID: %s", sphereId)) end
    return sphereId
end

function SphereLibrary.removeSphere(sphereId)
    if spheres[sphereId] then
        spheres[sphereId] = nil
        if debugMode then print(string.format("Sphere with ID: %s removed.", sphereId)) end
    else
        print(string.format("Warning: Attempted to remove a non-existent sphereId '%s'.", sphereId))
    end
end

function SphereLibrary.updateRender()
    local cameraCoords = getCameraCoordinates()
    for _, currentSphere in pairs(spheres) do
        updatePosition(currentSphere)
        if cameraCoords then
            if isWithinRenderDistance(currentSphere.center, cameraCoords) and isPointOnScreen(currentSphere.center.x, currentSphere.center.y, currentSphere.center.z) then renderSphere(currentSphere) end
        else
            if isPointOnScreen(currentSphere.center.x, currentSphere.center.y, currentSphere.center.z) then renderSphere(currentSphere) end
        end
    end
end

function SphereLibrary.setDebugMode(enabled)
    debugMode = enabled and true or false
    print(string.format("Debug mode %s.", debugMode and "enabled" or "disabled"))
end
return SphereLibrary
```
Функции getAllEntities не существует, реализуй ее.