Jump to content

setTimer and getTickCount - desynced blinkers


Dzsozi (h03)

Recommended Posts

Hello!

I am having a hard time solving this problem, I can't seem to find a solution for it so I came here to ask. First of all, let me provide you with a video of the problem.

As you can see, I am working on vehicle model lights, and I would like to make indicators for a vehicle as well as the other lights, but don't mind about them, only the indicators are being a problem for me right now. At the beginning of the video, I turned on the left side, then turned on right side as well, representing a hazard blinker. For the first few blinks they are in sync, but after I alt+tab and use some CPU needy program for example 3ds max, the blinkers go out of sync and each blink on their own.

Now my guess is, since I am the one running the server from my PC, and I am running MTA and other programs as well while developing, it of course uses my CPU, so when I alt+tab out of MTA, getTickCount() returns a slightly different value each time, I think that's why it goes out of sync. Just when I started the recording it went out of sync as well, I guess because of heavy CPU usage.

My question is, how can I solve a problem like this, is there any way to work around it?

I am using a looped timer every 100 ms to check updates on server side, inside that timer I use getTickCount to measure the time past between blinks. Here is my server side code of the timer check part:

setTimer(function()
	for _,vehicle in pairs(getElementsByType('vehicle')) do
		if getElementSyncer(vehicle) then
			local lightsData = vehicle:getData("lights")
			if lightsData then
				for light, data in pairs(lightsData) do
					if vehicle.controller then
						if string.find(light, "brake") then
							if data.state ~= isVehicleBraking(vehicle) then
								toggleVehicleLight(vehicle, light, not data.state, false, false, data.broken, data.tag)
							end
						end
						
						if vehicle.engineState then
							if string.find(light, "reverse") then
								if data.state ~= (isVehicleReversing(vehicle) and getControlState(vehicle.controller, "brake_reverse")) then
									toggleVehicleLight(vehicle, light, not data.state, false, false, data.broken, data.tag)
								end
							end
						end
					end
					
					if string.find(light, "tail") then
						local tailLightsOn = vehicle.overrideLights == 2 and true or false
						if data.state ~= tailLightsOn then
							toggleVehicleLight(vehicle, light, not data.state, false, false, data.broken, data.tag)
						end
					end
					
					if string.find(light, "fog") then
						local fogLightsOn = vehicle:getData("vehicle").lights == 2 and true or false
						if data.state ~= fogLightsOn then
							toggleVehicleLight(vehicle, light, not data.state, false, false, data.broken, data.tag)
						end
					end
					
					if tonumber(data.blinkFreq) and VEHICLE_BLINK_TICK[vehicle] and VEHICLE_BLINK_TICK[vehicle][light] and getTickCount() - VEHICLE_BLINK_TICK[vehicle][light].tick > data.blinkFreq then
						--if data.blink then
							--VEHICLE_BLINK_TICK[vehicle][light].tick = getTickCount()
							
							if data.tag == AEL_TAG then
								--if not VEHICLE_BLINK_TICK[vehicle][light].step or VEHICLE_BLINK_TICK[vehicle][light].step >= #strobes[vehicle.model][1] then
								--	VEHICLE_BLINK_TICK[vehicle][light].step = 1
								--end
								if VEHICLE_BLINK_TICK[vehicle][light].step < #strobes[vehicle.model][1] then
									VEHICLE_BLINK_TICK[vehicle][light].step = VEHICLE_BLINK_TICK[vehicle][light].step + 1
								else
									VEHICLE_BLINK_TICK[vehicle][light].step = 1
								end
								
								for lightIndex, state in ipairs(strobes[vehicle.model][1][VEHICLE_BLINK_TICK[vehicle][light].step].lights) do
									if string.find(light, lightIndex) then
										VEHICLE_BLINK_TICK[vehicle][light].tick = getTickCount()
										toggleVehicleLight(vehicle, light, (not data.blink) and state or false, data.blink, strobes[vehicle.model][1][VEHICLE_BLINK_TICK[vehicle][light].step].length, data.broken, data.tag)
									end
								end
							else
                
                -- HERE IS THE PART THAT IS RESPONSIBLE FOR THE INDICATORS
                
								if data.blink then
									VEHICLE_BLINK_TICK[vehicle][light].tick = getTickCount()
									toggleVehicleLight(vehicle, light, not data.state, data.blink, data.blinkFreq, data.broken, data.tag)
								end
							end
						--end
					end
				end
			end
		end
	end
end, 100, 0)

Also, I am curious whether I should create this server side or client side. For the first time I did it on client side, but it went out of sync even more and quicker.

Thank you for your help!

Edited by Dzsozi (h03)
Link to comment
  • Moderators
6 hours ago, Dzsozi (h03) said:
 

Also, I am curious whether I should create this server side or client side. For the first time I did it on client side, but it went out of sync even more and quicker.

Doing it serverside would be a waste of your network usage.

How about you use server time to solve your problem?

local duration = 1000
local status = (serverTime % duration) > (duration / 2)

 

Link to comment
  • Moderators
7 minutes ago, Dzsozi (h03) said:

So, should I implement your servertimesync resource to my core resources, and make the light checks on client side, using exported servertimesync function?

You can do that, but you can also keep it a separated resource and include it in your core meta.xml. That way you can use it easier in multiple application-suited-resources.

 

 

Link to comment
  • Moderators
19 minutes ago, Dzsozi (h03) said:

But for sure I have to rework it on client side to make the checks, right? Would it be more efficient?

For the overall synchronisation experience of your server, yes. Take a look at your network usage with and without the blink resource running.

You know how to do that right?

/shownetstat

https://wiki.multitheftauto.com/wiki/Client_Commands#shownetstat

  • Like 1
Link to comment

To answer the original question, you should store the current time in a variable so that it is synchronized for the entire timer callback.

setTimer(function()
    local now = getTickCount()
	for _,vehicle in pairs(getElementsByType('vehicle')) do
      (...)

Then you should use the "now" variable in the following operations instead of the direct call to "getTickCount", for example...

					end
					
					if tonumber(data.blinkFreq) and VEHICLE_BLINK_TICK[vehicle] and VEHICLE_BLINK_TICK[vehicle][light] and now - VEHICLE_BLINK_TICK[vehicle][light].tick > data.blinkFreq then
						--if data.blink then

The reason for that is that the getTickCount function does fetch the current time point and you seem to be oblivious to the fact that execution of scripts does take time aswell. Please be mindful of this fact.

  • Like 1
Link to comment
9 hours ago, The_GTA said:

To answer the original question, you should store the current time in a variable so that it is synchronized for the entire timer callback.

setTimer(function()
    local now = getTickCount()
	for _,vehicle in pairs(getElementsByType('vehicle')) do
      (...)

Then you should use the "now" variable in the following operations instead of the direct call to "getTickCount", for example...

					end
					
					if tonumber(data.blinkFreq) and VEHICLE_BLINK_TICK[vehicle] and VEHICLE_BLINK_TICK[vehicle][light] and now - VEHICLE_BLINK_TICK[vehicle][light].tick > data.blinkFreq then
						--if data.blink then

The reason for that is that the getTickCount function does fetch the current time point and you seem to be oblivious to the fact that execution of scripts does take time aswell. Please be mindful of this fact.

Thank you so much, this seems to fix the problem. You are absolutely right, it went by me that I should use a variable for the current tick as well. This is what I was looking for, thank you for the help guys. I'm sorry but I don't really want to make this resource depend on another one. However, I will consider making it client side, since as IIYAMA mentioned, /shownetstat gets a little bit higher values, I haven't really used this command before for debugging, so I don't really understand it yet, fortunately packet loss doesn't happen.

Thank you for educating me again, have a nice day!

  • Like 1
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...