Is this performance heavy? Should I do this a different way?

Hi, i’m making a round based game and a ‘status’ textlabel ui i is shown on all clients for what the current situation is (eg, Intermission, Waiting for Players, Starting, etc). At first, i thought about just using a remote event and :FireAllClients(), but it has me thinking, would this be performance heavy? Because it would have to be called each time an intermission’s current time changes for example. Is it a bad practice? Or should i use a different method? Thank you.

local function BeginIntermission()
	local count = 16
	while count > 0 do
		count = count - 1
		print(count)
		changeUIevent:FireAllClients("Intermission: " .. count)
		task.wait(1)
	end
	
end
2 Likes

You could fire some intermissionStartEvent and have the client calculate it all on their end. This way you aren’t sending out x (x=#of plyrs * 16) amount of network calls.

Server:

intermissionStartEvent:FireAllClients()

Client:

intermissionStartEvent:Connect(function()
    --add your code here
end
2 Likes

you can just use a for loop for this purpose:

for i = 16, 0, -1 do
    changeUIevent:FireAllClients("Intermission: " .. i)
    print(i)
    task.wait(1)
end

While yes, loop tend to take a lot of Resources, They shouldn’t cause performance issues depending on how much you are using them, or how much you are trying ti do within a period of time, People generally swap them out with .Changed Events as they are more practical and way more efficient than a loop of any kind.

RemoteEvents dont really take up a lot however, just know that they can be exploited upon so you would need to secure them in order to prevent them from this.

This wouldn’t be ideal, You need the Server to be doing all the Calculations for your game, using the Client for this process is a Stupid move on your Part, because It can easily be exploited, plus, it be a lot faster than having the Server waiting for a check that the Client is completed in doing a task.

1 Like

They asked about performance, my suggestion is more performant than yours. Less networking. Also this ideology is not a good one. The server should only do calculations that are necessary like sanity checks.

The code in question can’t be exploited. It’s a server talking to a client, not the other way around. There’s no security issues arising from my code sample.

In this code, the server doesn’t yield for the client. I didn’t add general yielding in my code but you can add this to achieve it:

intermissionStartEvent:FireAllClients()
task.wait(16)

I won’t add another reply because at this point it’s clogging up the original topic. The code is handling user interface on the client and it’s one way from server to client meaning it’s unexploitable. The other points in your reply are about theoretical code that isn’t relevant here.

2 Likes

You arent making a Good Argument,

A lot of what you’re saying can be easily disproven with literal facts.

The Server is may more Secure than the Client, And that is a fact, You have to understand that Exploiters (anybody as a matter of fact) can manipulate the Client, they are also able to fire RemoteEvents and Spam then which can cause Issue’s for Other Players which is not something you want, and your saying of “more performant” is Stupid here, It doesnt matter, It would leave the Client more in Control of your Game rather than the Server, which is something Exploiters can easily take advantage of, and start abusing it.

People use the Client for Visual Effects, Like User Interface, Animations, or Viewmodels, which is only visible on their Screen, not anybody elses (maybe with the exception of Animations)
Speaking of the Client, a RemoteEvent is not Required to change UI, You can simply use a Changed event with a Value Instance for all of this, so you can easily have it only affect the Client instead of having the Server Communicate with the Players that are in the Game.

It doesnt matter if its Better Performant or Smooth, You never trust the Client with anything important, Its always the Server you trust, Its Secure, and cant be accessed by Exploiters, Stuff like Main Game Scripts which can be a Round System, Mob Intelligence, and Services like DataStores should always be in the Server.

You never see stuff like this Handled on the Client, Its always on the Server.

1 Like

DevForum sending me two people in my post just to argue

9 Likes

unfortunately.

I don’t think it’s performance heavy, but it could be resource heavy as there would be a lot of networking if there’s a lot of players.

If you wanna be extra cautious, make a NumberValue (or an attribute, more performant) in workspace, then change it’s value to the count variable on the BeginIntermission function. Then, on the client, use :GetPropertyChangedSignal("Value") on the NumberValue to get it’s value each time it changes, and do what you want with it from there.

Some code if you're too lazy to implement this hehe

BeginIntermission function replacement:

local function BeginIntermission()
	local count = 16
	while count > 0 do
		count -= 1
		print(count)
		workspace.IntermissionTime.Value = count
		task.wait(1)
	end
end

changeUIevent:FireAllClients() “reciever script” replacement:

local value = workspace:WaitForChild('IntermissionTime')
value:GetPropertyChangedSignal('Value'):Connect(function()
	[TextLabel].Text = `Intermission: ${value.Value}`
end)

You’re the one starting it lol

2 Likes

Im more used to @DasKairo approach, fire the clients in that way. The impact on sever is perfectly acceptable.
I prefer that approach cause if you only FireAllClients once, and let clients to handle a countdown, could cause to not be in perfect sync with what server is handling.

On the other side, FireAllClients once and let them handle that, sound like less stress for the server. I think could be a matter of taste

2 Likes

Nope, since you’re already doing it once every second, which is not performance heavy at all. Though, there is one problem with your current code. It’s because you’re not taking delta time into account, and if the server experiences lag, nothing will adjust. You can replace count = count - 1 with count = count - task.wait(1) and use "Intermission: "..math.round(count) instead so that it’s more accurate.

1 Like

It’s pretty simple. In any round-based games with a “status bar”, I just did it like this:

Make a StringValue in ReplicatedStorage called “StatusValue”,

Server implementation:

-- Notice the use of for loops here.

local ReplicatedStorage = game:GetService("ReplicatedStorage");

local status_value = ReplicatedStorage:WaitForChild("StatusValue");

local INTERMISSION_TIME = 16;

local function begin_intermission()
    for i = INTERMISSION_TIME, 1, -1 do
        status_value.Value = "Intermission: " .. i;
        task.wait(1);
    end
end

Client implementation:

local ReplicatedStorage = game:GetService("ReplicatedStorage");

local status_value = ReplicatedStorage:WaitForChild("StatusValue");

local label = script.Parent; --or wherever your gui label is

local function update_status_label()
    label.Text = status_value.Value;
end

update_status_label()
status_value:GetPropertyChangedSignal("Value"):Connect(update_status_label);

I don’t see why it should be any more complicated or convoluted than this. The server handling the intermission allows for it to keep track of its schedule for the round while the clients get relayed only the necessary information about the current status of the game in real time. No need to mess with Remotes here.

Trivial solutions :^)

3 Likes

Yeah…

1 Like

Would exploiters be able to change the value because its in ReplicatedStorage?

No, they can only change the value for themselves and not everyone elses value. Also another way of doing it is sending a remoteEvent once on the server to all clients with the start time, and then looping from that start time on all the clients (which is probably best practice imo)

No. I mean they could alter the value of the StringValue, but the worst that can happen here is that they trick their own client into thinking the status is something else. It is very safe.

I would personally go with @BullfrogBait 's method. Most of the time visuals should be calculated on the client and everything that effects important gameplay should be calculated on the sever. In this case you would only handle the GUI part on the client and handle everything else on the server. Regardless of which method you chose, I doubt you would experience any sort of heavy performance impact.

Making each client handle the intermission time individually is unnecessary. If the server is already handling the countdown with a for loop and a 1 second wait, (or if we werent interfacing with the front-end, a task.wait(INTERMISSION);, then relaying this to the clients in the most simplistic way possible is with value objects in the way I described, speaking from experience.

Having worked on plenty of games which implement status bars and similar mechanics, I have tried out the RemoteEvent methods for displaying a universal status many times only to realise they fall short when it comes to trying to keep each client up to date with what is being displayed on their screen. If they join too late while the bar isn’t being updated, they won’t see anything unless their client asks the server for the current status (therefore introducing even MORE networking code which is making matters worse). You could argue that there is not a substantially large amount of excess code required to handle these edge cases, but the value object method just overall feels a lot more simplified in my opinion.

By using value objects for this specific scenario you can mitigate having to write networking code where it doesn’t need to exist. Even if it is not a “pure lua / code implementation”, I will personally go for what is most simplistic where possible so long as it does not sacrifice readability and/or performance; and I do not believe the value object method does either here.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.