adding new Weigh Station pack
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
lua54 'yes'
|
||||
author 'John Chin'
|
||||
description 'Weigh Station Shared Props'
|
||||
version '1.0.0'
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation-shared/stream/jd_weighstation_ext.ydr
LFS
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation-shared/stream/jd_weighstation_ext.ytd
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation-shared/stream/jd_weighstation_int.ydr
LFS
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation-shared/stream/jd_weighstation_int.ytd
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+285
@@ -0,0 +1,285 @@
|
||||
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
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
-- ============================================================
|
||||
-- LANE STATE (SINGLE LANE)
|
||||
-- ============================================================
|
||||
local laneStates = {
|
||||
LaneA = Config.MainLights and Config.MainLights.AutoMode and true or nil
|
||||
}
|
||||
|
||||
-- Prevent multiple timers from overlapping
|
||||
local autoTimers = {
|
||||
LaneA = false
|
||||
}
|
||||
|
||||
-- ============================================================
|
||||
-- SEND STATE TO PLAYER
|
||||
-- ============================================================
|
||||
RegisterNetEvent("jd_weighlight:requestState")
|
||||
AddEventHandler("jd_weighlight:requestState", function()
|
||||
local src = source
|
||||
-- Sends the current server truth to the client
|
||||
TriggerClientEvent("jd_weighlight:setLaneState", src, "LaneA", laneStates.LaneA)
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- SET LANE STATE (MANUAL)
|
||||
-- ============================================================
|
||||
RegisterNetEvent("jd_weighlight:setLaneState")
|
||||
AddEventHandler("jd_weighlight:setLaneState", function(lane, state)
|
||||
local src = source
|
||||
if lane ~= "LaneA" then return end
|
||||
|
||||
-- ACL check
|
||||
if Config.ACL.UseACL and not IsPlayerAceAllowed(src, Config.ACL.MainLights) then
|
||||
print(("[weigh_lights] Player %d denied access"):format(src))
|
||||
return
|
||||
end
|
||||
|
||||
-- Update the Master State and tell EVERYONE to update their local objects
|
||||
laneStates.LaneA = state
|
||||
TriggerClientEvent("jd_weighlight:setLaneState", -1, "LaneA", state)
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- AUTO MODE TRIGGER
|
||||
-- ============================================================
|
||||
RegisterNetEvent("jd_weighlight:autoTrigger")
|
||||
AddEventHandler("jd_weighlight:autoTrigger", function(lane)
|
||||
if lane ~= "LaneA" or not Config.MainLights.AutoMode then return end
|
||||
|
||||
-- Safety: If a timer is already running, don't start another one
|
||||
if autoTimers.LaneA then return end
|
||||
|
||||
-- Turn the light RED for everyone
|
||||
laneStates.LaneA = false
|
||||
TriggerClientEvent("jd_weighlight:setLaneState", -1, "LaneA", false)
|
||||
|
||||
autoTimers.LaneA = true
|
||||
CreateThread(function()
|
||||
Wait(30000) -- 30 Seconds
|
||||
|
||||
autoTimers.LaneA = false
|
||||
|
||||
-- Only set back to GREEN if a staff member hasn't manually changed it or turned it OFF
|
||||
if laneStates.LaneA == false then
|
||||
laneStates.LaneA = true
|
||||
TriggerClientEvent("jd_weighlight:setLaneState", -1, "LaneA", true)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- PERMISSION CHECK
|
||||
-- ============================================================
|
||||
RegisterNetEvent("weigh_lights:checkPermissionMain")
|
||||
AddEventHandler("weigh_lights:checkPermissionMain", function()
|
||||
local src = source
|
||||
local allowed = true
|
||||
|
||||
if Config.ACL.UseACL then
|
||||
allowed = IsPlayerAceAllowed(src, Config.ACL.MainLights)
|
||||
end
|
||||
|
||||
TriggerClientEvent("weigh_lights:permissionResultMain", src, allowed)
|
||||
end)
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
local lightSets = {}
|
||||
local playerAllowed = false
|
||||
|
||||
-- ============================================================
|
||||
-- REQUEST PERMISSION IF ACL IS ENABLED
|
||||
-- ============================================================
|
||||
CreateThread(function()
|
||||
if Config.ACL.UseACL then
|
||||
TriggerServerEvent("weigh_lights:checkPermission")
|
||||
else
|
||||
playerAllowed = true -- bypass permission
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent("weigh_lights:permissionResult", function(allowed)
|
||||
playerAllowed = allowed
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- LOAD CONFIGURED AMBER LIGHT SETS
|
||||
-- ============================================================
|
||||
CreateThread(function()
|
||||
for _, cfg in ipairs(Config.RoadSigns.LightSets) do
|
||||
table.insert(lightSets, {
|
||||
name = cfg.name,
|
||||
model = cfg.model,
|
||||
coordsA = cfg.coordsA,
|
||||
coordsB = cfg.coordsB,
|
||||
rotA = cfg.rotA or vector3(0.0, 0.0, 0.0),
|
||||
rotB = cfg.rotB or vector3(0.0, 0.0, 0.0),
|
||||
control = cfg.control,
|
||||
distance = cfg.distance or 2.0,
|
||||
propA = nil,
|
||||
propB = nil,
|
||||
flashing = false,
|
||||
pointCreated = false
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- REQUEST SYNC EVERY 10 SECONDS
|
||||
-- ============================================================
|
||||
CreateThread(function()
|
||||
while true do
|
||||
TriggerServerEvent("weigh_lights:requestSync")
|
||||
Wait(10000)
|
||||
end
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- SYNC ALL STATES
|
||||
-- ============================================================
|
||||
RegisterNetEvent("weigh_lights:syncAll", function(states)
|
||||
for _, set in ipairs(lightSets) do
|
||||
if states[set.name] ~= nil then
|
||||
local desired = states[set.name]
|
||||
|
||||
if desired and not set.flashing then
|
||||
StartFlashing(set)
|
||||
set.flashing = true
|
||||
elseif not desired and set.flashing then
|
||||
StopFlashing(set)
|
||||
set.flashing = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- SYNC A SINGLE SET
|
||||
-- ============================================================
|
||||
RegisterNetEvent("weigh_lights:syncSingle", function(setName, state)
|
||||
for _, set in ipairs(lightSets) do
|
||||
if set.name == setName then
|
||||
if state and not set.flashing then
|
||||
StartFlashing(set)
|
||||
set.flashing = true
|
||||
elseif not state and set.flashing then
|
||||
StopFlashing(set)
|
||||
set.flashing = false
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- FLASHING LOGIC
|
||||
-- ============================================================
|
||||
function StartFlashing(set)
|
||||
if DoesEntityExist(set.propA) then DeleteEntity(set.propA) end
|
||||
if DoesEntityExist(set.propB) then DeleteEntity(set.propB) end
|
||||
|
||||
if not HasModelLoaded(set.model) then
|
||||
RequestModel(set.model)
|
||||
while not HasModelLoaded(set.model) do Wait(10) end
|
||||
end
|
||||
|
||||
local zOffset = -0.09
|
||||
local posA = set.coordsA + vector3(0.0, 0.0, zOffset)
|
||||
local posB = set.coordsB + vector3(0.0, 0.0, zOffset)
|
||||
|
||||
set.propA = CreateObject(set.model, posA.x, posA.y, posA.z, false, false, false)
|
||||
set.propB = CreateObject(set.model, posB.x, posB.y, posB.z, false, false, false)
|
||||
|
||||
SetEntityRotation(set.propA, set.rotA.x, set.rotA.y, set.rotA.z, 2, true)
|
||||
SetEntityRotation(set.propB, set.rotB.x, set.rotB.y, set.rotB.z, 2, true)
|
||||
|
||||
SetEntityVisible(set.propA, false, false)
|
||||
SetEntityVisible(set.propB, false, false)
|
||||
|
||||
SetEntityAsMissionEntity(set.propA, true, true)
|
||||
SetEntityAsMissionEntity(set.propB, true, true)
|
||||
|
||||
CreateThread(function()
|
||||
local toggle = true
|
||||
while set.flashing do
|
||||
if toggle then
|
||||
SetEntityVisible(set.propA, true, false)
|
||||
SetEntityVisible(set.propB, false, false)
|
||||
else
|
||||
SetEntityVisible(set.propA, false, false)
|
||||
SetEntityVisible(set.propB, true, false)
|
||||
end
|
||||
toggle = not toggle
|
||||
Wait(500)
|
||||
end
|
||||
|
||||
if DoesEntityExist(set.propA) then DeleteEntity(set.propA) end
|
||||
if DoesEntityExist(set.propB) then DeleteEntity(set.propB) end
|
||||
set.propA = nil
|
||||
set.propB = nil
|
||||
end)
|
||||
end
|
||||
|
||||
function StopFlashing(set)
|
||||
set.flashing = false
|
||||
end
|
||||
|
||||
-- ============================================================
|
||||
-- OX_LIB E-KEY INTERACTION (with ACL toggle)
|
||||
-- ============================================================
|
||||
CreateThread(function()
|
||||
while #lightSets == 0 do Wait(100) end
|
||||
|
||||
-- wait until permission is determined
|
||||
if Config.ACL.UseACL then
|
||||
while playerAllowed == false do Wait(100) end
|
||||
end
|
||||
|
||||
for _, set in ipairs(lightSets) do
|
||||
if set.control and not set.pointCreated then
|
||||
local point = lib.points.new(set.control, set.distance)
|
||||
set.pointCreated = true
|
||||
|
||||
function point:nearby()
|
||||
-- bypass or check permission
|
||||
if Config.ACL.UseACL and not playerAllowed then
|
||||
lib.hideTextUI()
|
||||
return
|
||||
end
|
||||
|
||||
if self.currentDistance < set.distance then
|
||||
lib.showTextUI("[E] Toggle Amber Light: " .. set.name)
|
||||
|
||||
if IsControlJustPressed(0, 38) then
|
||||
TriggerServerEvent("weigh_lights:toggleLight", set.name, not set.flashing)
|
||||
end
|
||||
else
|
||||
lib.hideTextUI()
|
||||
end
|
||||
end
|
||||
|
||||
function point:onExit()
|
||||
lib.hideTextUI()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
local lightStates = {}
|
||||
|
||||
-- ============================================================
|
||||
-- REQUEST SYNC
|
||||
-- ============================================================
|
||||
RegisterNetEvent("weigh_lights:requestSync")
|
||||
AddEventHandler("weigh_lights:requestSync", function()
|
||||
local src = source
|
||||
TriggerClientEvent("weigh_lights:syncAll", src, lightStates)
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- TOGGLE LIGHT
|
||||
-- ============================================================
|
||||
RegisterNetEvent("weigh_lights:toggleLight")
|
||||
AddEventHandler("weigh_lights:toggleLight", function(setName, newState)
|
||||
local src = source
|
||||
|
||||
-- Only check ACL if UseACL is true
|
||||
if Config.ACL.UseACL then
|
||||
if not IsPlayerAceAllowed(src, Config.ACL.AmberLights) then
|
||||
print(("[weigh_lights] Player %d tried to toggle light '%s' without permission!"):format(src, setName))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
lightStates[setName] = newState
|
||||
TriggerClientEvent("weigh_lights:syncSingle", -1, setName, newState)
|
||||
end)
|
||||
|
||||
-- ============================================================
|
||||
-- CHECK PERMISSION
|
||||
-- ============================================================
|
||||
RegisterNetEvent("weigh_lights:checkPermission")
|
||||
AddEventHandler("weigh_lights:checkPermission", function()
|
||||
local src = source
|
||||
local allowed = true -- default allow if ACL disabled
|
||||
|
||||
if Config.ACL.UseACL then
|
||||
allowed = IsPlayerAceAllowed(src, Config.ACL.AmberLights)
|
||||
end
|
||||
|
||||
TriggerClientEvent("weigh_lights:permissionResult", src, allowed)
|
||||
end)
|
||||
@@ -0,0 +1,185 @@
|
||||
-- WeighUi/client.lua
|
||||
local uiOpen = false
|
||||
local checkDistance = 4.0
|
||||
local truckWeights = {}
|
||||
local truckTrailers = {}
|
||||
local trucksOnLane = {}
|
||||
local lastLaneWeight = {}
|
||||
|
||||
local serverCallbacks = {}
|
||||
|
||||
-- =========================
|
||||
-- CUSTOM COORDINATES
|
||||
-- =========================
|
||||
local laneTriggerCenters = {
|
||||
LaneA = vector3(2905.2993, 4171.1538, 50.2786)
|
||||
}
|
||||
|
||||
-- =========================
|
||||
-- Helpers
|
||||
-- =========================
|
||||
local function IsModelInList(modelHash, list)
|
||||
for _, name in ipairs(list or {}) do
|
||||
if GetHashKey(name) == modelHash then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TriggerServerCallback(name, cb, ...)
|
||||
local id = math.random(1, 999999)
|
||||
serverCallbacks[id] = cb
|
||||
TriggerServerEvent(name, id, ...)
|
||||
end
|
||||
|
||||
RegisterNetEvent("weighstation:serverCallback", function(id, ...)
|
||||
if serverCallbacks[id] then
|
||||
serverCallbacks[id](...)
|
||||
serverCallbacks[id] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
-- =========================
|
||||
-- Lane initialization
|
||||
-- =========================
|
||||
trucksOnLane["LaneA"] = {}
|
||||
lastLaneWeight["LaneA"] = nil
|
||||
|
||||
-- =========================
|
||||
-- UI Logic
|
||||
-- =========================
|
||||
local function ToggleUI(open)
|
||||
uiOpen = open
|
||||
SetNuiFocus(open, open)
|
||||
SendNUIMessage({ action = open and "showUI" or "hideUI" })
|
||||
|
||||
if open then
|
||||
TriggerServerCallback("weighstation:getRecentVehicles", function(recent)
|
||||
SendNUIMessage({ action = "updateRecentVehicles", recent = recent })
|
||||
end)
|
||||
TriggerServerCallback("weighstation:getStats", function(stats)
|
||||
SendNUIMessage({
|
||||
action = "updateStats",
|
||||
totalTrucks = stats.totalTrucks or 0,
|
||||
avgWeight = stats.avgWeight or 0
|
||||
})
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local function ShowPopup(text)
|
||||
SendNUIMessage({ action = "showPopup", text = text })
|
||||
end
|
||||
|
||||
local function HidePopup()
|
||||
SendNUIMessage({ action = "hidePopup" })
|
||||
end
|
||||
|
||||
-- =========================
|
||||
-- Detection Threads
|
||||
-- =========================
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(0)
|
||||
local ped = PlayerPedId()
|
||||
local pos = GetEntityCoords(ped)
|
||||
local controlPos = Config.MainLights.ControlCoords
|
||||
local dist = #(pos - controlPos)
|
||||
|
||||
if dist < (Config.MainLights.ControlDistance or 2.0) then
|
||||
ShowPopup("[G] Open Weigh Station")
|
||||
if IsControlJustPressed(0, 47) and not uiOpen then
|
||||
ToggleUI(true)
|
||||
end
|
||||
else
|
||||
HidePopup()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
CreateThread(function()
|
||||
while true do
|
||||
Wait(1000)
|
||||
local vehicles = GetGamePool('CVehicle')
|
||||
local laneName = "LaneA"
|
||||
local laneCenter = laneTriggerCenters[laneName]
|
||||
|
||||
if laneCenter then
|
||||
local laneWeight = nil
|
||||
local laneTruckFound = nil
|
||||
local minDist = checkDistance + 0.01
|
||||
|
||||
for _, vehicle in ipairs(vehicles) do
|
||||
if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then
|
||||
local model = GetEntityModel(vehicle)
|
||||
|
||||
if IsModelInList(model, Config.RampLight.AllowedModels) then
|
||||
local vehiclePos = GetEntityCoords(vehicle)
|
||||
local distToLane = #(vehiclePos - laneCenter)
|
||||
|
||||
if distToLane <= checkDistance and distToLane < minDist then
|
||||
minDist = distToLane
|
||||
local hasTrailer, trailer = GetVehicleTrailerVehicle(vehicle)
|
||||
local plate = GetVehicleNumberPlateText(vehicle)
|
||||
|
||||
-- PERSISTENT WEIGHT LOGIC START
|
||||
if not truckWeights[vehicle] or truckTrailers[vehicle] ~= trailer then
|
||||
|
||||
-- 1. Generate Seed from License Plate
|
||||
local seed = 0
|
||||
for i = 1, #plate do
|
||||
seed = seed + string.byte(plate, i)
|
||||
end
|
||||
|
||||
-- 2. Set Seed (Forces math.random to be identical to Station 02)
|
||||
math.randomseed(seed)
|
||||
|
||||
if hasTrailer and trailer ~= 0 then
|
||||
local trailerModel = GetEntityModel(trailer)
|
||||
if IsModelInList(trailerModel, Config.RampLight.HeavyModels) then
|
||||
truckWeights[vehicle] = math.random(85000, 125000)
|
||||
elseif IsModelInList(trailerModel, Config.RampLight.LightModels) then
|
||||
truckWeights[vehicle] = math.random(35000, 55000)
|
||||
else
|
||||
truckWeights[vehicle] = math.random(40000, 100000)
|
||||
end
|
||||
else
|
||||
truckWeights[vehicle] = math.random(32000, 45000) -- Bobtail
|
||||
end
|
||||
|
||||
-- 3. Reset Seed for other system functions
|
||||
math.randomseed(GetGameTimer())
|
||||
|
||||
truckTrailers[vehicle] = trailer
|
||||
local truckModel = GetDisplayNameFromVehicleModel(model)
|
||||
local trailerModelName = (hasTrailer and trailer ~= 0) and GetDisplayNameFromVehicleModel(GetEntityModel(trailer)) or nil
|
||||
|
||||
TriggerServerEvent("weighstation:logTruck", plate, truckModel, trailerModelName, truckWeights[vehicle])
|
||||
end
|
||||
-- PERSISTENT WEIGHT LOGIC END
|
||||
|
||||
laneWeight = truckWeights[vehicle]
|
||||
laneTruckFound = vehicle
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if lastLaneWeight[laneName] ~= laneWeight then
|
||||
lastLaneWeight[laneName] = laneWeight
|
||||
SendNUIMessage({
|
||||
action = "updateWeight",
|
||||
lane = laneName,
|
||||
weight = laneWeight,
|
||||
vehicle = laneTruckFound or nil
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNUICallback('closeUI', function(data, cb)
|
||||
ToggleUI(false)
|
||||
cb('ok')
|
||||
end)
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const win = document.getElementById("browser-window");
|
||||
const closeBtn = document.getElementById("close-btn");
|
||||
|
||||
// Lane status (Lane B Removed)
|
||||
const statusLaneA = document.getElementById("status-laneA");
|
||||
|
||||
// Recent vehicles log
|
||||
const recentVehicles = document.getElementById("recent-vehicles");
|
||||
|
||||
// Totals / Summary
|
||||
const totalTrucksEl = document.getElementById("total-trucks");
|
||||
const avgWeightEl = document.getElementById("avg-weight");
|
||||
const overweightCountEl = document.getElementById("overweight-count");
|
||||
|
||||
// Popup Logic (Keep existing)
|
||||
const popup = document.createElement("div");
|
||||
popup.id = "popup";
|
||||
popup.style.position = "fixed";
|
||||
popup.style.top = "20px";
|
||||
popup.style.left = "20px";
|
||||
popup.style.padding = "10px 20px";
|
||||
popup.style.backgroundColor = "#000080";
|
||||
popup.style.color = "#fff";
|
||||
popup.style.fontFamily = "MS Sans Serif, Arial, sans-serif";
|
||||
popup.style.fontSize = "14px";
|
||||
popup.style.fontWeight = "bold";
|
||||
popup.style.border = "2px solid #000";
|
||||
popup.style.display = "none";
|
||||
popup.style.zIndex = "9999";
|
||||
popup.style.borderRadius = "4px";
|
||||
document.body.appendChild(popup);
|
||||
|
||||
let recentVehiclesData = [];
|
||||
let totalTrucks = 0;
|
||||
let totalWeight = 0;
|
||||
let overweightCount = 0;
|
||||
let loggedVehicles = {};
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
const data = event.data;
|
||||
|
||||
if (data.action === "showUI") {
|
||||
win.style.display = "block";
|
||||
document.body.style.cursor = "default";
|
||||
} else if (data.action === "hideUI") {
|
||||
win.style.display = "none";
|
||||
document.body.style.cursor = "none";
|
||||
} else if (data.action === "showPopup") {
|
||||
popup.innerText = data.text;
|
||||
popup.style.display = "block";
|
||||
} else if (data.action === "hidePopup") {
|
||||
popup.style.display = "none";
|
||||
} else if (data.action === "updateWeight") {
|
||||
// Filter: Only update if the data is for LaneA
|
||||
if (data.lane !== "LaneA") return;
|
||||
|
||||
const laneWeightEl = document.getElementById("laneA-weight");
|
||||
laneWeightEl.innerText = data.weight ? data.weight + " LBS" : "-- LBS";
|
||||
|
||||
if (data.weight) {
|
||||
statusLaneA.innerText = data.weight > 80000 ? `Lane A: ⚠️ Overweight` : `Lane A: Occupied`;
|
||||
} else {
|
||||
statusLaneA.innerText = `Lane A: Open`;
|
||||
}
|
||||
|
||||
if (data.vehicle && data.weight && !loggedVehicles[data.vehicle]) {
|
||||
loggedVehicles[data.vehicle] = true;
|
||||
totalTrucks++;
|
||||
totalWeight += data.weight;
|
||||
if (data.weight > 80000) overweightCount++;
|
||||
|
||||
totalTrucksEl.innerText = totalTrucks;
|
||||
avgWeightEl.innerText = Math.floor(totalWeight / totalTrucks);
|
||||
overweightCountEl.innerText = overweightCount;
|
||||
|
||||
const entry = `${new Date().toLocaleTimeString()} - Lane A - ${data.weight} LBS`;
|
||||
recentVehiclesData.unshift(entry);
|
||||
if (recentVehiclesData.length > 10) recentVehiclesData.pop();
|
||||
recentVehicles.innerHTML = recentVehiclesData.map(e => `<li>${e}</li>`).join("");
|
||||
}
|
||||
|
||||
if (!data.weight && data.vehicle) {
|
||||
loggedVehicles[data.vehicle] = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
closeBtn.addEventListener("click", () => {
|
||||
fetch(`https://${GetParentResourceName()}/closeUI`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({})
|
||||
}).finally(() => {
|
||||
win.style.display = "none";
|
||||
document.body.style.cursor = "none";
|
||||
});
|
||||
});
|
||||
});
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
body {
|
||||
font-family: "MS Sans Serif", Arial, sans-serif;
|
||||
background-color: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Browser window */
|
||||
#browser-window {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
background-color: #c0c0c0;
|
||||
border: 3px solid #000;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: none;
|
||||
box-shadow: 7px 7px 0px #000;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Top bar */
|
||||
#browser-topbar {
|
||||
height: 30px;
|
||||
background-color: #000080;
|
||||
color: #fff;
|
||||
padding: 6px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* URL tab */
|
||||
#tab {
|
||||
font-weight: normal;
|
||||
background-color: #c0c0c0;
|
||||
color: #000;
|
||||
padding: 4px 8px;
|
||||
border: 2px inset #fff;
|
||||
margin-left: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Close button */
|
||||
#close-btn {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
#close-btn:hover {
|
||||
background: #ff0000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Menu buttons */
|
||||
#browser-menu {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
background-color: #c0c0c0;
|
||||
border-bottom: 2px inset #fff;
|
||||
}
|
||||
.menu-btn {
|
||||
border: 2px outset #fff;
|
||||
margin: 2px;
|
||||
padding: 4px 10px;
|
||||
background-color: #c0c0c0;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
}
|
||||
.menu-btn:active {
|
||||
border-style: inset;
|
||||
}
|
||||
|
||||
/* Content area */
|
||||
#browser-content {
|
||||
background-color: #e0e0e0;
|
||||
padding: 30px;
|
||||
font-size: 16px;
|
||||
border-top: 2px solid #fff;
|
||||
border-bottom: 2px solid #000;
|
||||
height: calc(100% - 30px - 30px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Lane boxes */
|
||||
.lane {
|
||||
margin-top: 15px;
|
||||
padding: 10px;
|
||||
border: 2px inset #fff;
|
||||
background-color: #c0c0c0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.lane-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Lane status, log, summary */
|
||||
.lane-status, .log, .summary {
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
border: 2px inset #fff;
|
||||
background-color: #c0c0c0;
|
||||
}
|
||||
.lane-status h3, .log h3, .summary h3 {
|
||||
margin: 0 0 5px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.log ul {
|
||||
padding-left: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Weigh Station UI</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="browser-window">
|
||||
<div id="browser-topbar">
|
||||
<span id="tab">www.sanandreasdot.gov/panel</span>
|
||||
<button id="close-btn">X</button>
|
||||
</div>
|
||||
|
||||
<div id="browser-menu">
|
||||
<button class="menu-btn">File</button>
|
||||
<button class="menu-btn">Edit</button>
|
||||
<button class="menu-btn">View</button>
|
||||
<button class="menu-btn">Help</button>
|
||||
</div>
|
||||
|
||||
<div id="browser-content">
|
||||
<h2>Weigh Station Panel</h2>
|
||||
|
||||
<div class="lane">
|
||||
<span class="lane-name">Lane A:</span> <span id="laneA-weight">-- LBS</span>
|
||||
</div>
|
||||
|
||||
<div class="lane-status">
|
||||
<h3>Lane Status</h3>
|
||||
<div id="status-laneA">Lane A: Open</div>
|
||||
</div>
|
||||
|
||||
<div class="log">
|
||||
<h3>Recent Vehicles</h3>
|
||||
<ul id="recent-vehicles">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="summary">
|
||||
<h3>Summary</h3>
|
||||
<div>Total Trucks Today: <span id="total-trucks">0</span></div>
|
||||
<div>Average Weight: <span id="avg-weight">0</span> LBS</div>
|
||||
<div>Overweight Trucks: <span id="overweight-count">0</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
-- WeighUi/server.lua
|
||||
-- In-memory logging for weigh station
|
||||
|
||||
local recentTrucks = {} -- FIFO queue for last 10 trucks
|
||||
local totalWeightToday = 0
|
||||
local totalTrucksToday = 0
|
||||
|
||||
-- =========================
|
||||
-- Log a truck
|
||||
-- =========================
|
||||
RegisterNetEvent("weighstation:logTruck", function(plate, truckModel, trailerModel, weight)
|
||||
-- Add to recent trucks (at front)
|
||||
table.insert(recentTrucks, 1, {
|
||||
plate = plate,
|
||||
truckModel = truckModel,
|
||||
trailerModel = trailerModel or "none",
|
||||
weight = weight
|
||||
})
|
||||
|
||||
-- Keep only last 10
|
||||
if #recentTrucks > 10 then
|
||||
table.remove(recentTrucks)
|
||||
end
|
||||
|
||||
-- Update totals
|
||||
totalTrucksToday = totalTrucksToday + 1
|
||||
totalWeightToday = totalWeightToday + weight
|
||||
end)
|
||||
|
||||
-- =========================
|
||||
-- Get recent vehicles
|
||||
-- =========================
|
||||
RegisterNetEvent("weighstation:getRecentVehicles", function(id)
|
||||
TriggerClientEvent("weighstation:serverCallback", source, id, recentTrucks)
|
||||
end)
|
||||
|
||||
-- =========================
|
||||
-- Get stats
|
||||
-- =========================
|
||||
RegisterNetEvent("weighstation:getStats", function(id)
|
||||
local avgWeight = totalTrucksToday > 0 and totalWeightToday / totalTrucksToday or 0
|
||||
TriggerClientEvent("weighstation:serverCallback", source, id, {
|
||||
totalTrucks = totalTrucksToday,
|
||||
avgWeight = avgWeight
|
||||
})
|
||||
end)
|
||||
@@ -0,0 +1,81 @@
|
||||
Config = {}
|
||||
|
||||
-- =============================================
|
||||
-- ACE PERMISSIONS
|
||||
-- =============================================
|
||||
Config.ACL = {
|
||||
UseACL = false, -- set to false to disable ACE checks allowing anyone to use the light controls
|
||||
MainLights = "weighstation.mainlights",
|
||||
AmberLights = "weighstation.amberlights"
|
||||
}
|
||||
|
||||
-- =============================================
|
||||
-- MAIN WEIGH STATION TRAFFIC LIGHTS
|
||||
-- =============================================
|
||||
Config.MainLights = {
|
||||
AutoMode = true,
|
||||
Lanes = {
|
||||
LaneA = {
|
||||
Lights = {
|
||||
{
|
||||
coords = vector3(2911.517090, 4153.126465, 58.026089),
|
||||
rotation = vector3(0.0, 0.0, 0.0)
|
||||
},
|
||||
{
|
||||
coords = vector3(2896.470703, 4179.305664, 56.372925),
|
||||
rotation = vector3(20.0, -90.0, 20.0)
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
ControlCoords = vector3(2920.2078, 4191.4390, 50.4580),
|
||||
ControlDistance = 1.0,
|
||||
LightSpawnRange = 1000.0,
|
||||
ResyncTime = 60000
|
||||
}
|
||||
|
||||
|
||||
-- =============================================
|
||||
-- ROAD SIGN / AMBER LIGHT SETS
|
||||
-- =============================================
|
||||
Config.RoadSigns = {
|
||||
LightSets = {
|
||||
{
|
||||
name = "San Chainski",
|
||||
model = `jd_weighstation_lightamber`,
|
||||
coordsA = vector3(2946.227051, 3795.911865, 54.827042),
|
||||
rotA = vector3(0.0, 0.0, -18.46),
|
||||
coordsB = vector3(2947.412842, 3795.516113, 54.827042),
|
||||
rotB = vector3(0.0, 0.0, -18.46),
|
||||
control = vector3(2946.8794, 3795.7717, 52.5899),
|
||||
distance = 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- =============================================
|
||||
-- WEIGH STATION RAMP LIGHT SYSTEM
|
||||
-- =============================================
|
||||
Config.RampLight = {
|
||||
AllowedClasses = {
|
||||
[18] = false,
|
||||
[20] = false,
|
||||
},
|
||||
AllowedModels = { "phantom", "hauler", "packer", "phantom3", "hauler2", "packer2" }, -- ← container truck models
|
||||
|
||||
HeavyModels = {
|
||||
"TRAILER", -- ← container heavy trailers
|
||||
"TRAILERS", "TRAILER2", "TRAILER3", "TRAILER4",
|
||||
"trailers", "trailers2", "trailers3", "trailers4",
|
||||
"freighttrailer", "armytanker", "docktrailer"
|
||||
},
|
||||
|
||||
LightModels = {
|
||||
"tr2", "tr3", "tr4", "trflat", -- ← container light trailers
|
||||
"tanker", "tanker2", "trailerlogs",
|
||||
"tvtrailer", "baletrailer", "graintrailer"
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
lua54 'yes'
|
||||
author 'John Chin'
|
||||
description 'Weigh Stations'
|
||||
version '1.0.0'
|
||||
|
||||
|
||||
shared_scripts {
|
||||
'@ox_lib/init.lua',
|
||||
'config.lua'
|
||||
}
|
||||
|
||||
client_scripts {
|
||||
'MainLights/client.lua',
|
||||
'RoadSignLights/client.lua',
|
||||
'WeighUi/client.lua'
|
||||
}
|
||||
|
||||
server_scripts {
|
||||
'MainLights/server.lua',
|
||||
'RoadSignLights/server.lua',
|
||||
'WeighUi/server.lua'
|
||||
}
|
||||
|
||||
ui_page 'WeighUi/html/ui.html'
|
||||
|
||||
files {
|
||||
'WeighUi/html/ui.html',
|
||||
'WeighUi/html/style.css',
|
||||
'WeighUi/html/script.js'
|
||||
}
|
||||
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation01/stream/jd_weighstation01_int_1.ymap
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation01/stream/jd_weighstation_01_det01.ydr
LFS
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation01/stream/jd_weighstation_01_det02.ydr
LFS
BIN
Binary file not shown.
resources/[EGRP-Map-Addons]/[jd-weighstations]/jd-weighstation01/stream/jd_weighstation_01_det03.ydr
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
fx_version "cerulean"
|
||||
game "gta5"
|
||||
|
||||
lua54 'yes'
|
||||
author 'John Chin'
|
||||
description 'Weigh Station Scenarios'
|
||||
version '1.0.0'
|
||||
|
||||
|
||||
file "sp_manifest.ymt"
|
||||
data_file "SCENARIO_POINTS_OVERRIDE_PSO_FILE" "sp_manifest.ymt"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
lua54 'yes'
|
||||
author 'John Chin'
|
||||
description 'Weigh Station Shared Props'
|
||||
version '1.0.0'
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user