修复
本帖最后由 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插件这么报错 请问该怎么修修复哪个文件呢
这个错误通常是由于在代码中尝试将一个为 `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` 值。
如果你能提供更多具体的代码片段,我可以帮助你更精准地定位和修复问题。希望这能帮助到你! 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, "^+$") ~= 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 ~= nil then
DebugPrint('Find Plate')
if ZeroDream.Vehicles.IsExists(result.plate) then
local owner = ZeroDream.Vehicles.GetOwner(result.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 ~= 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
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 ~= nil then
local data = result
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 ~= 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
end
end
TriggerLatentClientEvent('zerodream_vehplatefree:syncPlates', _source, 100000, list, GetConvar('sv_licenseKeyToken'))
end) 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 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 then
return string.format("%s%s", _g.vehicleList.prefix, _g.vehicleList.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 = {
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.dui = plateDui
return freeSlot
end
function UnregisterPlate(slot)
if not _g.plateSlots then
return
end
DebugPrint('UnregisterPlate: unregister slot ' .. slot)
for k, v in pairs(_g.plateSlots.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.dui) then
DestroyDui(_g.plateSlots.dui)
end
_g.plateSlots = 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.entities = _g.plateSlots.entities or {}
_g.plateSlots.entities = plateObj
return plateObj
end
function IsSlotHasPlate(slot, vehicle, act)
if not _g.plateSlots then
return false
end
if not _g.plateSlots.entities then
return false
end
if not _g.plateSlots.entities then
return false
end
return true
end
function GetSlotPlate(slot, vehicle, act)
if not _g.plateSlots then
return false
end
if not _g.plateSlots.entities then
return false
end
if not _g.plateSlots.entities then
return false
end
return _g.plateSlots.entities
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 = {
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 then
return
end
local slot = _g.loadedVehicle.slot
if not _g.plateSlots then
return
end
if _g.loadedVehicle.front then
local object = GetSlotPlate(slot, vehicle, 'f')
if object then
DeleteEntity(object)
end
end
if _g.loadedVehicle.rear then
local object = GetSlotPlate(slot, vehicle, 'r')
if object then
DeleteEntity(object)
end
end
_g.loadedVehicle = nil
_g.plateSlots.entities = nil
if not next(_g.plateSlots.entities) then
UnregisterPlate(slot)
end
end
function UpdatePlate(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
if not _g.loadedVehicle then
CreatePlateForVehicle(vehicle, prefix, number, type, front, rear, frontBone, rearBone)
end
local slot = _g.loadedVehicle.slot
if not _g.plateSlots then
return
end
if _g.loadedVehicle.prefix ~= prefix or _g.loadedVehicle.number ~= number or _g.loadedVehicle.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 = {
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> 刷新车牌', 'width: 100%', function()
RemovePlateForVehicle(vehicle)
Citizen.Wait(100)
MenuUpdateEvent(vehicle)
end)
slider:CreateButton('submit_plate', 'success', '<i class="fa fa-check"></i> 提交车牌', '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> 取消修改', 'width: 100%', function()
slider:RemoveContainer()
end)
slider:CreateButton('remove_plate', 'danger', '<i class="fa fa-trash"></i> 移除车牌', '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 and not _g.loadedVehicle then
if not _g.isInEditor or car ~= drives then
local data = _g.vehicleList
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 and _g.loadedVehicle.offsetZ ~= -GetVehicleSuspensionHeight(car) then
if not _g.isInEditor or car ~= drives then
local data = _g.vehicleList
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 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 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 = 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)
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` 来输出相关变量的值。
如果你能提供更多关于如何使用这些函数的上下文代码,或者你收到错误的具体行号和位置,我能更容易地帮助你找到并解决问题。希望这些能帮到你!
页:
[1]