I am creating a speed run game that starts a timer on the player's screen once they touch a starting brick. The timer is saved as a stat in their leaderboard and if it is better than their fastest time, it will replace their fastest time with the timer. I have this script inside of a local script inside the player's GUI and I am using remote events to trigger the timer. I'm pretty new to scripting and I don't know the best ways of combatting exploiters. Is it fine that I coded it the way I did?
Local Script:
local ReplicatedStorage = game:GetService("ReplicatedStorage") local remoteEvent = ReplicatedStorage:WaitForChild("ShowTime") local Clear = ReplicatedStorage:WaitForChild("ClearTimeran") local Replace = ReplicatedStorage:WaitForChild("Replace") local SpeedBrick = workspace.RunBlock local EndBrick = workspace.EndBlock local go = true local db = false SpeedBrick.Touched:Connect(function(hit) local startplayer = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent) if startplayer ~= nil and startplayer == game:GetService("Players").LocalPlayer then if db == false then db = true Clear:FireServer() repeat wait(0.1) remoteEvent:FireServer() ---SHOWING ON GUI--- local player = script.Parent.Parent.Parent.Parent.Parent local leaderstats = player:WaitForChild("leaderstats") local stat = leaderstats:WaitForChild("runningtime") local besttime = leaderstats:WaitForChild("time1") script.Parent.Text = stat.Value stat.Changed:Connect(function() script.Parent.Text = stat.Value end) if stat.Value < besttime.Value then local ColorNew = Color3.new(0.333333, 1, 0) --GREEN script.Parent.TextColor3 = ColorNew end if stat.Value > besttime.Value and besttime.Value ~= 0 then local ColorNew = Color3.new(1, 0, 0) --RED script.Parent.TextColor3 = ColorNew end ------------------- EndBrick.Touched:Connect(function(hit) local endplayer = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent) if endplayer ~= nil and endplayer == game:GetService("Players").LocalPlayer then go = false end end) until go == false end wait(0.5) db = true end --Clearing timeran and replacing leveltime if go == false then local player = script.Parent.Parent.Parent.Parent.Parent local leaderstats = player:WaitForChild("leaderstats") local stat = leaderstats:WaitForChild("runningtime") local leveltime = leaderstats:WaitForChild("time1") if stat.Value < leveltime.Value then Replace:FireServer(leveltime,stat) script.Parent.Parent.BestTimeValue.Text = stat.Value elseif leveltime.Value == 0 then Replace:FireServer(leveltime,stat) script.Parent.Parent.BestTimeValue.Text = stat.Value end end end)
Server Script:
local remote = game:GetService("ReplicatedStorage") local remoteEvent = remote:WaitForChild("ShowTime") remoteEvent.OnServerEvent:Connect(function(player) player.leaderstats.runningtime.Value = player.leaderstats.runningtime.Value + 0.1 end)
I know that putting sensitive information in local scripts is never the best option but is the way I coded it still safe from exploiters being able to tamper with their run timer?
Also, the game will give better rewards the faster they complete the speed run
Any help would be appreciated!
Try moving the calculations to the server side. Or exploiters can just fire it and get 10 Value a second.
You may have to change some things around. I didnt have time to fully read over the script
Local Script
SpeedBrick.Touched:Connect(function() remoteEvent:FireServer() end)
Server Script
remoteEvent.OnServerEvent:Connect(function() local startplayer = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent) if startplayer ~= nil and startplayer == game:GetService("Players").LocalPlayer then if db == false then db = true Clear:FireServer() repeat wait(0.1) remoteEvent:FireServer() ---SHOWING ON GUI--- local player = script.Parent.Parent.Parent.Parent.Parent local leaderstats = player:WaitForChild("leaderstats") local stat = leaderstats:WaitForChild("runningtime") local besttime = leaderstats:WaitForChild("time1") script.Parent.Text = stat.Value stat.Changed:Connect(function() script.Parent.Text = stat.Value end) if stat.Value < besttime.Value then local ColorNew = Color3.new(0.333333, 1, 0) --GREEN script.Parent.TextColor3 = ColorNew end if stat.Value > besttime.Value and besttime.Value ~= 0 then local ColorNew = Color3.new(1, 0, 0) --RED script.Parent.TextColor3 = ColorNew end ------------------- EndBrick.Touched:Connect(function(hit) local endplayer = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent) if endplayer ~= nil and endplayer == game:GetService("Players").LocalPlayer then go = false end end) until go == false end wait(0.5) db = true end --Clearing timeran and replacing leveltime if go == false then local player = script.Parent.Parent.Parent.Parent.Parent local leaderstats = player:WaitForChild("leaderstats") local stat = leaderstats:WaitForChild("runningtime") local leveltime = leaderstats:WaitForChild("time1") if stat.Value < leveltime.Value then player.leaderstats.runningtime.Value = player.leaderstats.runningtime.Value + 0.1 script.Parent.Parent.BestTimeValue.Text = stat.Value elseif leveltime.Value == 0 then player.leaderstats.runningtime.Value = player.leaderstats.runningtime.Value + 0.1 script.Parent.Parent.BestTimeValue.Text = stat.Value end end)