How to sync client side timers

I have 2 timers that are hooked to the Initialize function client side. Obviously as you would assume when 1 player connects, and then another player connects 5 or so minutes later, the timers will be out of alignment. What is the best possible way to align these timers and assure that all players on the server have the same exact time remaining on their timers. I would provide code but I’m assuming there’s no need for it since this is more of just a general question.

Wait, so why not create and use a serverside timer in the Initialize function instead? I guess there’s a obvious reason why you don’t want to do this, but some extra info would help about what you’re trying to do since I don’t see a reason not to

That’s most definitely an option. I was more just trying to challenge myself and find a way to do this all client side though, if for some reason it came a time where it was needed.

Just send a net message out from the server every second syncing it. That’s how most round timers work.

-snip-

That makes no sense; you’re going to have to post some code.

I’m sorry for explaining this in such a shitty way, I’m not the best at doing so if you can’t tell.

So basically with this code, Schedule.Classes[Schedule.CurrentClassActive].Active = true , this index “Schedule.CurrentClassActive” needs to be aligned with all clients, however it’s not if another player joins at a later time.

Also I’ve rewritten this code about 3 times to get the same product so if this doesn’t make sense I can write it in another way that it will.

At this point it’s no longer a matter of unsynced timers, it’s just a matter of unsynced values.

[editline]29th July 2016[/editline]


//Shared
Schedule.Classes = {

	[1] = {Name= "Name1", Location = "Location1", Active = true}, // Do not change the Active = false
	
	[2] = {Name= "Name2", Location = "Location2", Active = false},
	
	[3] = {Name= "Name3", Location = "Mum's Bum", Active = false},
	
	[4] = {Name= "Name4", Location = "Location4", Active = false},
	
	[5] = {Name= "Name5", Location = "Location5", Active = false},
	
	[6] = {Name= "Name6", Location = "Location6", Active = false},
	
	[7] = {Name= "Name7", Location = "Location7", Active = false},
	
	[8] = {Name= "Name8", Location = "Location8", Active = false},
	
	[9] = {Name = "Name9", Location = "Location9", Active = false}, 

}

Schedule.CurrentClassActive = 1
Schedule.NumberOfClasses = 9


//Server

util.AddNetworkString("StartT1")
util.AddNetworkString("StartT2")
 hook.Add("Initialize", "StartClassTimer", function()
 
 
	timer.Create( "StartT1", 600, 0, function() 
	
		net.Start("StartT1")
		
		net.Broadcast()
		
	end)
	
	timer.Create("StartT2", 620, 0, function()

		net.Start("StartT2")
		
		net.Broadcast()
			
		end)
 
 
 end)

//Client

net.Receive("StartT1", function(len,ply)

		Schedule.Classes[Schedule.CurrentClassActive].Active = false 
		
    timer.Stop("StartT1")
end)

net.Receive("StartT2", function(len,ply)

		
		Schedule.CurrentClassActive = Schedule.CurrentClassActive + 1

                Schedule.Classes[Schedule.CurrentClassActive].Active = true

   timer.Start("StartT1")

end)


Essentially without all the extra BS it’s just this

If you only want a time to be synchronized with clients and the server, use

CurTime
It’s a function that return the “uptime” of the server in second, and it’s synced between every computer on the server.

Simply define a variable on the server (for example 120 seconds) and network it to every clients. Then on the client:
[lua]
local timeout = 120 // Networked from the server

hook.Add(“Tick”, “TimerCheckerBlah”, function()
if (timeout < CurTime()) then
// Do your shit
hook.Remove(“Tick”, “TimerCheckerBlah”)
end
end)
[/lua]

Right however that’s no longer the issue since the timers are now synced. The indexes that the timers change are not in sync. Check out what I posted above this response.

If I need to explain this in a better way, I will do so.

What is wrong with using CurTime? I don’t understand what you mean by “The indexes that the timers change are not in sync.”

When a player initially spawns, network all indexes’ current states (including those that are false) and have the client set this as its starting values.

I had to deal with the same kind of thing before and ended up doing something like this:

[lua]if SERVER then
AddCSLuaFile()
end

CURRENT_TIMESTAMP = CURRENT_TIMESTAMP or 0

local UpdateTimestamp

if SERVER then

util.AddNetworkString("HL2CoopTimeSync")
util.AddNetworkString("HL2CoopTimeClientSync")

local lastUpdate = SysTime()

hook.Add("Tick", "HL2CoopTimeSync", function()
	UpdateTimestamp()
end)

UpdateTimestamp = function()

	CURRENT_TIMESTAMP = SysTime()

	if CURRENT_TIMESTAMP - lastUpdate &gt;= 1 then

		net.Start("HL2CoopTimeSync")
		net.WriteDouble(CURRENT_TIMESTAMP)
		net.Broadcast()

		lastUpdate = CURRENT_TIMESTAMP
	end

	local world = game.GetWorld()
	world:SetNWFloat("CoopTimeSync", CURRENT_TIMESTAMP)
end

else

TIMESTAMP_UPDATE_TIME = TIMESTAMP_UPDATE_TIME or 0

net.Receive("HL2CoopTimeSync", function(len)

	local ply = LocalPlayer()
	TIMESTAMP_UPDATE_TIME = SysTime()
	CURRENT_TIMESTAMP = net.ReadDouble()
	if IsValid(ply) then
		CURRENT_TIMESTAMP = CURRENT_TIMESTAMP + (ply:Ping() / 1000)
	end
	--DbgPrint("Update")

end)

end

function GetSyncedTimestamp()
if CURRENT_TIMESTAMP == 0 then
if SERVER then
UpdateTimestamp()
else
local world = game.GetWorld()
CURRENT_TIMESTAMP = world:GetNWFloat(“CoopTimeSync”, 0)
end
end

local res = CURRENT_TIMESTAMP

if CLIENT then
	local delta = (SysTime() - TIMESTAMP_UPDATE_TIME)
	res = res + delta
end

return res

end[/lua]

Its not exactly highly precise but it should cover most of the cases.

You are exactly right this is what I thought of last night, I just wasn’t networking the server values to the client.