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 4 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:

local function intermission() do
        local iTime = game.Workspace.Countdowns.intermission
        script.Parent.CounterGui.CounterFrame.Counter.Text = "0:" .. iTime.Value
        while wait(1) and iTime.Value > 0 do
            if(iTime.Value <= 10) then
                script.Parent.CounterGui.CounterFrame.Counter.TextColor3 = Color3.fromRGB(255,0,0)
                game.Workspace.ServerSounds.tick:Play()
            end
            iTime.Value = iTime.Value - 1
            if(iTime.Value >= 10) then
                script.Parent.CounterGui.CounterFrame.Counter.Text = "0:" .. iTime.Value
            else
                script.Parent.CounterGui.CounterFrame.Counter.Text = "0:0" .. iTime.Value
            end
        end
    end
end

intermission()
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 — 4y
0
I am using a server script IProgram_CPlusPlus 58 — 4y

1 answer

Log in to vote
2
Answered by
Ziffixture 6913 Moderation Voter Community Moderator
4 years ago
Edited 4 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:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")

local 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:

for TimeLeft = CountdownTime,1,-1 do
    local String = ("Intermission: %0x2d:%0x2d"):format(TimeLeft/60, TimeLeft%60)
    RemoteEvent:FireAllClients(String)
wait(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:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")

local CountdownTime = --// Intermission length

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

--// 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.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")

local Player = game:GetService("Players").LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local CounterGui = PlayerGui:WaitForChild("CounterGui")
local CounterFrame = CounterGui:WaitForChild("CounterFrame")
local Counter = CounterFrame:WaitForChild("Counter")

RemoteEvent.OnClientEvent:Connect(function(Time)
    Counter.Text = Time
end)

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 — 4y
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 — 4y
Ad

Answer this question