How can i regenerate player`s stamina once they have not been sprinting for the past two seconds

  1. What do you want to achieve? Keep it simple and clear!
    some sort of a timeout that checks if player has been sprinting, and if not hten regenerate stamina

  2. What is the issue? Include screenshots / videos if possible!
    i dont know how to set a custom timeout

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    i did look but nothing seemed to work, i also asked ai, but it didnt solve the issue

server script

local stopLCtrlhold = false

game.ReplicatedStorage.events.keyPress.OnServerEvent:Connect(function(plr,keycode,id) --keycode and id are being sent from localscript, keycode is self explanatory, id: if 1 then player pressed ctrl, if 0 then player released ctrl
	if keycode == 'LCtrl' then
		if id == 1 then
			stopLCtrlhold = false
			if game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value >= 10 then
				plr.Character.Humanoid.WalkSpeed = 40
				repeat
					game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value -= 1
					game.ReplicatedStorage.events.sprint:FireClient(plr,game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value,game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.max.Value) --fires client to change UI stamina bar (and i just realised i could have done it here)
					task.wait(0.2)
				until game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value <= 0 or stopLCtrlhold == true
				plr.Character.Humanoid.WalkSpeed = 16
			end
		elseif id == 0 then
			stopLCtrlhold = true
		end
	end
end)

if possible, i need this system in a serverscript (exploiers issue)
feel free to ask questions about this code because i`ve been writing it for only me to understand

4 Likes

You can use task.delay(), it should work !
Hope this help, have a nice day !

1 Like

for example
i sprinted for 50% of stamina bar, waited 1 second and sprinted again
stamina bar will regenerate

what i need is to restart task.delay() timer after player sprints and cancel regen when player sprints second time, is it possible?

1 Like

You should not handle sprinting on the server. Make everything on the client, as for regenerating the stamina after not sprinting for a while, id use threads

(client)

local stamina = 0
local thread

function changeSprint(sprinting)
	if thread then pcall(task.cancel, thread) end
	
	if sprinting then
		-- player starts sprinting
		
		humanoid.WalkSpeed = 40
		
		thread = task.defer(function() -- start removing stamina untill sprinting changes or goes below 0
			while true do
				stamina -= 1
				
				if stamina <= 0 then
					changeSprint(false)
					break
				end

				task.wait(1)
			end
		end)
		
		return
	end
	
	-- player stops sprinting
	
	humanoid.WalkSpeed = 16
	thread = task.delay(2, function() -- after 2 seconds start regenerating
		while stamina < 100 do
			stamina += 1
			task.wait(.1)
		end
	end)
end

note that this isnt the full code and i haven’t tested it

1 Like

but the problem is… exploiters
thats why i store player stamina on the server, as players could not exploit its value and spritn forever

p.s.: if its stored on the server, means local script is not the best solution here

1 Like

What stops the exploiter from setting their walkspeed to any value?
I would not bother with such a thing; you can opt for client sided anti cheats (altough not the most secure and you should not rely solely on them; will stop most kiddos) or a server sided teleport check

1 Like
local spRegenThread : thread = nil

local function RegenerateSp()
  -- regen some sp every seconds
end

SprintStarted.Event:Connect(function()
  if spRegenThread then
    task.cancel(spRegenThread)
    spRegenThread = nil
  end
  -- decrease sp over time
end)

SprintEnded.Event:Connect(function()
  spRegenThread = task.delay(waitTime, RegenerateSp)
end)
3 Likes

this seems like the solution, i`ll test it and update the thread

2 Likes

when i tested that i`ve found out two errors:

  1. when i`m standing still, i could run. I fixed this but if i start running and then stand still i could still run in place
  2. in some circumstances, while regenerating stamina, i could sprint and stamina would still regenerate
    so if somebody knows how to fix at least one of them, let me know

first point is irrelevant to stamina regeneration. you cannot both standing still and run. i think you are talking about the animation though. but again irrelevant to the regen script.

second point when you sprint, you have to cancel the regen thread like i suggested to do. I don’t know how you signal for the “sprint start” so you should adapt to your own method. when you sprint, you cancel the thread and do the decrease stamina logic

all stamina logic is being held on script i wrote in the topic, heres the modified code (with task.cancel):

local stopLCtrlhold = false
local spRegenThread = nil

game.ReplicatedStorage.events.keyPress.OnServerEvent:Connect(function(plr,keycode,id)
	if keycode == 'LCtrl' then
		if id == 1 then
			if plr.Character.Humanoid.MoveDirection == Vector3.new(0,0,0) then return end
			stopLCtrlhold = false
			if game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value >= 10 then
				game.ReplicatedStorage.events.anihmatey:FireClient(plr,'run',true)
				plr.Character.Humanoid.WalkSpeed = 40
				if spRegenThread then
					task.cancel(spRegenThread)
					spRegenThread = nil
				end
				repeat
					game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value -= 1
					plr.Character.HumanoidRootPart.staminaBarLocal.bg.upper.Text = game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value
					game:GetService('TweenService'):Create(plr.Character.HumanoidRootPart.staminaBarLocal.Frame,TweenInfo.new(0.03,Enum.EasingStyle.Linear,Enum.EasingDirection.Out),{Size = UDim2.new(0.2,0,game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value/game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.max.Value*-1)}):Play()
					task.wait(0.1)
				until game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value <= 0 or stopLCtrlhold == true
				plr.Character.Humanoid.WalkSpeed = 16
				game.ReplicatedStorage.events.anihmatey:FireClient(plr,'run',false)
			end
		elseif id == 0 then
			spRegenThread = task.delay(1,function()
				repeat
					game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value += 1
					plr.Character.HumanoidRootPart.staminaBarLocal.bg.upper.Text = game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value
					game:GetService('TweenService'):Create(plr.Character.HumanoidRootPart.staminaBarLocal.Frame,TweenInfo.new(0.03,Enum.EasingStyle.Linear,Enum.EasingDirection.Out),{Size = UDim2.new(0.2,0,game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value/game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.max.Value*-1)}):Play()
					task.wait(0.05)
				until game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value == 100
			end)
			stopLCtrlhold = true
		end
	end
end)


this is the video of a problem i am describing (the second one)

1 Like

Hey! a time ago i did a stamina system that you have to wait until it regenerates, the problem is that the code is a really mess, I’ll try to making it more readble

seems like i fixed it by moving

task.cancel(spRegenThread)

out of the

if game.ServerStorage.users[plr.Name.."_"..plr.UserId].stamina.Value >= 10 then

(bug was occuring when i started spriting below 10 stamina)

but i won`t mark this as the solution, i will wait for your solution, because it might be even better

2 Likes

Ok, this is what it looks like:

https://gyazo.com/eeb9ac9c17b6f4328a477a6eed2b64a3

there are quite a lot of condition checks here. also i am not sure if the press event, will it keep firing when the player hold the button?

my code assume you would only get sprint begin and end event once they changed.
you shall add some print() to see whether you get multiples of press event coming in so potentially it creates multiple regen threads and not cancelling the existing one properly

Here is the most important part of the code:

local defaultWalkSpeed = 16
local runSpeed = 26 
local stamina = 100
local maxStamina = 100 
local minStaminaToRun = 10 
local staminaPerSecond = 1 
local staminaRegenPerSecond = 1
local counter = 0

local isRunning = false
local isExhuasted = false

function StopRunning()
	character.Humanoid.WalkSpeed = defaultWalkSpeed
	PlayNoRun:Play()
end

function StartRunning()
	if stamina >= minStaminaToRun and CanRun and humanoid.MoveDirection.Magnitude > 0 then
		counter = 0
		PlayRun:Play()
		isRunning = true
		character.Humanoid.WalkSpeed = runSpeed
	end
end

function BindRunning(actionName: string, InputState: Enum.UserInputState)
	if actionName == "Run" then
		if InputState == Enum.UserInputState.Begin then
			if not isExhuasted then
				StartRunning()
			else
				StopRunning() 
			end
			
		else
			StopRunning()
			isRunning = false
			
			task.spawn(function()
				while counter <= 2 and not isRunning do
					counter += 1
					task.wait(1)
				end
			end)
		end
	end
end

task.spawn(function()
	while wait(.1) do
		if not isRunning and stamina < maxStamina  and counter >= 2 then
			stamina += staminaRegenPerSecond
		elseif isRunning and humanoid.MoveDirection.Magnitude > 0 and stamina > 0 then
			stamina -= staminaPerSecond
		end

		if stamina > 0 then
			isExhuasted = false
		else
			isExhuasted = true
			StopRunning()
			isRunning = false
		end
	end
end)

I know its not the best code, but you can enhance it, im showing you the logic about this, any question is welcome (also in my code you cant run if your stamina is < 10%, so you will have to wait until it regenerates)

1 Like

the best part is this code is amazing
the worst part is that my script is server sided and yours is client sided

script for playing animations:

local char = script.Parent.Parent.Character or script.Parent.Parent.CharacterAdded:Wait()
local runTrack = char.Humanoid.Animator:LoadAnimation(game.ReplicatedStorage.anims.run)
game.ReplicatedStorage.events.anihmatey.OnClientEvent:Connect(function(name,state)
	if state == true then
		if name == 'run' then runTrack:Play() end
	elseif state == false then
		if name == 'run' then runTrack:Stop() end
	end
end)

script for getting player input:

local uis = game:GetService('UserInputService')

uis.InputBegan:Connect(function(i,g)
	if g then return end
	if i.KeyCode == Enum.KeyCode.LeftControl then
		game.ReplicatedStorage.events.keyPress:FireServer('LCtrl',1)
	end
end)

uis.InputEnded:Connect(function(i,g)
	if i.KeyCode == Enum.KeyCode.LeftControl and not g then
		game.ReplicatedStorage.events.keyPress:FireServer('LCtrl',0)
	end
end)

P.S: i already fixed the problem (look previous messages)

EDIT: i fixed second issue by checking moveDirection every tick (stamina loss tick) and if it equals to 0, break from cycle

if plr.Character.Humanoid.MoveDirection.Magnitude == 0 then
	game.ReplicatedStorage.events.anihmatey:FireClient(plr,'run',false)
	break
end
4 Likes