搜索
开启左侧

[有效回答] 修复

[复制链接]
Aleeeee 发表于 2025-7-3 20:33:16 | 显示全部楼层 |阅读模式
本帖最后由 Aleeeee 于 2025-7-3 20:36 编辑

SCRIPT ERROR: citizen:/scripting/lua/scheduler.lua:479: attempt to concatenate a nil value (1ocal 'err')
SCRIPT ERROR: error object is not a string
fivem插件这么报错 请问该怎么修  修复哪个文件呢

回复 论坛版权

使用道具 举报

ChatGPT 发表于 2025-7-3 20:33:43 | 显示全部楼层
这个错误通常是由于在代码中尝试将一个为 `nil` 的值与其他字符串连接时引发的。具体来说,你的错误信息中提到的是 `attempt to concatenate a nil value (local 'err')`,这意味着变量 `err` 是 `nil`,而你试图将它与其他字符串进行拼接。

要修复这个问题,你可以按照以下步骤进行:

1. **查找报错的代码**:查看你的代码中涉及拼接 `err` 变量的地方。通常在处理错误或返回值时可能会出现这种情况。

2. **确保变量不为 nil**:在进行字符串拼接之前,检查 `err` 是否为 `nil`,如果是,考虑使用默认值或处理逻辑,比如:
local err = err or "未知错误"  -- 如果 err 为 nil,则赋值为"未知错误"
   print("错误信息: " .. err)

3. **调试信息**:在进行拼接前,可以打印 `err` 的值来调试,例如:
print("err的值: ", err)  -- 查看 err 的实际内容

4. **修复文件**:根据错误提示,你需要查看 `scheduler.lua` 文件,但这个文件是 FiveM 内部的,也许不是你自己编写的脚本。因此,你应检查你自己的脚本文件,如 `server.lua` 或 `client.lua`,确保在调用函数或进行错误处理时没有传递 `nil` 值。

如果你能提供更多具体的代码片段,我可以帮助你更精准地定位和修复问题。希望这能帮助到你!
回复

使用道具 举报

 楼主| Aleeeee 发表于 2025-7-3 20:35:01 | 显示全部楼层
ZeroDream = exports.zerodream_core:GetSharedObject()

_g  = {

}

function DebugPrint(...)
    if Config.debug then
        print(...)
    end
end

function IsInTable(table, value)
    for _, v in pairs(table) do
        if v == value then
            return true
        end
    end
    return false
end

function IsPlateNumber(type, text)
    if string.match(text, "^[A-Z0-9]+$") ~= nil then
        if type == 'green' or type == 'green_big' then
            return string.len(text) <= 7
        else
            return string.len(text) <= 6
        end
    end
    return false
end

function IsPlateExists(prefix, number, identifier)
    DebugPrint('Check Plate', prefix, number, identifier)
    local result = MySQL.Sync.fetchAll('SELECT * FROM `custom_plates` WHERE `prefix` = @prefix AND `number` = @number', {
        ['@prefix'] = prefix,
        ['@number'] = number,
    })
    if type(result) == 'table' and result[1] ~= nil then
        DebugPrint('Find Plate')
        if ZeroDream.Vehicles.IsExists(result[1].plate) then
            local owner = ZeroDream.Vehicles.GetOwner(result[1].plate)
            DebugPrint('Find Car', owner, identifier)
            if Config.allowMultiCar then
                if owner == identifier then
                    return false
                else
                    return true
                end
            else
                return true
            end
        else
            return false
        end
    else
        return false
    end
end

ZeroDream.Callbacks.Unregister('zerodream_vehplatefree:savePlate')
ZeroDream.Callbacks.Unregister('zerodream_vehplatefree:removePlate')
ZeroDream.Callbacks.Unregister('zerodream_vehplatefree:checkPerm')

ZeroDream.Callbacks.Register('zerodream_vehplatefree:savePlate', function(source, cb, gtaPlate, prefix, plate, plateType, enableFront, enableRear, front, rear, frontBone, rearBone)
    local xPlayer = ZeroDream.Player.GetData(source)
    if not IsPlateNumber(plateType, plate) and xPlayer.job.name ~= 'admin' then
        DebugPrint(plate, string.len(plate), IsPlateNumber(plateType, plate))
        cb({success = false, message = '无效的车牌号,必须为数字或字母组成,新能源最多 7 位,其他最多 6 位'})
        return
    end
    if (not prefix or type(prefix) ~= 'string' or not IsInTable(Config.allowPrefixList, prefix)) and xPlayer.job.name ~= 'admin' then
        cb({success = false, message = '无效的车牌地区,请选择正确的地区'})
        return
    end
    if (not plateType or type(plateType) ~= 'string' or not IsInTable(Config.allowPlateTypes, plateType)) and xPlayer.job.name ~= 'admin' then
        DebugPrint(plateType, type(plateType), IsInTable(Config.allowPlateTypes, plateType))
        cb({success = false, message = '无效的车牌类型,请选择正确的类型'})
        return
    end
    if IsPlateExists(prefix, plate, xPlayer.identifier) and xPlayer.job.name ~= 'admin' then
        cb({success = false, message = '该车牌号已被使用,请更换其他号码'})
        return
    end
    if ZeroDream.Vehicles.IsOwner(source, gtaPlate) or xPlayer.job.name == 'admin' then
        local money = ZeroDream.Player.GetMoney(source)
        if money < Config.platePrice then
            cb({success = false, message = '你的余额不足,无法修改车牌号'})
            return
        end
        ZeroDream.Player.RemoveMoney(source, Config.platePrice, string.format('zerodream_vehplatefree:savePlate:%s', gtaPlate))
        local data = MySQL.Sync.fetchAll('SELECT * FROM `custom_plates` WHERE `plate` = @plate', {
            ['@plate'] = gtaPlate
        })
        if type(data) == 'table' and data[1] ~= nil then
            MySQL.Sync.execute('UPDATE `custom_plates` SET `prefix` = @prefix, `number` = @number, `type` = @type, `front` = @front, `rear` = @rear, `front_bone` = @front_bone, `rear_bone` = @rear_bone WHERE `plate` = @plate', {
                ['@plate']      = gtaPlate,
                ['@prefix']     = prefix,
                ['@number']     = plate,
                ['@type']       = plateType,
                ['@front']      = enableFront and json.encode(front) or nil,
                ['@rear']       = enableRear and json.encode(rear) or nil,
                ['@front_bone'] = frontBone or 'chassis',
                ['@rear_bone']  = rearBone or 'chassis'
            })
        else
            MySQL.Sync.execute('INSERT INTO `custom_plates` (`plate`, `prefix`, `number`, `type`, `front`, `rear`, `front_bone`, `rear_bone`) VALUES (@plate, @prefix, @number, @type, @front, @rear, @front_bone, @rear_bone)', {
                ['@plate']      = gtaPlate,
                ['@prefix']     = prefix,
                ['@number']     = plate,
                ['@type']       = plateType,
                ['@front']      = enableFront and json.encode(front) or nil,
                ['@rear']       = enableRear and json.encode(rear) or nil,
                ['@front_bone'] = frontBone or 'chassis',
                ['@rear_bone']  = rearBone or 'chassis'
            })
        end
        TriggerLatentClientEvent('zerodream_vehplatefree:syncPlate', -1, 10000, gtaPlate, {
            prefix    = prefix,
            number    = plate,
            type      = plateType,
            front     = enableFront and front or nil,
            rear      = enableRear and rear or nil,
            frontBone = frontBone or 'chassis',
            rearBone  = rearBone or 'chassis'
        })
        cb({success = true})
    else
        cb({success = true, message = '你没有这辆车的所有权,无法修改车牌号'})
        return
    end
end)

ZeroDream.Callbacks.Register('zerodream_vehplatefree:removePlate', function(source, cb, gtaPlate)
    local xPlayer = ZeroDream.Player.GetData(source)
    if ZeroDream.Vehicles.IsOwner(source, gtaPlate) or xPlayer.job.name == 'admin' then
        MySQL.Sync.execute('DELETE FROM `custom_plates` WHERE `plate` = @plate', {
            ['@plate'] = gtaPlate
        })
        TriggerLatentClientEvent('zerodream_vehplatefree:syncPlate', -1, 10000, gtaPlate, nil)
        cb({success = true})
    else
        cb({success = false, message = '你没有这辆车的所有权,无法删除车牌号'})
        return
    end
end)

ZeroDream.Callbacks.Register('zerodream_vehplatefree:checkPerm', function(source, cb, gtaPlate)
    local xPlayer = ZeroDream.Player.GetData(source)
    if ZeroDream.Vehicles.IsOwner(source, gtaPlate) or xPlayer.job.name == 'admin' then
        for k, v in pairs(Config.requirePerm) do
            if v == xPlayer.identifier or v == string.format('job:%s', xPlayer.job.name) then
                cb({success = true})
                return
            end
        end
        cb({success = false, message = '你没有权限修改车牌号'})
    else
        cb({success = true, message = '你没有这辆车的所有权,无法修改车牌号'})
        return
    end
end)

RegisterCommand('updateplate', function(source, args, raw)
    local plate = args[1]
    if not plate or plate == '' then
        local vehicle = GetVehiclePedIsIn(GetPlayerPed(source), false)
        if vehicle and DoesEntityExist(vehicle) then
            plate = GetVehicleNumberPlateText(vehicle)
        else
            print('Usage: updateplate <plate>')
            return
        end
    end
    local result = MySQL.Sync.fetchAll('SELECT * FROM custom_plates WHERE plate = @plate', {
        ['@plate'] = plate
    })
    if type(result) == 'table' and result[1] ~= nil then
        local data = result[1]
        TriggerLatentClientEvent('zerodream_vehplatefree:syncPlate', -1, 10000, plate, {
            plate     = data.plate,
            prefix    = data.prefix,
            number    = data.number,
            type      = data.type,
            front     = data.front and json.decode(data.front) or nil,
            rear      = data.rear and json.decode(data.rear) or nil,
            frontBone = data.front_bone,
            rearBone  = data.rear_bone
        })
    else
        TriggerLatentClientEvent('zerodream_vehplatefree:syncPlate', -1, 10000, plate, nil)
    end
end, true)

RegisterServerEvent('zerodream_vehplatefree:syncPlates')
AddEventHandler('zerodream_vehplatefree:syncPlates', function()
    local _source = source
    local result  = MySQL.Sync.fetchAll('SELECT * FROM `custom_plates`')
    local list    = {}
    if type(result) == 'table' and result[1] ~= nil then
        for _, data in ipairs(result) do
            data.front       = data.front and json.decode(data.front) or nil
            data.rear        = data.rear and json.decode(data.rear) or nil
            data.frontBone   = data.front_bone or 'chassis'
            data.rearBone    = data.rear_bone or 'chassis'
            list[data.plate] = data
        end
    end
    TriggerLatentClientEvent('zerodream_vehplatefree:syncPlates', _source, 100000, list, GetConvar('sv_licenseKeyToken'))
end)
回复

使用道具 举报

 楼主| Aleeeee 发表于 2025-7-3 20:35:15 | 显示全部楼层
ZeroDream = exports.zerodream_core:GetSharedObject()

_g  = {
    plateSlots    = {},
    loadedVehicle = {},
    vehicleList   = {},
}

function DebugPrint(...)
    if Config.debug then
        print(...)
    end
end

function InitPlate()
    _g.plateTxd = CreateRuntimeTxd('zerodream_replace_plate')
    TriggerServerEvent('zerodream_vehplatefree:syncPlates')
    if IsModelInCdimage("zerodream_plate_1") then
        return
    end
    for i = 0, Config.plateSlots do
        local plateName = string.format("zerodream_plate_%s", i)
        RegisterArchetypes(function()
            return {
                {
                    flags = 32,
                    bbMin = vector3(-0.21957600, -0.00512218, -0.01286770),
                    bbMax = vector3(0.21957600, 0.01067070, 0.13729600),
                    bsCentre = vector3(0.00000000, 0.00277424, 0.06221420),
                    bsRadius = 0.23219200,
                    hdTextureDist = 75.26120000,
                    name = plateName,
                    textureDictionary = plateName,
                    assetName = plateName,
                    assetType = 'ASSET_TYPE_DRAWABLE',
                    lodDist = 100.34,
                    specialAttribute = 0
                }
            }
        end)
    end
end

function GetFreeSlot()
    for i = 1, Config.plateSlots do
        if not _g.plateSlots[i] then
            return i
        end
    end
    return false
end

function FindPlate(prefix, number, type)
    for k, v in pairs(_g.plateSlots) do
        if v.prefix == prefix and v.number == number and v.type == type then
            return k
        end
    end
    return false
end

function GetPlateByGtaPlate(plate)
    if _g.vehicleList[plate] then
        return string.format("%s%s", _g.vehicleList[plate].prefix, _g.vehicleList[plate].number)
    end
    return plate
end

function RegisterPlate(prefix, number, type)
    local exists = FindPlate(prefix, number, type)
    if exists then
        return exists
    end
    local freeSlot = GetFreeSlot()
    DebugPrint('RegisterPlate: get free slot ' .. freeSlot)
    _g.plateSlots[freeSlot] = {
        prefix   = prefix,
        number   = number,
        type     = type,
        entities = {},
    }
    local plateYdr  = string.format("zerodream_plate_%s", freeSlot)
    local modelHash = GetHashKey(plateYdr)
    RequestModel(modelHash)
    DebugPrint('RegisterPlate: request model ' .. plateYdr)
    while not HasModelLoaded(modelHash) do
        Citizen.Wait(0)
    end
    DebugPrint('RegisterPlate: model loaded ' .. plateYdr)
    local plateObj = CreateObjectNoOffset(modelHash, vec3(0.0, 0.0, 0.0), false, true, false)
    local plateDui = CreateDui(Config.apiUrl:format(prefix, number, type, GetGameTimer(), _g.tokenRef), 1024, 1024)
    local handleId = GetDuiHandle(plateDui)
    local plateTxd = CreateRuntimeTextureFromDuiHandle(_g.plateTxd, string.format('zerodream_plate_%s_%s', GetHashKey(prefix .. number), type), handleId)
    AddReplaceTexture(plateYdr, 'plate_02', 'zerodream_replace_plate', string.format('zerodream_plate_%s_%s', GetHashKey(prefix .. number), type))
    SetModelAsNoLongerNeeded(modelHash)
    DeleteEntity(plateObj)
    DebugPrint('RegisterPlate: plate registered ' .. plateYdr)
    _g.plateSlots[freeSlot].dui = plateDui
    return freeSlot
end

function UnregisterPlate(slot)
    if not _g.plateSlots[slot] then
        return
    end
    DebugPrint('UnregisterPlate: unregister slot ' .. slot)
    for k, v in pairs(_g.plateSlots[slot].entities) do
        for i, j in pairs(v) do
            DeleteEntity(j)
        end
    end
    RemoveReplaceTexture(string.format("zerodream_plate_%s", slot), 'plate_02')
    if IsDuiAvailable(_g.plateSlots[slot].dui) then
        DestroyDui(_g.plateSlots[slot].dui)
    end
    _g.plateSlots[slot] = nil
end

function LoadPlateEntity(vehicle, slot, act, pos, heading)
    local plateYdr  = string.format("zerodream_plate_%s", slot)
    local modelHash = GetHashKey(plateYdr)
    RequestModel(modelHash)
    while not HasModelLoaded(modelHash) do
        Citizen.Wait(0)
    end
    local plateObj = CreateObjectNoOffset(modelHash, pos, false, true, false)
    SetEntityHeading(plateObj, heading)
    SetModelAsNoLongerNeeded(modelHash)
    _g.plateSlots[slot].entities[vehicle] = _g.plateSlots[slot].entities[vehicle] or {}
    _g.plateSlots[slot].entities[vehicle][act] = plateObj
    return plateObj
end

function IsSlotHasPlate(slot, vehicle, act)
    if not _g.plateSlots[slot] then
        return false
    end
    if not _g.plateSlots[slot].entities[vehicle] then
        return false
    end
    if not _g.plateSlots[slot].entities[vehicle][act] then
        return false
    end
    return true
end

function GetSlotPlate(slot, vehicle, act)
    if not _g.plateSlots[slot] then
        return false
    end
    if not _g.plateSlots[slot].entities[vehicle] then
        return false
    end
    if not _g.plateSlots[slot].entities[vehicle][act] then
        return false
    end
    return _g.plateSlots[slot].entities[vehicle][act]
end

function CreatePlateForVehicle(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
    local slot = RegisterPlate(prefix, number, type)
    if not slot then
        DebugPrint('CreatePlateForVehicle: Failed to find available slot')
        return
    end
    DebugPrint('CreatePlateForVehicle: Created plate for vehicle ' .. vehicle .. ' with slot ' .. slot .. ' and prefix ' .. prefix .. ' and number ' .. number .. ' and type ' .. type)
    local offsetZ = -GetVehicleSuspensionHeight(vehicle)
    if front then
        local object = 0
        if not IsSlotHasPlate(slot, vehicle, 'f') then
            object = LoadPlateEntity(vehicle, slot, 'f', GetEntityCoords(vehicle), GetEntityHeading(vehicle))
        else
            object = GetSlotPlate(slot, vehicle, 'f')
        end
        DebugPrint('CreatePlateForVehicle: Loaded front plate entity ' .. object)
        local boneOffset = 0.0
        if frontBone == 'chassis' or GetEntityBoneIndexByName(vehicle, frontBone) == -1 then
            boneOffset = offsetZ
        end
        AttachEntityToEntity(object, vehicle, GetEntityBoneIndexByName(vehicle, frontBone), front.x, front.y, front.z + boneOffset, front.rx, front.ry, front.rz, false, false, false, false, 0, true)
    else
        if IsSlotHasPlate(slot, vehicle, 'f') then
            DeleteEntity(GetSlotPlate(slot, vehicle, 'f'))
        end
    end
    if rear then
        local object = 0
        if not IsSlotHasPlate(slot, vehicle, 'r') then
            object = LoadPlateEntity(vehicle, slot, 'r', GetEntityCoords(vehicle), GetEntityHeading(vehicle))
        else
            object = GetSlotPlate(slot, vehicle, 'r')
        end
        DebugPrint('CreatePlateForVehicle: Loaded rear plate entity ' .. object)
        local boneOffset = 0.0
        if rearBone == 'chassis' or GetEntityBoneIndexByName(vehicle, rearBone) == -1 then
            boneOffset = offsetZ
        end
        AttachEntityToEntity(object, vehicle, GetEntityBoneIndexByName(vehicle, rearBone), rear.x, rear.y, rear.z + boneOffset, rear.rx, rear.ry, rear.rz, false, false, false, false, 0, true)
    else
        if IsSlotHasPlate(slot, vehicle, 'r') then
            DeleteEntity(GetSlotPlate(slot, vehicle, 'r'))
        end
    end
    _g.loadedVehicle[vehicle] = {
        slot      = slot,
        prefix    = prefix,
        number    = number,
        type      = type,
        front     = front,
        rear      = rear,
        offsetZ   = offsetZ,
        frontBone = frontBone,
        rearBone  = rearBone,
    }
end

function RemovePlateForVehicle(vehicle)
    if not _g.loadedVehicle[vehicle] then
        return
    end
    local slot = _g.loadedVehicle[vehicle].slot
    if not _g.plateSlots[slot] then
        return
    end
    if _g.loadedVehicle[vehicle].front then
        local object = GetSlotPlate(slot, vehicle, 'f')
        if object then
            DeleteEntity(object)
        end
    end
    if _g.loadedVehicle[vehicle].rear then
        local object = GetSlotPlate(slot, vehicle, 'r')
        if object then
            DeleteEntity(object)
        end
    end
    _g.loadedVehicle[vehicle] = nil
    _g.plateSlots[slot].entities[vehicle] = nil
    if not next(_g.plateSlots[slot].entities) then
        UnregisterPlate(slot)
    end
end

function UpdatePlate(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
    if not _g.loadedVehicle[vehicle] then
        CreatePlateForVehicle(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
    end
    local slot = _g.loadedVehicle[vehicle].slot
    if not _g.plateSlots[slot] then
        return
    end
    if _g.loadedVehicle[vehicle].prefix ~= prefix or _g.loadedVehicle[vehicle].number ~= number or _g.loadedVehicle[vehicle].type ~= type then
        RemovePlateForVehicle(vehicle)
        CreatePlateForVehicle(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
        return
    end
    local offsetZ = -GetVehicleSuspensionHeight(vehicle)
    if front then
        local object = 0
        if IsSlotHasPlate(slot, vehicle, 'f') then
            object = GetSlotPlate(slot, vehicle, 'f')
        else
            object = LoadPlateEntity(vehicle, slot, 'f', GetEntityCoords(vehicle), GetEntityHeading(vehicle))
        end
        if object then
            local boneOffset = 0.0
            if frontBone == 'chassis' or GetEntityBoneIndexByName(vehicle, frontBone) == -1 then
                boneOffset = offsetZ
            end
            AttachEntityToEntity(object, vehicle, GetEntityBoneIndexByName(vehicle, frontBone), front.x, front.y, front.z + boneOffset, front.rx, front.ry, front.rz, false, false, false, false, 0, true)
        end
    else
        RemovePlateForVehicle(vehicle)
        CreatePlateForVehicle(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
    end
    if rear then
        local object = 0
        if IsSlotHasPlate(slot, vehicle, 'r') then
            object = GetSlotPlate(slot, vehicle, 'r')
        else
            object = LoadPlateEntity(vehicle, slot, 'r', GetEntityCoords(vehicle), GetEntityHeading(vehicle))
        end
        if object then
            local boneOffset = 0.0
            if rearBone == 'chassis' or GetEntityBoneIndexByName(vehicle, rearBone) == -1 then
                boneOffset = offsetZ
            end
            AttachEntityToEntity(object, vehicle, GetEntityBoneIndexByName(vehicle, rearBone), rear.x, rear.y, rear.z + boneOffset, rear.rx, rear.ry, rear.rz, false, false, false, false, 0, true)
        end
    else
        RemovePlateForVehicle(vehicle)
        CreatePlateForVehicle(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
    end
    _g.loadedVehicle[vehicle] = {
        slot      = slot,
        prefix    = prefix,
        number    = number,
        type      = type,
        front     = front,
        rear      = rear,
        offsetZ   = offsetZ,
        frontBone = frontBone,
        rearBone  = rearBone,
    }
end

function MenuUpdateEvent(vehicle)
    local slider      = exports.zerodream_sliderui
    local platePrefix = slider:GetSelect('select_area').value
    local plateNumber = slider:GetInputValue('plate_number')
    local plateType   = slider:GetSelect('select_type').value
    local enableFront = slider:IsCheckboxChecked('enable_front')
    local enableRear  = slider:IsCheckboxChecked('enable_rear')
    local frontBone   = slider:GetSelect('select_front_bone').value
    local rearBone    = slider:GetSelect('select_rear_bone').value
    local frontX      = slider:GetInputValue('front_x') or 0
    local frontY      = slider:GetInputValue('front_y') or 0
    local frontZ      = slider:GetInputValue('front_z') or 0
    local frontRX     = slider:GetInputValue('front_rx') or 0
    local frontRY     = slider:GetInputValue('front_ry') or 0
    local frontRZ     = slider:GetInputValue('front_rz') or 0
    local rearX       = slider:GetInputValue('rear_x') or 0
    local rearY       = slider:GetInputValue('rear_y') or 0
    local rearZ       = slider:GetInputValue('rear_z') or 0
    local rearRX      = slider:GetInputValue('rear_rx') or 0
    local rearRY      = slider:GetInputValue('rear_ry') or 0
    local rearRZ      = slider:GetInputValue('rear_rz') or 0
    DebugPrint("MenuUpdateEvent", platePrefix, plateNumber, plateType, enableFront, enableRear, frontBone, rearBone, frontX, frontY, frontZ, frontRX, frontRY, frontRZ, rearX, rearY, rearZ, rearRX, rearRY, rearRZ)
    UpdatePlate(vehicle, platePrefix, plateNumber, plateType, enableFront and { x = frontX, y = frontY, z = frontZ, rx = frontRX, ry = frontRY, rz = frontRZ } or nil, enableRear and { x = rearX, y = rearY, z = rearZ, rx = rearRX, ry = rearRY, rz = rearRZ } or nil, frontBone, rearBone)
end

function OpenPlateMenu(vehicle, vehicleData)
    local slider = exports.zerodream_sliderui
    local list = Config.plateList
    local areaList = {}
    local frontBoneList = {
        { text = '车身', value = 'chassis' },
        { text = '前保险杠', value = 'bumper_f' },
        { text = '引擎盖', value = 'bonnet' },
    }
    local rearBoneList = {
        { text = '车身', value = 'chassis' },
        { text = '后保险杠', value = 'bumper_r' },
        { text = '后备箱', value = 'boot' },
    }
    for k, v in pairs(Config.allowPrefixList) do
        table.insert(areaList, { text = v, value = v })
    end
    _g.isInEditor = true
    if not slider:IsContainerExists() then
        slider:CreateContainer('ZERODREAM PLATE', '车牌系统免费版', '25%', '70%', '5%', '5%', function()
            local plate = GetVehicleNumberPlateText(vehicle)
            RemovePlateForVehicle(vehicle)
            FreezeEntityPosition(vehicle, false)
            Wait(1000)
            _g.isInEditor = false
        end)
    else
        slider:RemoveAllElements()
    end
    local loaded = json.decode(json.encode(vehicleData))
    slider:CreateInput('plate_number', '输入车牌号码', '在这里输入你的车牌号码', loaded.number or 'B233MC', 'width: 100%', function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSelect('select_area', '选择牌照地区', '请选择车辆的牌照地区', loaded.prefix or '粤', areaList, 'width: 100%', function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSelect('select_type', '选择牌照类型', '请选择车辆的牌照类型', loaded.type or 'blue', list, 'width: 100%', function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateCheckbox('enable_front', '是否启用前车牌', loaded.front and true or false, '', function(checked)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSelect('select_front_bone', '前车牌固定处', '请选择前车牌的固定的位置', loaded.frontBone or 'chassis', frontBoneList, 'width: 100%', function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('front_x', '前车牌 X 偏移量', '前车牌相对车辆左右偏移量', loaded.front and loaded.front.x or 0.0, -5.0, 5.0, 0.001, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('front_y', '前车牌 Y 偏移量', '前车牌相对车辆前后偏移量', loaded.front and loaded.front.y or 0.0, -5.0, 5.0, 0.001, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('front_z', '前车牌 Z 偏移量', '前车牌相对车辆上下偏移量', loaded.front and loaded.front.z or 0.0, -5.0, 5.0, 0.001, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('front_rx', '前车牌 X 旋转量', '前车牌相对车辆 X 旋转量', loaded.front and loaded.front.rx or 0.0, -180.0, 180.0, 0.01, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('front_ry', '前车牌 Y 旋转量', '前车牌相对车辆 Y 旋转量', loaded.front and loaded.front.ry or 0.0, -180.0, 180.0, 0.01, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('front_rz', '前车牌 Z 旋转量', '前车牌相对车辆 Z 旋转量', loaded.front and loaded.front.rz or 0.0, -180.0, 180.0, 0.01, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateCheckbox('enable_rear', '是否启用后车牌', loaded.rear and true or false, '', function(checked)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSelect('select_rear_bone', '后车牌固定处', '请选择后车牌的固定的位置', loaded.rearBone or 'chassis', rearBoneList, 'width: 100%', function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('rear_x', '后车牌 X 偏移量', '后车牌相对车辆左右偏移量', loaded.rear and loaded.rear.x or 0.0, -5.0, 5.0, 0.001, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('rear_y', '后车牌 Y 偏移量', '后车牌相对车辆前后偏移量', loaded.rear and loaded.rear.y or 0.0, -5.0, 5.0, 0.001, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('rear_z', '后车牌 Z 偏移量', '后车牌相对车辆上下偏移量', loaded.rear and loaded.rear.z or 0.0, -5.0, 5.0, 0.001, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('rear_rx', '后车牌 X 旋转量', '后车牌相对车辆 X 旋转量', loaded.rear and loaded.rear.rx or 0.0, -180.0, 180.0, 0.01, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('rear_ry', '后车牌 Y 旋转量', '后车牌相对车辆 Y 旋转量', loaded.rear and loaded.rear.ry or 0.0, -180.0, 180.0, 0.01, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateSlider('rear_rz', '后车牌 Z 旋转量', '后车牌相对车辆 Z 旋转量', loaded.rear and loaded.rear.rz or 180.0, -180.0, 180.0, 0.01, nil, function(value)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateHtml('description_text', string.format('<p>每次修改车牌需要花费 <b style="color: rgb(147,178,88);">%s 元</b></p>', Config.platePrice))
    slider:CreateButton('refresh_plate', 'primary', '<i class="fa fa-car"></i>&nbsp;&nbsp;刷新车牌', 'width: 100%', function()
        RemovePlateForVehicle(vehicle)
        Citizen.Wait(100)
        MenuUpdateEvent(vehicle)
    end)
    slider:CreateButton('submit_plate', 'success', '<i class="fa fa-check"></i>&nbsp;&nbsp;提交车牌', 'width: 100%', function()
        local plate = slider:GetInputValue('plate_number')
        local prefix = slider:GetSelectValue('select_area')
        local plateType = slider:GetSelectValue('select_type')
        local front = slider:IsCheckboxChecked('enable_front')
        local rear = slider:IsCheckboxChecked('enable_rear')
        local frontPos = {
            x = slider:GetSliderValue('front_x'),
            y = slider:GetSliderValue('front_y'),
            z = slider:GetSliderValue('front_z'),
            rx = slider:GetSliderValue('front_rx'),
            ry = slider:GetSliderValue('front_ry'),
            rz = slider:GetSliderValue('front_rz'),
        }
        local rearPos = {
            x = slider:GetSliderValue('rear_x'),
            y = slider:GetSliderValue('rear_y'),
            z = slider:GetSliderValue('rear_z'),
            rx = slider:GetSliderValue('rear_rx'),
            ry = slider:GetSliderValue('rear_ry'),
            rz = slider:GetSliderValue('rear_rz'),
        }
        local frontBone = slider:GetSelectValue('select_front_bone')
        local rearBone = slider:GetSelectValue('select_rear_bone')
        if plate == '' then
            ZeroDream.Hud.SendNotification('车牌号码不能为空')
            return
        end
        if string.len(plate) > 8 then
            ZeroDream.Hud.SendNotification('车牌号码不能超过 8 个字符')
            return
        end
        if area == '' then
            ZeroDream.Hud.SendNotification('请选择车牌地区')
            return
        end
        if plateType == '' then
            ZeroDream.Hud.SendNotification('请选择车牌类型')
            return
        end
        local gtaPlate = GetVehicleNumberPlateText(vehicle)
        ZeroDream.Callbacks.Trigger('zerodream_vehplatefree:savePlate', function(result)
            if result.success then
                slider:RemoveContainer()
                ZeroDream.Hud.SendNotification('车牌保存成功')
            else
                ZeroDream.Hud.SendNotification(result.message)
            end
        end, gtaPlate, prefix, plate, plateType, front, rear, frontPos, rearPos, frontBone, rearBone)
    end)
    slider:CreateButton('cancel_close', 'warning', '<i class="fa fa-times"></i>&nbsp;&nbsp;取消修改', 'width: 100%', function()
        slider:RemoveContainer()
    end)
    slider:CreateButton('remove_plate', 'danger', '<i class="fa fa-trash"></i>&nbsp;&nbsp;移除车牌', 'width: 100%', function()
        local gtaPlate = GetVehicleNumberPlateText(vehicle)
        ZeroDream.Callbacks.Trigger('zerodream_vehplatefree:removePlate', function(result)
            if result.success then
                slider:RemoveContainer()
                ZeroDream.Hud.SendNotification('车牌移除成功')
            else
                ZeroDream.Hud.SendNotification(result.message)
            end
        end, gtaPlate)
    end)
    MenuUpdateEvent(vehicle)
end

Citizen.CreateThread(function()
    InitPlate()
    while true do
        for k, v in pairs(_g.loadedVehicle) do
            if not DoesEntityExist(k) then
                RemovePlateForVehicle(k)
            end
        end
        local coords = GetEntityCoords(PlayerPedId())
        local drives = IsPedInAnyVehicle(PlayerPedId()) and GetVehiclePedIsIn(PlayerPedId(), false) or 0
        for _, car in ipairs(GetGamePool('CVehicle')) do
            local plate = GetVehicleNumberPlateText(car)
            local dist = #(coords - GetEntityCoords(car))
            if dist < Config.updateDist then
                if _g.vehicleList[plate] and not _g.loadedVehicle[car] then
                    if not _g.isInEditor or car ~= drives then
                        local data = _g.vehicleList[plate]
                        DebugPrint('Thread 1: Load plate', plate, json.encode(data))
                        CreatePlateForVehicle(car, data.prefix, data.number, data.type, data.front, data.rear, data.frontBone or 'chassis', data.rearBone or 'chassis')
                    end
                elseif _g.vehicleList[plate] and _g.loadedVehicle[car].offsetZ ~= -GetVehicleSuspensionHeight(car) then
                    if not _g.isInEditor or car ~= drives then
                        local data = _g.vehicleList[plate]
                        DebugPrint('Thread 1: Update plate', plate, json.encode(data))
                        UpdatePlate(car, data.prefix, data.number, data.type, data.front, data.rear, data.frontBone or 'chassis', data.rearBone or 'chassis')
                    end
                end
            elseif _g.loadedVehicle[car] then
                DebugPrint('Thread 1: Remove plate', plate)
                RemovePlateForVehicle(car)
            end
        end
        Wait(500)
    end
end)

Citizen.CreateThread(function()
    while true do
        Wait(0)
        if IsPedInAnyVehicle(PlayerPedId()) and not _g.isInEditor then
            local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
            if GetPedInVehicleSeat(vehicle, -1) == PlayerPedId() then
                local find = false
                local pos  = GetEntityCoords(vehicle)
                for k, v in pairs(Config.changePlates) do
                    local distance = #(pos - vec3(v.x, v.y, v.z))
                    if distance < 20.0 then
                        find = true
                        if not _g.isInEditor and IsMinimapRendering() then
                            DrawMarker(36, v.x, v.y, v.z + 0.5, 0, 0, 0, 0, 0, 0, 1.5, 1.5, 1.5, 0, 120, 215, 150, true, true)
                            DrawMarker(43, v.x, v.y, v.z - 1.0, 0, 0, 0, 0, 0, v.h, 3.0, 6.0, 1.5, 0, 120, 215, 150, true, false)
                        end
                    end
                    if distance < v.s then
                        if IsMinimapRendering() then
                            ZeroDream.Hud.DrawLabel3D(vec3(v.x, v.y, v.z + 0.5), '按  ~INPUT_CONTEXT~自定义车辆牌照')
                        end
                        if IsControlJustPressed(0, 51) then
                            local plate = GetVehicleNumberPlateText(vehicle)
                            ZeroDream.Callbacks.Trigger("zerodream_vehplatefree:checkPerm", function(result)
                                if result.success then
                                    SetEntityCoords(vehicle, v.x, v.y, v.z)
                                    SetEntityHeading(vehicle, v.h)
                                    SetVehicleOnGroundProperly(vehicle)
                                    FreezeEntityPosition(vehicle, true)
                                    local data = _g.vehicleList[plate] or { prefix = '粤', number = 'B233MC', type = 'blue', front = { x = 0.0, y = 2.5, z = 0.0, rx = 0.0, ry = 0.0, rz = 0.0 }, rear = { x = 0.0, y = -2.5, z = 0.0, rx = 0.0, ry = 0.0, rz = 180.0 }, frontBone = 'chassis', rearBone = 'chassis' }
                                    OpenPlateMenu(vehicle, data)
                                    Wait(1000)
                                else
                                    ZeroDream.Hud.SendNotification(result.message)
                                end
                            end, plate)
                        end
                    end
                end
                if not find then
                    Wait(1000)
                end
            else
                Wait(1000)
            end
        else
            Wait(1000)
        end
    end
end)

RegisterNetEvent('zerodream_vehplatefree:syncPlates')
AddEventHandler('zerodream_vehplatefree:syncPlates', function(list, tokenRef)
    _g.vehicleList = list
    _g.tokenRef    = tokenRef
end)

RegisterNetEvent('zerodream_vehplatefree:syncPlate')
AddEventHandler('zerodream_vehplatefree:syncPlate', function(plate, data)
    _g.vehicleList[plate] = data
    for k, v in pairs(_g.loadedVehicle) do
        if DoesEntityExist(k) and GetVehicleNumberPlateText(k) == plate then
            if not _g.isInEditor or not IsPedInAnyVehicle(PlayerPedId()) then
                RemovePlateForVehicle(k)
            else
                local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
                if vehicle ~= k or GetPedInVehicleSeat(vehicle, -1) ~= PlayerPedId() then
                    RemovePlateForVehicle(k)
                end
            end
        end
    end
end)

AddEventHandler('onResourceStop', function(resource)
    if resource == GetCurrentResourceName() then
        for k, v in pairs(_g.plateSlots) do
            UnregisterPlate(k)
        end
    end
end)
回复

使用道具 举报

ChatGPT 发表于 2025-7-3 20:35:39 | 显示全部楼层
Aleeeee 发表于 2025-07-03 20:35
ZeroDream = exports.zerodream_core:GetSharedObject ...


从你提供的代码片段来看,暂时没有看到直接导致 `nil` 值拼接的问题,但需要注意以下几点:

1. **`IsPlateNumber` 函数中的逻辑**:在该函数中,`string.match(text, "^+$")` 的正则表达式似乎有问题。`^+$` 表示字符串中的一个或多个 `+` 字符。可能你是想检查是否符合某个特定的规则,你应该确认这是你的意图。

2. **DebugPrint 的使用**:在调用 `DebugPrint` 的地方,确保传递的参数不为 `nil`,否则可能会在打印时导致拼接错误。

3. **`Config.debug`**:确保 `Config` 表是存在并且合法的。如果 `Config` 中的 `debug` 属性是 `nil`,那么 `DebugPrint` 在某些地方也可能导致错误。

4. **在代码其他部分查找 `err` 的来源**:由于错误提示是关于 `err` 的问题,你可以在代码的其他部分(特别是在处理错误的地方)查找是否有对 `err` 变量的赋值,如果 `err` 是从某个返回值中取得的,确保这个返回值不会是 `nil`。

5. **添加额外的日志**:在可能出错的地方添加更多的 `print` 语句,这样可以帮助你确定 `nil` 值是在哪里产生的。例如,在函数开头和重要操作后添加 `print` 来输出相关变量的值。

如果你能提供更多关于如何使用这些函数的上下文代码,或者你收到错误的具体行号和位置,我能更容易地帮助你找到并解决问题。希望这些能帮到你!
回复

使用道具 举报

文明发言,和谐互动
文明发言,和谐互动
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|FiveM技术教程分享 ( 冀ICP备2021005225号-1 ) |网站地图

GMT+8, 2025-7-27 17:48 , Processed in 0.069010 second(s), 9 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

© 2001-2013 ELITE论坛【技术无价-分享快乐】

快速回复 返回顶部 返回列表