I’ve tried for about 5 hours now to make a stamina system for my game. It needs to be serversided so exploiters can’t change their own stamina.
The stamina system will be removing stamina in a loop, while the player is running.
The stamina system will remove x stamina points whenever the player punches.
The stamina system will remove x stamina points whenever the player jumps
The stamina system will remove x stamina points whenever the player dashes.
At last the stamina system should regenerate after x amount of time the events has not happened.
Note, the dash, jump, run and combat scripts are different scripts, so I don’t know how I will communicate from server to server and from client to server.
Thanks In advance.
This is the latest code I ditched, it was just a test with a bindable event from a server script. It didn’t work ofc.
local RS = game:GetService("ReplicatedStorage")
local STAM_REMOTE = RS:WaitForChild("Remotes"):WaitForChild("Stamina")
local SS = game:GetService("ServerStorage")
local STAM_EVENT = SS:WaitForChild("Stam")
local CanRegen = true
local running = false
STAM_EVENT.Event:Connect(function(plr, action)
local stam = plr.Character:FindFirstChild("Stamina").Value
print(plr, action)
if action == "punch" then
if stam > 7 then
stam = stam - 7
print(stam)
else
stam = 0
end
end
end)
For the running I would first use Humanoid.Running:Connect(function(speed) to check if the player is actually running.
I think for this one you already have an idea seeing your script already have this kind of condition player punch, lose A stamina.
For this one same as the running Humanoid:GetPropertyChangedSignal("Jump"):Connect(function()
Same as the punching instead of action == "punch" it’s action == "dash"
For this one I would use tick() and subtract it with, when was the player last use the event then player can regen.
This is the idea of how I would create A stamina system if ever I would create one for my self.
I’m not sure what x is you said “system will remove x stamina”, then you said “should regenerate after x amount of time”, I’m not sure if your talking about value or time here, maybe both, since both are separate I thought both are the same thing.
with x i meant x amount of stamina, and regenerate after x amount of time yes.
I know all this you mentioned, but how would I make it safe and server sided. I can’t connect a function to a humanoid event since it’s on the server. I would have to fire the server to do that.
I think I’ll end up firing the server from the client anyways so let’s leave that behind.
And for last, how can I communicate from server script to server script?
I tried BindableFunctions, and BindableEvents but they didn’t work as intended.
That doesn’t mean you can’t connect events of a humanoid on the server. You CAN connect those events on the server. You just have to loop through each player’s character model and get their humanoid instance and connect the events.
BindableFunctions and BindableEvents. If it doesn’t work then you’re probably using them wrong.
You should spawn a thread for every singe player in your game that handles their stamina system. It should be in a while loop, and inside it you should check if they are jumping, running, dashing or other things that would cost stamina. If any one of these is true, you deduct the stamina accordingly, otherwise you can safely regenerate the stamina.
You misread my point here. You should use a while loop to constantly regenerate the stamina. If you want to deduct any stamina, use Humanoid.StateChanged just like what @MakerDoe said.
I tried to make a simple repeat until loop, but it does not work.
local RS = game:GetService("ReplicatedStorage")
local STAM_REMOTE = RS:WaitForChild("Remotes"):WaitForChild("Stamina")
STAM_REMOTE.OnServerEvent:Connect(function(plr, action)
local run = false
local stamina = plr.Character:WaitForChild("Stamina").Value
if action == "startedRun" then
run = true
repeat
if stamina >= 1 then
stamina -= 1
wait(0.05)
if stamina == 0 then
run = false
end
else
stamina = 0
end
print(stamina)
until run == false
elseif action == "stoppedRun" then
print("tried to stop")
run = false
end
end)
When the stoppedRun action is fired it does set run to false, but the repeat loop does not stop for some reason?
This part tricks me as well, but I need some time to think about it. For now, try to brainstorm with the first step as doing a check whenever one of the events/actions is fired.
Just finished adding it all to reduce. It works well, now just for the generating part!
local RS = game:GetService("ReplicatedStorage")
local STAM_REMOTE = RS:WaitForChild("Remotes"):WaitForChild("Stamina")
local STAM_BIND = RS:WaitForChild("Remotes"):WaitForChild("StaminaBind")
local run = false
local timer = 0
STAM_REMOTE.OnServerEvent:Connect(function(plr, action)
local stamina = plr.Character:WaitForChild("Stamina")
if action == "startedRun" then
run = true
while run == true do
if stamina.Value >= 1 then
stamina.Value -= 1
wait(0.05)
if stamina.Value == 0 then
run = false
end
else
stamina.Value = 0
break
end
print(stamina.Value)
end
elseif action == "stoppedRun" then
run = false
elseif action == "jump" then
if stamina.Value >= 10 then
stamina.Value -= 10
else
stamina = 0
end
print(stamina.Value)
end
end)
STAM_BIND.Event:Connect(function(plr, action)
local stamina = plr.Character:WaitForChild("Stamina")
if action == "punch" then
if stamina.Value >= 5 then
stamina.Value -= 5
else
stamina = 0
end
print(stamina.Value.. " punch")
end
end)
like I said use tick(), I’ll show you an example of what I made from the past although the script is checking if the client is spamming the event, but this should give you an idea of how you would implement it.
local lastCall = {}
event.OnServerEvent:Connect(function(player, data)
if not lastCall[player.Name] then
lastCall[player.Name] = {0, 0, 0}
else
if (math.max(tick() - lastCall[player.Name][1], 0.001)) < 0.3 then
if (tick() - lastCall[player.Name][3]) > 5 then
lastCall[player.Name][2] += 1
lastCall[player.Name][3] = tick()
warn(player.Name.." is consecutively fireing the remote event.\nWarnning:", lastCall[player.Name][2])
if lastCall[player.Name][2] > 3 then
player:Kick(player.Name, "is consecutively fireing the remote event")
end
end
else
lastCall[player.Name][3] = tick()
end
end
lastCall[player.Name][1] = tick()
end)
For the regen I think what I would do is spawn(fucntion() then add wait then use if statement and check if the lastCall has changed. It’s just an idea maybe there are other ideas out there that I’m not familiar with yet, or you could use while loop though for this one I’m not particularly sure since this feel’s like a server intensive.
Note: if you wan’t to remove the player from the array just create a PlayerRemoving function and just set the lastCall[player.Name] = nil.
Hmm, if you can look at my latest post I made 2 different parts. The first part a remote event, and the second part a BindableEvent. Since it’s not a single thread how would i go about making that???