Fuel text label NOT updating with CarAttribute change

Hi everyone. My current game in development has a Fuel System. Every car that is purchased by a player has an attribute named “FuelAmount”. The max fuel in each vehicle is 25, but the default fuel level is 15, giving players a little over half a tank when purchasing a vehicle. I’m running into some issues with the GUI, etc, but I’ll get to that later. My main issue appears to be very simple, but I just can’t figure out what is going on.

As a player drives their vehicle, the car attribute properly decreases as the vehicle drives. (Starting at 15.00, it decreases going down like 14.99 to 14.01 etc). Whenever the number hits 14.00, the “Fuel” text label in the GUI is supposed to change to 14, then to 13, 12, 11 so on and so forth as the car attribute changes. Whenever the amount hits 5.00, a image label “YellowGas” is supposed to become visible. The problem is, I cannot figure out why, but the Fuel text label does not update no matter what the FuelAmount attribute number is.

All of the labels for this are located at CarModel > A-Chassis Tune > Plugins > Gauge (image label), all of them are below Gauge.

I have even ran my scripts through ChatGPT to see if maybe ChatGPT could help me figure it out and no matter what it’s tried, we still cannot get the Fuel label to update.

There is 3 scripts for the Fuel System to function, FuelHandler (ServerScriptService), FuelPumpGUIScript (StarterPlayerScripts) and FuelScript (located in the Vehicle’s Plugins folder). I’m pretty sure all of this would be an issue inside of FuelScript, but maybe there’s an issue in the other 2? I’ve been scratching my head for 2 days, if anyone could review this and give me an idea on what’s going on I’d be so grateful!

The Gauge with the “Fuel” text label which is stuck at 15:
Screenshot 2025-02-07 105038

Also, for reference:

Thank you in advanced for any assistance!

FuelScript (vehicle plugins folder) this most recent script also was run through ChatGPT multiple times FYI - All 3 scripts are below, FuelScript is the top script:

   FuelScript
   Place this script in: CarModel > A-Chassis Tune > Plugins > FuelScript
   This script updates the vehicle’s dashboard fuel gauge based on the car’s "FuelAmount" attribute.
--]]

-- Services
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

-----------------------------------------------------
-- Configuration Constants
-----------------------------------------------------
local DEFAULT_FUEL = 15             -- Default starting fuel (gallons)
local MAX_FUEL = 25                 -- Maximum fuel capacity
local CONSUMPTION_RATE = 0.1        -- Gallons consumed per second at full throttle
local LOW_FUEL_THRESHOLD = 5        -- When fuel warnings begin
local NORMAL_TEXT_COLOR = Color3.new(1, 1, 1)       -- White
local WARNING_TEXT_COLOR = Color3.fromRGB(189, 42, 42)  -- Red (Similar to old script)

-----------------------------------------------------
-- References & Setup
-----------------------------------------------------
local pluginsFolder = script.Parent
local gauge = pluginsFolder:WaitForChild("Gauge")
local fuelTextLabel = gauge:WaitForChild("Fuel")
local yellowGasImage = gauge:WaitForChild("YellowGas")

-- Use this print to verify which instance of the car is being used.
local car = pluginsFolder.Parent.Parent
print("FuelScript running on car instance:", car:GetFullName())

if not car then
    warn("FuelScript: Car model not found!")
    return
end

-- Initialize FuelAmount attribute if not set.
if car:GetAttribute("FuelAmount") == nil then
    car:SetAttribute("FuelAmount", DEFAULT_FUEL)
end

-----------------------------------------------------
-- Helper: Recursively find the DriveSeat by name and class.
-----------------------------------------------------
local function findDriveSeat(model)
    for _, obj in ipairs(model:GetDescendants()) do
        if obj.Name == "DriveSeat" and obj:IsA("VehicleSeat") then
            return obj
        end
    end
    return nil
end

-- Wait for the DriveSeat to exist (up to 10 seconds)
local driveSeat = findDriveSeat(car)
local waited = 0
while not driveSeat and waited < 10 do
    wait(0.1)
    waited = waited + 0.1
    driveSeat = findDriveSeat(car)
end
if not driveSeat then
    warn("FuelScript: No DriveSeat found in car " .. car.Name)
else
    print("FuelScript: DriveSeat found in car " .. car.Name .. " after waiting " .. waited .. " seconds.")
end

-----------------------------------------------------
-- Helper Functions for Fuel Amount
-----------------------------------------------------
local function getFuel()
    return car:GetAttribute("FuelAmount") or DEFAULT_FUEL
end

local function setFuel(newFuel)
    car:SetAttribute("FuelAmount", newFuel)
end

-----------------------------------------------------
-- Update Dashboard Gauge Function
-----------------------------------------------------
local function updateGaugeUI()
    local fuel = getFuel()
    -- Display fuel as a whole number (e.g. "15")
    fuelTextLabel.Text = tostring(math.floor(fuel))
    -- Show the low-fuel warning image if fuel is at or below threshold.
    yellowGasImage.Visible = (fuel <= LOW_FUEL_THRESHOLD)
    -- Debug: print current fuel
    print("updateGaugeUI: Fuel =", fuel)

    -- Tweening effect when fuel is low
    if fuel <= LOW_FUEL_THRESHOLD then
        local phase = math.sin(tick() * 3)
        if phase > 0 then
            fuelTextLabel.TextColor3 = WARNING_TEXT_COLOR
        else
            fuelTextLabel.TextColor3 = NORMAL_TEXT_COLOR
        end
    else
        fuelTextLabel.TextColor3 = NORMAL_TEXT_COLOR
    end
end

-- Do an initial update.
updateGaugeUI()

-- Listen for changes to FuelAmount.
car:GetAttributeChangedSignal("FuelAmount"):Connect(function()
    updateGaugeUI()
end)

-----------------------------------------------------
-- Main Fuel Consumption Loop (Dashboard consumption)
-----------------------------------------------------
RunService.Heartbeat:Connect(function(deltaTime)
    if not driveSeat then return end
    local throttle = math.abs(driveSeat.Throttle)
    local fuel = getFuel()

    if throttle > 0 and fuel > 0 then
        local consumption = CONSUMPTION_RATE * throttle * deltaTime
        fuel = math.max(fuel - consumption, 0)
        setFuel(fuel)
        -- updateGaugeUI() will be triggered by the attribute change.
    end

    if fuel <= 0 and driveSeat then
        driveSeat.Throttle = 0
    end

    updateGaugeUI()
end)

-----------------------------------------------------
-- Listen for FuelUpdateEvent from server
-----------------------------------------------------
local FuelUpdateEvent = game.ReplicatedStorage:WaitForChild("FuelUpdateEvent")

FuelUpdateEvent.OnClientEvent:Connect(function(newFuelAmount)
    setFuel(newFuelAmount)  -- Update the fuel attribute on the car.
    updateGaugeUI()  -- Refresh the UI with the new fuel value.
end)```


*OTHER SCRIPTS BELOW:*



***FuelHandler:***
```local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local RunService = game:GetService("RunService")

local FuelEvent = ReplicatedStorage:WaitForChild("FuelEvent")
local FuelUpdateEvent = ReplicatedStorage:WaitForChild("FuelUpdateEvent")  -- Added FuelUpdateEvent
local DataStore = DataStoreService:GetDataStore("PlayerFuelData")

local MAX_FUEL = 25
local PRICE_PER_GALLON = 6.75
local CONSUMPTION_RATE = 0.1  -- Gallons consumed per second at full throttle

-----------------------------------------------------
-- Save fuel data for the player's spawned cars
-----------------------------------------------------
local function saveFuelData(player)
	local spawnedCarsFolder = workspace:FindFirstChild("SpawnedCars")
	local data = {}
	if spawnedCarsFolder then
		for _, car in ipairs(spawnedCarsFolder:GetChildren()) do
			if car:GetAttribute("owner") == player.Name then
				local fuel = car:GetAttribute("FuelAmount") or MAX_FUEL
				table.insert(data, {Name = car.Name, Fuel = fuel})
			end
		end
	end
	local success, errorMessage = pcall(function()
		DataStore:SetAsync(player.UserId, data)
	end)
	if not success then
		warn("Failed to save fuel data for", player.Name, errorMessage)
	end
end

-----------------------------------------------------
-- Load fuel data and update spawned cars
-----------------------------------------------------
local function loadFuelData(player)
	local success, data = pcall(function()
		return DataStore:GetAsync(player.UserId)
	end)
	if success and data then
		local spawnedCarsFolder = workspace:FindFirstChild("SpawnedCars")
		if spawnedCarsFolder then
			for _, carData in pairs(data) do
				local car = spawnedCarsFolder:FindFirstChild(carData.Name)
				if car then
					car:SetAttribute("FuelAmount", carData.Fuel)
				end
			end
		end
	else
		warn("Failed to load fuel data for", player.Name)
	end
end

-----------------------------------------------------
-- FuelEvent handling (refuel/consume from pump)
-----------------------------------------------------
FuelEvent.OnServerEvent:Connect(function(player, car, action)
	-- Ensure we work on the actual spawned vehicle (search recursively for DriveSeat)
	if not car or not car:FindFirstChild("DriveSeat", true) then return end
	local fuel = car:GetAttribute("FuelAmount") or MAX_FUEL

	if action == "Refuel" then
		if player.NewkCash.Value >= PRICE_PER_GALLON and fuel < MAX_FUEL then
			player.NewkCash.Value = player.NewkCash.Value - PRICE_PER_GALLON
			car:SetAttribute("FuelAmount", math.min(fuel + 1, MAX_FUEL))
		end
	elseif action == "Consume" then
		if fuel > 0 then
			car:SetAttribute("FuelAmount", math.max(fuel - 1, 0))
		else
			local driveSeat = car:FindFirstChild("DriveSeat", true)
			if driveSeat then
				driveSeat.Throttle = 0
			end
		end
	end

	-- After changing fuel, notify the client via FuelUpdateEvent
	local updatedFuel = car:GetAttribute("FuelAmount")
	FuelUpdateEvent:FireClient(player, updatedFuel)
end)

-----------------------------------------------------
-- Continuous Fuel Consumption Loop for spawned cars
-----------------------------------------------------
RunService.Heartbeat:Connect(function(deltaTime)
	local spawnedCarsFolder = workspace:FindFirstChild("SpawnedCars")
	if spawnedCarsFolder then
		for _, car in ipairs(spawnedCarsFolder:GetChildren()) do
			local owner = car:GetAttribute("owner")
			if owner then
				local driveSeat = car:FindFirstChild("DriveSeat", true)
				if driveSeat then
					local throttle = math.abs(driveSeat.Throttle)
					if throttle > 0 then
						local fuel = car:GetAttribute("FuelAmount") or MAX_FUEL
						local consumption = CONSUMPTION_RATE * throttle * deltaTime
						fuel = math.max(fuel - consumption, 0)
						car:SetAttribute("FuelAmount", fuel)
						if fuel <= 0 then
							driveSeat.Throttle = 0
						end
					end
				end
			end
		end
	end
end)

-----------------------------------------------------
-- Player Data Events
-----------------------------------------------------
Players.PlayerAdded:Connect(function(player)
	loadFuelData(player)
	player.CharacterAdded:Connect(function()
		local spawnedCarsFolder = workspace:FindFirstChild("SpawnedCars")
		if spawnedCarsFolder then
			for _, car in ipairs(spawnedCarsFolder:GetChildren()) do
				if car:GetAttribute("owner") == player.Name then
					car:SetAttribute("FuelAmount", car:GetAttribute("FuelAmount") or MAX_FUEL)
				end
			end
		end
	end)
end)

Players.PlayerRemoving:Connect(saveFuelData)
game:BindToClose(function()
	for _, player in ipairs(Players:GetPlayers()) do
		saveFuelData(player)
	end
end)```




***FuelPumpGUIScript:***
```-- Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local MarketplaceService = game:GetService("MarketplaceService")
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local player = Players.LocalPlayer

-- GUI Elements
local playerGui = player:WaitForChild("PlayerGui")
local fuelPumpGui = playerGui:WaitForChild("FuelPumpGui")
local pumpFrame = fuelPumpGui:WaitForChild("PumpFrame")
local fuelFrame = pumpFrame:WaitForChild("FuelFrame")
local fuelAmountFrame = fuelFrame:WaitForChild("FuelAmount")
local clickToFuel = pumpFrame:WaitForChild("ClickToFuel")
local instantFuel = pumpFrame:WaitForChild("InstantFuel")
local vehicleNameLabel = pumpFrame:WaitForChild("VehicleName")
local currentFuelLabel = pumpFrame:WaitForChild("CurrentFuel")
local instantFuelPriceLabel = pumpFrame:WaitForChild("InstantFuelPrice")
local pricePerGalLabel = pumpFrame:WaitForChild("PricePerGal")
local confirmationLabel = pumpFrame:WaitForChild("Confirmation")

-- Variables
local car
local fuelPricePerGallon = 6.75
local gamePassID = 994621107
local fuelDepletedShown = false

-- RemoteEvent for receiving fuel updates
local FuelUpdateEvent = ReplicatedStorage:WaitForChild("FuelUpdateEvent")

local function debugLog(message)
	print("[FuelPumpGUIScript]: " .. message)
end

-----------------------------------------------------
-- Enhanced Car Search: Look in character, player.Cars, and SpawnedCars.
-----------------------------------------------------
local function findCar()
	-- 1. Check player's character for a VehicleSeat
	local character = player.Character
	if character then
		local seat = character:FindFirstChildWhichIsA("VehicleSeat")
		if seat and seat.Parent and seat.Parent:GetAttribute("owner") == player.Name then
			debugLog("Found player's car via character seat: " .. seat.Parent.Name)
			return seat.Parent
		end
	end

	-- 2. Check player's Cars folder (the placeholder)
	local playerCars = player:FindFirstChild("Cars")
	if playerCars then
		for _, vehicle in ipairs(playerCars:GetChildren()) do
			if vehicle:GetAttribute("owner") == player.Name then
				debugLog("Found player's car in player.Cars: " .. vehicle.Name)
				-- Note: This is the placeholder; we want the spawned version.
				-- So, do not return this.
			end
		end
	end

	-- 3. Check Workspace.SpawnedCars (the actual vehicle)
	local spawnedCarsFolder = Workspace:FindFirstChild("SpawnedCars")
	if spawnedCarsFolder then
		for _, vehicle in ipairs(spawnedCarsFolder:GetChildren()) do
			if vehicle:GetAttribute("owner") == player.Name then
				debugLog("Found player's car in SpawnedCars: " .. vehicle.Name)
				return vehicle
			end
		end
	end

	debugLog("No car found for player.")
	return nil
end

-----------------------------------------------------
-- Fuel amount getter/setter
-----------------------------------------------------
local function getFuelAmount()
	return car and car:GetAttribute("FuelAmount") or 0
end

local function setFuelAmount(newValue)
	if car then
		car:SetAttribute("FuelAmount", newValue)
	end
end

-----------------------------------------------------
-- Update Fuel Pump GUI
-----------------------------------------------------
local function setConfirmation(message, color)
	confirmationLabel.Text = message
	confirmationLabel.TextColor3 = color
	confirmationLabel.Visible = true
	task.wait(2)
	confirmationLabel.Visible = false
end

local function updateFuelUI()
	if car then
		local driveSeat = car:FindFirstChildOfClass("VehicleSeat")
		if not driveSeat then
			debugLog("ERROR: DriveSeat not found in car: " .. car.Name)
			return
		end

		local fuelLevel = getFuelAmount()
		local maxFuel = driveSeat:GetAttribute("MaxFuel") or 15
		local fuelPercentage = fuelLevel / maxFuel
		fuelAmountFrame.Size = UDim2.new(fuelPercentage, 0, 1, 0)
		currentFuelLabel.Text = string.format("%.2f gal.", fuelLevel)
		local remainingFuelCost = math.ceil((maxFuel - fuelLevel) * fuelPricePerGallon)
		instantFuelPriceLabel.Text = "$" .. tostring(remainingFuelCost)
		debugLog("Fuel UI updated successfully.")

		if fuelLevel <= 0 then
			driveSeat.Throttle = 0
			if not fuelDepletedShown then
				setConfirmation("Fuel Depleted! Car shut off.", Color3.fromRGB(255, 0, 0))
				fuelDepletedShown = true
			end
		else
			fuelDepletedShown = false
		end
	else
		debugLog("Car is nil. Cannot update Fuel UI.")
	end
end

-----------------------------------------------------
-- Fueling Functions
-----------------------------------------------------
local function beginFueling()
	if car then
		local driveSeat = car:FindFirstChildOfClass("VehicleSeat")
		if not driveSeat then
			debugLog("ERROR: DriveSeat not found in car: " .. car.Name)
			return
		end

		local fuelLevel = getFuelAmount()
		local maxFuel = driveSeat:GetAttribute("MaxFuel") or 15

		if fuelLevel >= maxFuel then
			setConfirmation("Gas Tank Full!", Color3.fromRGB(0, 255, 0))
			return
		end

		local fuelingConnection
		fuelingConnection = RunService.Heartbeat:Connect(function(deltaTime)
			if fuelLevel < maxFuel and player.NewkCash.Value >= fuelPricePerGallon then
				fuelLevel = math.min(fuelLevel + (0.5 * deltaTime), maxFuel)
				setFuelAmount(fuelLevel)
				player.NewkCash.Value = player.NewkCash.Value - fuelPricePerGallon
				updateFuelUI()
			elseif fuelLevel >= maxFuel then
				setConfirmation("Gas Tank Full!", Color3.fromRGB(0, 255, 0))
				fuelingConnection:Disconnect()
			elseif player.NewkCash.Value < fuelPricePerGallon then
				setConfirmation("Not Enough NewkCash!", Color3.fromRGB(255, 0, 0))
				fuelingConnection:Disconnect()
			end
		end)

		clickToFuel.MouseButton1Up:Connect(function()
			if fuelingConnection then
				fuelingConnection:Disconnect()
			end
		end)
	else
		debugLog("No car detected for fueling.")
	end
end

local function instantRefuel()
	if car then
		local driveSeat = car:FindFirstChildOfClass("VehicleSeat")
		if not driveSeat then
			debugLog("ERROR: DriveSeat not found in car during instant refuel.")
			return
		end

		local fuelLevel = getFuelAmount()
		local maxFuel = driveSeat:GetAttribute("MaxFuel") or 15

		if fuelLevel >= maxFuel then
			setConfirmation("Gas Tank Full!", Color3.fromRGB(0, 255, 0))
			return
		end

		local cost = math.ceil((maxFuel - fuelLevel) * fuelPricePerGallon)

		MarketplaceService:UserOwnsGamePassAsync(player.UserId, gamePassID):andThen(function(ownsPass)
			if ownsPass then
				if player.NewkCash.Value >= cost then
					setFuelAmount(maxFuel)
					player.NewkCash.Value = player.NewkCash.Value - cost
					updateFuelUI()
					setConfirmation("Instant Refuel Successful!", Color3.fromRGB(0, 255, 0))
				else
					setConfirmation("Not Enough NewkCash!", Color3.fromRGB(255, 0, 0))
				end
			else
				MarketplaceService:PromptGamePassPurchase(player, gamePassID)
			end
		end):catch(function(err)
			debugLog("Game pass check failed: " .. tostring(err))
		end)
	else
		debugLog("No car detected for instant refuel.")
	end
end

-----------------------------------------------------
-- Event Connections
-----------------------------------------------------
clickToFuel.MouseButton1Down:Connect(function()
	debugLog("ClickToFuel button pressed.")
	beginFueling()
end)

instantFuel.MouseButton1Click:Connect(function()
	debugLog("InstantFuel button clicked.")
	instantRefuel()
end)

fuelPumpGui.Enabled = false

-- Listen for fuel updates from the server
FuelUpdateEvent.OnClientEvent:Connect(function(newFuelAmount)
	debugLog("FuelUpdateEvent received. New Fuel Amount: " .. tostring(newFuelAmount))
	-- Update the fuel value when the server sends a new value
	setFuelAmount(newFuelAmount)
	updateFuelUI()
end)

local function showFuelGUI()
	debugLog("Attempting to show FuelPumpGui...")
	car = findCar()
	if car then
		local driveSeat = car:FindFirstChildOfClass("VehicleSeat")
		if driveSeat then
			local vehicleMake = driveSeat:FindFirstChild("Make") and driveSeat.Make.Value or car.Name
			local vehicleModel = driveSeat:FindFirstChild("Model") and driveSeat.Model.Value or ""
			vehicleNameLabel.Text = vehicleMake .. " " .. vehicleModel
		else
			vehicleNameLabel.Text = car.Name
		end
		pricePerGalLabel.Text = string.format("$%.2f / gal.", fuelPricePerGallon)
		updateFuelUI()
		fuelPumpGui.Enabled = true
	else
		debugLog("No car found. FuelPumpGui will not be displayed.")
	end
end

pumpFrame.Close.MouseButton1Click:Connect(function()
	fuelPumpGui.Enabled = false
	debugLog("FuelPumpGui closed.")
end)

return showFuelGUI```

Seems like it should be working, looking at updateGuageUI() and car:GetAttributeChangedSignal().

Does the print statement from updateGuageUI() run when the attribute changes? : print("updateGaugeUI: Fuel =", fuel)

Have you tried placing a print statement inside the car:GetAttributeChangedSignal() event connection to ensure it is running?

Yes, everything in output always looks like everything is fine. Recently though, the Output has been spammed after ChatGPT did an update to the script:

  10:37:36.046  FuelScript: DriveSeat found in car WhiteTuxGroom after waiting 0 seconds.  -  Client - FuelScript:66
  10:37:36.046  updateGaugeUI: Fuel = 15  -  Client - FuelScript:90
  10:37:36.054   ▶ updateGaugeUI: Fuel = 15 (x5)  -  Client - FuelScript:90
  10:37:36.134  updateGaugeUI: Fuel = 15  -  Client - FuelScript:90
  10:37:36.141  updateGaugeUI: Fuel = 15  -  Client - FuelScript:90
  10:37:36.158   ▶ updateGaugeUI: Fuel = 15 (x502)  -  Client - FuelScript:90
  10:37:44.539   ▶ updateGaugeUI: Fuel = 15 (x238)  -  Client - FuelScript:90
  10:37:48.531   ▶ updateGaugeUI: Fuel = 15 (x223)  -  Client - FuelScript:90
  10:37:52.273   ▶ updateGaugeUI: Fuel = 15 (x199)  -  Client - FuelScript:90
  10:37:55.590   ▶ updateGaugeUI: Fuel = 15 (x302)  -  Client - FuelScript:90
  10:38:00.688   ▶ updateGaugeUI: Fuel = 15 (x24)  -  Client - FuelScript:90
  10:38:01.091   ▶ updateGaugeUI: Fuel = 15 (x18)  -  Client - FuelScript:90
  10:38:01.402   ▶ updateGaugeUI: Fuel = 15 (x1033)  -  Client - FuelScript:90
  10:38:18.730   ▶ updateGaugeUI: Fuel = 15 (x28)  -  Client - FuelScript:90
  10:38:19.188   ▶ updateGaugeUI: Fuel = 15 (x540)  -  Client - FuelScript:90```

That’s probably because your UpdateGuageUI() function is updating the server-side UI that gets replicated to everyone instead of the client version. For example, updating UI from StarterGui won’t edit anyone’s UI on their screen

Put the `car:GetAttributeChangedSignal() event on the client and update directly from there + it’s better than constantly firing remote events

1 Like

You were right, it was that simply. I ended up changing the pathing to playergui and it updates as it’s supposed to! Thanks for jogging my mind!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.