timer.Create running completely off

So I have a clock that shows the time limit in my gamemode. This clock is part of the HUD and is run completely by the player. However the server does have logic that allows the server to calculate the angle the clock should be in. I got it to work by making that angle a GlobalInt, but it caused some lag that I’d like to try and remove. So I made a timer on the clients side, which gets the timelimit from the server, and calculates the angle itself, until it gets a message from the server that the round has ended. It should theoretically work, but it just doesn’t! I was testing with a time limit set to 1 second, thus making the clocks arrow rotate 1 degree per (1/360) seconds. However it only makes 29 degrees before the time is up! I have no idea why! I also tried making it fire at a fixed 0.01 timer, and then set it to reduce the angle with (360/timelimit)*0.01, but yet this one doesn’t make it past 104 either. They should both theoretically work. Is there just a limit to how fast a clock can run or maybe it’s just not accurate enough?

Here’s some code:

function getRoundRestarted( um )
		hasjail = true
		hassmokespawn = true
		hassmoke = false
		Arrowrotation = 0
		timelimit = um:ReadFloat()
		print("Timelimit has been set to "..timelimit)
		timer.Create("RotationClock", 0.01, 100, function() Arrowrotation = Arrowrotation - ((360/timelimit)*0.01) if Arrowrotation <= -360 then Arrowrotation = 0 end print(Arrowrotation) end)
		timer.Start("RotationClock") -- The clock above here makes it to 104.4 in one second.
usermessage.Hook("roundrestart", getRoundRestarted)

-- The other version of the timer. This one makes it to -29 degrees before 1 seconds has passed.
timer.Create("RotationClock", timelimit / 360, 100, function() Arrowrotation = Arrowrotation - 1, function() if Arrowrotation <= -360 then Arrowrotation = 0 end print(Arrowrotation) end)

Is there any way to fix this? Both clocks do not make it far enough and are not synchronized with the server’s time limit. Also, printing “timelimit” does show the correct number, whether it would be 0.002777… or 1 second (depending on if I put ‘/360’ before or after the message was sent).

Image of the console with the second version of the timer used. In this one, instead of “timelimit / 360” it’s just “timelimit” and the ‘/360’ was done before the message was sent to the client.

Don’t know why you are using usermessages, but alright.

Also, what effect did you expect? You started a timer by setting its time to:

timelimit / 360

which basically means you are doing:

0.00277777784504 / 360

which in my calc outputs:


I just said in the end, that the console screenshot shows a version where “timelimit / 360” was changed to just “timelimit”. The server divided its timelimit with 360 before sending that number to the client. The client then used that number without dividing by 360. It was the exact same result.

Oh, yeah, also timer.Start() doesn’t start a timer, it just restarts it.
When you run timer.Create() the timer is automatically started.

[editline]26th June 2014[/editline]

In that case, your timelimit is equal to what you have set it to before calling the function.

Put timelimit = 200 right above the timer outside the function.

Putting that right outside on top does no difference.

What I do is use CurTime or RealTime. Those should be synced with the client. Set up a start-time, and an expiry-time / end-time.

You can count up by using time elapsed = ( CurTime( ) - start-time )
where-as you can count backwards using end-time - elapsed whereby end-time is how many seconds the round, or whatever should last.

Using those two, you should have no trouble converting it to a 0-1 float / 0-100 percent to easily convert to an angle.

Example: https://dl.dropboxusercontent.com/u/26074909/tutoring/vgui/sh_hud_countdown.lua.html

I use a 1 second time buffer to give time for clients to receive the message so it starts at the top of the counter. It isn’t needed, but I hope that will help.

I told you to place it right above timer.
Because this is how I see it:

  • You register your local timelimit and set it to 0.
  • You start the timer outside function and it uses 0 as the time and because putting 0 will most likely glitch the timer out, it goes in reverse instead.
  • Then you call the function and start a timer that repeats 100 times each 0.01 second, instead of making it repeat 60 times each second.

Am I right ?

That particular timer is only created in that function. I also tried manually changing ‘timelimit’ into just 10, then changed the in-game time limit to ten to see if they matched. They still didn’t…

I copied your code in and calculated the angle with your percentage. It works! Now there’s just three questions;

  1. How can I dynamically change the ‘seconds’ to the ConVar “cr_timelimit”, so that it updates every time that ConVar is changed (but first after the round has restarted)? I know it will work if I replace all *.seconds with the GetConVar, but I’d rather avoid it, as clients constantly reaching to the server is what caused me to use timers instead of GlobalInts in the first place.
  2. How can I stop the timer so that the clock freezes in place, in case victory was gained in any other way than the time limit? If all Runners get jailed, I’d like the clock to freeze during the postround time, until next round has begun.
  3. Can I use your code for my mode? Since it works, it’ll be nice to use it, otherwise I’ll have to just learn from it and create the rest myself. My mode is going to be public in the Workshop when it is done, so you might not want to go uncredited?

Yeah, I’m a bit of Lua newb, this *is *my first real project, so a lot of questions arise :stuck_out_tongue:

If you want to dynamically change the round-time use timer.Adjust on the timer-name for the round to add or subtract the ▲Seconds; do the same for the end-time since it is the fixed time in seconds a round lasts… 300 for 5 minutes, etc… add/subtract.

For the clients to get updated, network the change, timer.Adjust on their end, and update the end-time just like you did on the server.

To stop the time ( and to stop the timer from firing ) use timer.Destroy, network that to the client too. To prevent the timer going down simply log the current time, use a round_ended enumeration to switch the clock to static instead of dynamic and simply draw the time… Server should store the same time… You could use the same dynamic clock system by having an output var controlled with an if, or ternary operation so on round-end it takes total-time - time-elapsed for time-remaining and display that…

I create tutorials to help people learn. I’ve had people put me in the credits as a “Thanks” or “Special Thanks” because it helps others identify where help/advice came from which could benefit others down the line. Calculating an elapsed/remaining time isn’t exactly anything special. Feel free to add me on Steam and we can talk about it, or if you have any more questions I respond to all messages/questions when I am on.

I tried using timer.Adjust to change the timer to a the cvar every time a new round began. Even though I printed *.seconds out for debugging and it did indeed state the new round limit, the angle and text which was calculated from *.seconds were still matching the original round limit I set to begin with. Wierd that printing it out states the new, but the math calculates with the old…

I also tried changing it with a cvars.AddChangeCallback function, that does update it, but it does so in the middle of the round, whereas the rounds timelimit only takes effect the next round. I can see why the code does that, but I can’t see a way to delay that change until the next round. I do have a variable ‘postround’, maybe that can be used in some way…?

Don’t use cvars to handle start/stop time. Store them in memory; read the convar at round start for the round-duration.

To update it mid-round, you’ll need to update the ones I said in the previous post. To update it next round, update the cvar and ensure the cvar doesn’t have a live-hook into the round system.

cvars are also on the memory so is the whole process and the whole kernel running your OS, what exactly are you trying to tell this guy?

It depends on when he wants to modify the end-time of the round and have it take over; I’m still confused when he wants it to happen, it sounds as though he wants it one way and another reply makes it sound like the other way. My advice covers both.

A) the next round
B) the current round

With B, it works like TTT in HASTE MODE where each kill gives additional time.

With A, it works like TTT in NORMAL MODE where modifying the round-time will happen for the next round.

In case A, immediate notification of the end-time needs to be networked across clients. In B it would only need to happen at round-start.