Secure Game (Server) or Game Performance (Client) for GUIs

Hey, y’all.

I’m making a game where image GUIs are needed, but I’m having trouble deciding if I want them to run on the image server or image client.

Running them on the image server is easier, as I can control them from a image single server script instead of a image server script and a image local script, but running them on the image client will make the game faster.

Running them on the image client, though, is less secure because you need to fire image RemoteEvents, which can be faked.


So, running them on the image server is easier and secure but laggier, while running them on the image client is less secure but improves server performance. Server = secure but lag, client = faster but not as secure.

Which one is better to run GUIs on?

Also, another question, GetNetworkOwner is a function of BasePart, but is there a function to use this on GUIs? If there was, that would also be better.

Depends on what kind of game you are making. You shouldn’t really be relying on the client to be honest at all; always use server sanity checks.

What are you using the GUIs for?

Arena game map voting.

Also, a timer on the top to show the players how much time is left in the round.

You should edit these values on the server and then use a localscript to simply read them and display then on the client.

Allow players to fire a remote to vote for a map and check if they have already voted. If so, change their vote. If not, add their vote.

As to answer your question, running GUIs on the client is better a large majority of the time, including this case.

There is never an instance where you should run GUIs on the server - ever. It is not supported behaviour by Roblox and you’ll immediately start hitting walls. The only real exception to these may be the world-space interfaces (i.e. SurfaceGuis and BillboardGuis) - but even then, it’s rarely the case that it is better to run it on the server.

It might be easier in the short term, but in the long term it’s easier to code your game more securely, efficiently and in line with Roblox’s guidance by running your interfaces & effects locally, and your business logic on the server.

In regards to what you said about RemoteEvents, I’m not sure what you mean that they can be faked. Yeah, they can be used by exploiters in the same way you can use them in your own Local Scripts - but I’m not sure why sending data directly from server → client via :FireClient would allow an attacker to inject malicious data into the server, or other clients. It is not more secure to do interface work on the server.

2 Likes

Unfortunately, I am only able to partially understand what you are saying.

[using first quote] I believe you that you are advising me not to trust the client, and [using second quote] run GUIs on the client, but always check with the server when needed, meaning I need to use scripts, local scripts, and remote events.

(My statement above may counteract itself because the two quotes confuse me.)

Sorry! This is entirely my fault. I meant to say “server” in the above quote :stuck_out_tongue:

You should always run GUIs on the client.

Okay, I can understand that more, but I need to count all the player’s votes when they vote maps for a round. How would I do that if I run GUIs on the client?

I’m guessing you’re saying that GUIs properties such as size and Visible should be configured on the client, and other things not relating to GUIs like vote counting should be sent to the server.

So, a good way to architecture this might be:

  1. A LocalScript and ScreenGui on the Client
  2. A Server script in ServerScriptService
  3. A RemoteEvent that is referred to by both

The LocalScript would listen to Button press events (MouseButton1Click) on the TextButtons in your ScreenGui for voting. It would then send that vote over to the server via the RemoteEvent. The server would then use FireAllClients to send the updated Vote tally over.

Here is some pseudocode to illustrate better:

-- Client.lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RemoteEvent = ReplicatedStorage:WaitForChild("VoteRemoteEvent")

local ScreenGui = script.Parent
local VoteButton = ScreenGui:WaitForChild("VoteButton")
local CurrentVotes = ScreenGui:WaitForChild("CurrentVotes")
-- This is a Frame that you show all the voter info

local function UpdateVotes(VoteInfo)
    for Player, Vote in pairs(VoteInfo) do
        -- Update your UI
    end
end

Event.OnClientEvent:Connect(UpdateVotes)

VoteButton.MouseButton1Click:Connect(function()
   -- Let's pretend they voted for Map "A"
   Event:FireServer("MapA")
end)
-- Server.lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")

local RemoteEvent = ReplicatedStorage:WaitForChild("VoteRemoteEvent")

local VoteInfo = {}
local Maps = {
   ["MapA"] = ServerStorage:FindFirstChild("Map A")
}

Event.OnServerEvent:Connect(function(Player, Map)
   if Maps[Map] then
      VoteInfo[Player.Name] = Map
   end
   Event:FireAllClients(VoteInfo)
end)
1 Like