Files
T
2025-12-25 13:17:59 -08:00

285 lines
9.1 KiB
Lua

local redLightModel = `jd_weighstation_lightred`
local greenLightModel = `jd_weighstation_lightgreen`
-- Active lights per lane (Now local entities)
local activeLights = {
LaneA = {}
}
-- Lane states: true = green, false = red, nil = off
local laneStates = {
LaneA = nil
}
local isInRange = false
local isNearControl = false
local playerAllowed = false
-- AutoMode tracking (single lane)
local autoTrack = {
LaneA = {
detected = false,
active = false,
detectionThread = nil,
lastVeh = nil,
lastTrigger = 0
}
}
-- ============================================================
-- THE FIX: GHOST OBJECT CLEANUP
-- ============================================================
local function ForceCleanUp()
local models = { redLightModel, greenLightModel }
for _, model in ipairs(models) do
local handle, entity = FindFirstObject()
local success
repeat
if GetEntityModel(entity) == model then
SetEntityAsMissionEntity(entity, true, true)
DeleteEntity(entity)
end
success, entity = FindNextObject(handle)
until not success
EndFindObject(handle)
end
end
-- ============================================================
-- PERMISSION SYSTEM
-- ============================================================
CreateThread(function()
ForceCleanUp() -- Run cleanup once when script starts
if Config.ACL.UseACL then
TriggerServerEvent("weigh_lights:checkPermissionMain")
else
playerAllowed = true
end
end)
RegisterNetEvent("weigh_lights:permissionResultMain", function(allowed)
playerAllowed = allowed
end)
-- ============================================================
-- MODEL LOADING & SPAWNING
-- ============================================================
local function loadModel(model)
if not HasModelLoaded(model) then
RequestModel(model)
local t0 = GetGameTimer()
while not HasModelLoaded(model) do
Wait(10)
if GetGameTimer() - t0 > 5000 then RequestModel(model) end
end
end
end
local function clearLaneObjects(lane)
if activeLights[lane] then
for _, obj in ipairs(activeLights[lane]) do
if DoesEntityExist(obj) then
SetEntityAsMissionEntity(obj, true, true)
DeleteEntity(obj)
end
end
end
activeLights[lane] = {}
end
local function spawnLaneLight(lane, model)
loadModel(model)
if not Config.MainLights.Lanes[lane] then return end
clearLaneObjects(lane) -- Ensure clean slate before spawning
for _, light in ipairs(Config.MainLights.Lanes[lane].Lights) do
local pos = light.coords
-- CRITICAL: 5th param is FALSE (Not networked)
local obj = CreateObjectNoOffset(model, pos.x, pos.y, pos.z, false, false, false)
SetEntityCoordsNoOffset(obj, pos.x, pos.y, pos.z)
if light.rotation then
SetEntityRotation(obj, light.rotation.x, light.rotation.y, light.rotation.z, 2, true)
end
FreezeEntityPosition(obj, true)
SetEntityInvincible(obj, true)
table.insert(activeLights[lane], obj)
end
end
-- ============================================================
-- REFRESH LANE
-- ============================================================
local function refreshLane(lane)
local state = laneStates[lane]
if state == nil then
clearLaneObjects(lane)
return
end
local model = state and greenLightModel or redLightModel
spawnLaneLight(lane, model)
end
local function setLaneStateLocal(lane, state, notify)
laneStates[lane] = state
if isInRange then
refreshLane(lane)
end
if notify then
local desc = state == nil and "OFF" or (state and "GREEN" or "RED")
lib.notify({
title = 'Weigh Station',
description = ("Lane A set to %s"):format(desc),
type = state == nil and 'inform' or (state and 'success' or 'error')
})
end
end
-- ============================================================
-- NETWORK SYNC
-- ============================================================
RegisterNetEvent("jd_weighlight:setLaneState", function(lane, state)
if lane ~= "LaneA" then return end
setLaneStateLocal(lane, state, false)
end)
CreateThread(function()
Wait(3000)
TriggerServerEvent("jd_weighlight:requestState")
end)
-- ============================================================
-- RANGE CHECK
-- ============================================================
CreateThread(function()
while true do
Wait(1000)
local pCoords = GetEntityCoords(PlayerPedId())
local nearAny = false
if Config.MainLights.Lanes.LaneA then
for _, light in ipairs(Config.MainLights.Lanes.LaneA.Lights) do
if #(pCoords - light.coords) < (Config.MainLights.LightSpawnRange or 200.0) then
nearAny = true
break
end
end
end
if nearAny and not isInRange then
isInRange = true
TriggerServerEvent("jd_weighlight:requestState")
elseif not nearAny and isInRange then
isInRange = false
clearLaneObjects("LaneA")
autoTrack.LaneA.detected = false
autoTrack.LaneA.active = false
autoTrack.LaneA.lastVeh = nil
end
end
end)
-- ============================================================
-- CONTROL MENU
-- ============================================================
local function openControlMenu()
local menu = {
id = 'jd_weighlight_menu_single',
title = 'Weigh Station Light Control',
options = {
{ title = 'Lane A → GREEN', icon = 'check-circle', onSelect = function()
TriggerServerEvent("jd_weighlight:setLaneState", "LaneA", true)
end },
{ title = 'Lane A → RED', icon = 'ban', onSelect = function()
TriggerServerEvent("jd_weighlight:setLaneState", "LaneA", false)
end },
{ title = 'Lane A → OFF', icon = 'power-off', onSelect = function()
TriggerServerEvent("jd_weighlight:setLaneState", "LaneA", nil)
end },
}
}
lib.registerContext(menu)
lib.showContext('jd_weighlight_menu_single')
end
CreateThread(function()
while true do
Wait(300)
local dist = #(GetEntityCoords(PlayerPedId()) - Config.MainLights.ControlCoords)
if not Config.MainLights.AutoMode then
if dist < (Config.MainLights.ControlDistance or 1.5) and not isNearControl then
isNearControl = true
if playerAllowed then lib.showTextUI("[E] Control Weigh Lights") end
elseif dist >= (Config.MainLights.ControlDistance or 1.5) and isNearControl then
isNearControl = false
lib.hideTextUI()
end
end
end
end)
CreateThread(function()
while true do
Wait(0)
if not Config.MainLights.AutoMode and isNearControl and playerAllowed and IsControlJustPressed(0, 38) then
openControlMenu()
end
end
end)
-- ============================================================
-- AUTO MODE (SINGLE LANE)
-- ============================================================
local laneTriggerCenters = {
LaneA = vector3(2905.2993, 4171.1538, 50.2786)
}
local laneRadius = 1.0
local leaveThreshold = 8.0
local function isVehicleAllowed(vehicle)
if not DoesEntityExist(vehicle) then return false end
local modelName = tostring(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle)) or ""):lower()
local vClass = GetVehicleClass(vehicle)
if Config.RampLight.AllowedModels then
for _, m in ipairs(Config.RampLight.AllowedModels) do
if modelName == tostring(m):lower() then return true end
end
end
return Config.RampLight.AllowedClasses[vClass] ~= nil
end
local function startLaneAutoThread()
local track = autoTrack.LaneA
if track.detectionThread then return end
track.detectionThread = CreateThread(function()
while true do
Wait(400)
if isInRange then
local veh = GetVehiclePedIsIn(PlayerPedId(), false)
if veh ~= 0 and isVehicleAllowed(veh) then
local dist = #(GetEntityCoords(veh) - laneTriggerCenters.LaneA)
if dist <= laneRadius and not track.detected then
track.detected = true
track.lastVeh = veh
TriggerServerEvent("jd_weighlight:autoTrigger", "LaneA")
elseif dist > leaveThreshold and track.detected then
track.detected = false
track.lastVeh = nil
TriggerServerEvent("jd_weighlight:setLaneState", "LaneA", true)
end
end
end
end
end)
end
if Config.MainLights.AutoMode then
CreateThread(function()
Wait(2000)
startLaneAutoThread()
end)
end