I went back to my older code that utilizes remote events and realized they are susceptible to exploitation so I fixed them up and they are fine now, except this script
This script is a timer, when the timer reaches 0 and the player presses a button they get some money, allowance if you will, but I have absolutely no idea how I could make the server check if the timer actually reached 0
Local timer script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local getFunds = ReplicatedStorage:WaitForChild("Allowance")
local button = script.Parent:FindFirstChild("Claim")
local alert = script.Parent:WaitForChild("Alert")
local p = script.Parent:WaitForChild("purchase")
local canClaim = false
local timer = script.Parent.Timer
local minutes = 10
local seconds = 0
local function startimer()
repeat
if seconds <= 0 then
minutes = minutes - 1
seconds = 59
else
seconds = seconds - 1
end
if seconds <= 9 then
timer.Text = tostring(minutes)..":0"..tostring(seconds)
else
timer.Text = tostring(minutes)..":"..tostring(seconds)
end
task.wait(1)
until minutes <= 0 and seconds <= 0 do
button.TextColor3 = Color3.fromRGB(195, 151, 46)
alert:Play()
game:GetService("StarterGui"):SetCore("SendNotification",{
Title = "FUNDS ALERT",
Text = "Your funds are ready to claim in the [EXCLUSIVE SHOP]",
Duration = 15
})
canClaim = true
end
end
startimer()
button.MouseButton1Click:Connect(function()
if canClaim then
getFunds:FireServer()
button.TextColor3 = Color3.fromRGB(0, 0, 0)
game:GetService("StarterGui"):SetCore("SendNotification",{
Title = "FUNDS ALERT",
Text = "Your funds have been successfully claimed at the [EXCLUSIVE SHOP], thank you for playing",
Duration = 7
})
p:Play()
canClaim = false
minutes = 10
seconds = 0
startimer()
end
end)
local player = game.Players.LocalPlayer
player.Character.Humanoid.Died:Connect(function()
script.Parent.Parent.Visible = false
end)
Server script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local getloan = ReplicatedStorage:WaitForChild("Allowance")
getloan.OnServerEvent:Connect(function(player)
local leaderstats = player.leaderstats
if leaderstats then
if player.MembershipType == Enum.MembershipType.Premium then
leaderstats.Money.Value = leaderstats.Money.Value + 3200
-- print("Premium user")
else
leaderstats.Money.Value = leaderstats.Money.Value + 2500
-- print("Non Premium user")
end
end
end)
If I am correct on how exploits work, this is (probably) the worst way I could have written this
Any suggestions/solutions on what I should change here?
Run the timer on the server and then signal the client they can use their button. When they do, confirm this was allowed on the server again and then give the reward.
thats a good idea but the client could just ignore that
I would:
Send an event to the server that the button was clicked and the server stores the points in a variable and adds one
the server now could recieve a new message from the client but
now we outsmart the exploiter because the server also started an timer when the
event reached the server
the server would only give the players points when the time has passed
when the signal now gone through and made an new point the server will start everything all over again
They don’t really need to be all that in sync. Any timer you may have on the client is just eye candy to make it look nice and give the player some idea (give or take a few short moments) as to when they can collect their allowance or w/e you giving them. The client timer doesn’t effect the game mechanic, its purely visual. The mechanic itself should be totally handled by the server, and the server simply signals the UI to tell the player the time interval is up. When the player clicks the button they are requesting the server allow them to collect. The server checks the interval and ensures they can and gives the reward. So you can start it off by having the server send the time remaining until next collection to the client and then run a timer on the client based on that time. Even if its off by a few milliseconds or seconds the player is virtually unaffected by this delay.
Here is a quick and dirty example
– Server
local collection_interval = 5 -- secs
local collection_timer = nil
local collectionEvent = game:GetService("ReplicatedStorage").CollectionEvent
collectionEvent.OnServerEvent:Connect(function(player, msg)
if(msg == "StartTimerRequest")then
if(not(collection_timer))then
collection_timer = tick()+collection_interval
end
elseif(msg == "CollectionRequest")then
if(not(collection_timer))then
--Give them the money....
collection_timer = tick()+collection_interval --Reset the timer
collectionEvent:FireClient(<somePlayer>, "StartTimer", collection_interval)--Tell the client
end
end
end)
game:GetService("RunService").Heartbeat:Connect(function()
if(collection_timer and collection_timer <= tick())then
--TIMES UP!!
collection_timer = nil --Clear the timer
collectionEvent:FireClient(<somePlayer>, "CollectionReady")--Tell client its ready
end
end)
–Client
collectionEvent.OnClientEvent:Connect(function(msg, interval)
if(msg == "StartTimer")then
--Start a timer using the interval given
--or you could of passed the timeRemaining
elseif(msg == "CollectionReady")then
--Run some code to enable the UI button they can press to make collection request
else
--Unhandled msg
end
end)
<someButton>.Activated:Connect(function()
collectionEvent:FireServer("CollectionRequest")
end)
--Request the server start the timer
collectionEvent:FireServer("StartTimerRequest")
I mean that the server is the one who has the timer so its not editable by the client
and the server doesnt let requests go through before the timer ends , so the client timer wouldt sync.
but if you want it sync you can have that the client asks the server if the time is already over and else it would wait one more sec.
It’s hard to understand i know but i think when you understand it it could make sence
but I could be wrong too so who knows