Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Why does my timer count down faster when more clients are added?

Asked by 5 years ago

I made a simple timer on studio for my game and it is supposed to decrease by one every second but when more clients are added it decreases by more. For example: for 2 clients it counts down 2 every second. For 3 clients 3 every second and so on. Here is the code:

01local function intermission() do
02        local iTime = game.Workspace.Countdowns.intermission
03        script.Parent.CounterGui.CounterFrame.Counter.Text = "0:" .. iTime.Value
04        while wait(1) and iTime.Value > 0 do
05            if(iTime.Value <= 10) then
06                script.Parent.CounterGui.CounterFrame.Counter.TextColor3 = Color3.fromRGB(255,0,0)
07                game.Workspace.ServerSounds.tick:Play()
08            end
09            iTime.Value = iTime.Value - 1
10            if(iTime.Value >= 10) then
11                script.Parent.CounterGui.CounterFrame.Counter.Text = "0:" .. iTime.Value
12            else
13                script.Parent.CounterGui.CounterFrame.Counter.Text = "0:0" .. iTime.Value
14            end
15        end
16    end
17end
18 
19intermission()
1
because this script is getting copied to each player, which all subtract from the same value. so that means you have two or three scripts minusing from the same value., this would probably be the case if you were using a local script which im guessing you are because of the gui. COMBATKOALA 5 — 5y
0
I am using a server script IProgram_CPlusPlus 58 — 5y

1 answer

Log in to vote
2
Answered by
Ziffixture 6913 Moderation Voter Community Moderator
5 years ago
Edited 5 years ago

Introduction and Understanding

This is due to Filtering Enabled. Each Client runs this code locally—individually on their local machine. However, they all make requests to manipulate a ValueObject from the Server; the more Clients making subtraction requests, the further it's decrements increase.

To solve this issue, you must perform the arithmetic within a ServerScript. These programs do not run on the local machine but instead on ROBLOX's linked Server. The Server has replication priority, therefore any action it performs will be shown to all Clients within a singular operation.


We still need to somehow have the Client update it's UI in correspondence to the timer, so how do we link both the ServerScript and LocalScript together? This can be done using a specially designed Object called a RemoteEvent, that will allow us securely build a trusted communication between both ends.

Using it's method :FireAllClients(), and the RBXScriptSignal .OnClientEvent, we can tell it to ask the Client's to update their PlayerGui with the information passed.

Making the RemoteEvent:

This Instance need's to be available for both the Server and the Client connected, so we need to create this Object under ReplicatedStorage, a service that will transfer any information stored to both ends.


Getting to making our new ServerScript

It's of best practice to store Instance under their affiliated containers, thus, we should store a newly create Script within ServerScriptService. Let's get into the code:

1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
3 
4local CountdownTime = --// Intermission length

We start off with allocating all the necessary information into variables, notice how I use workspace instead of game.Workspace? There is a special keyword built for this container, it will allow us immediate reference to it. On another note, I use the :WaitForChild() method, this will tell the code to find the Object, and yield (wait) for it if it doesn't exist, this ensures no nil declarations in our variables.


SIDE-NOTE:

You may realize that Intermission is no longer declared, that's because it is not needed anymore. With the new code we'll be creating, the ValueObject will have no use anymore.


Let's get to re-creating the countdown:

1for TimeLeft = CountdownTime,1,-1 do
2    local String = ("Intermission: %0x2d:%0x2d"):format(TimeLeft/60, TimeLeft%60)
3    RemoteEvent:FireAllClients(String)
4wait(1) end

Note:

StackEdit is recognizing the special format syntax provided in the string concatenation above, this is a small issue that I'm unable to avoid. Please note that %0x2:%0x2 is not the authentic format syntax, please take the snippet from this pastebin that contains the real code for the String variable.


Whoa! Things got a little complicated there! It's time I explain! It's of best practice to use something called a for loop for numerical iteration. This loop will allow us to traverse over a set of instructions through a specified amount of time. This time is fed into a variable called TimeLeft, which is formatted to count down to 1 from (n) Time by 1 number. We then use a complex method of the String class called string.format(), which allows us to use special characters, to identify how we wish to push the information we supply into. We ask that it creates two 0-digit placeholders conjoined via a colon. This translates to 00:00. By then dividing the current number we're on by 60, we can get the minutes left, and by using the modulo % operator, we can get the remainder of the identical division, which returns the seconds left. The :format() method will push these calculations into 00:00 respectfully, giving us a proper digital-time effect.

Here is our finished ServerScript:

01local ReplicatedStorage = game:GetService("ReplicatedStorage")
02local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
03 
04local CountdownTime = --// Intermission length
05 
06for TimeLeft = CountdownTime,1,-1 do
07    local String = ("Intermission: %0x2d:%0x2d"):format(TimeLeft/60, TimeLeft%60)
08    RemoteEvent:FireAllClients(String)
09wait(1) end
10 
11--// You can optionally put the for loop back into a function.

We're not done unfortunately, we still need to re-program our LocalScript. This shouldn't be too hard however, as all we need to do is declare the GUIObject that we wish to display the time for, and the same information for indexing the RemoteEvent.

01local ReplicatedStorage = game:GetService("ReplicatedStorage")
02local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
03 
04local Player = game:GetService("Players").LocalPlayer
05local PlayerGui = Player:WaitForChild("PlayerGui")
06local CounterGui = PlayerGui:WaitForChild("CounterGui")
07local CounterFrame = CounterGui:WaitForChild("CounterFrame")
08local Counter = CounterFrame:WaitForChild("Counter")
09 
10RemoteEvent.OnClientEvent:Connect(function(Time)
11    Counter.Text = Time
12end)

If this helps, don’t forget to accept and upvote this answer! If you have any questions, feel free to comment below!

0
Wow! Thanks. But you did not need to write all of that! I already have a good knowledge of how FE works, string formatting, and remote events. IProgram_CPlusPlus 58 — 5y
0
Ah, that’s alright. On ScriptingHelpers, we aren’t just here to help you with your work, we’re here to ensure we leave a detailed answer for others to come across if they experience a similar issue. Ziffixture 6913 — 5y
Ad

Answer this question