I made a server-sided sprint that goes like this:
[1] - Gets input from the client when the player presses shift and passes it to the server.
[2] - The server places players into a table when input is begun and takes them out when the input is ended.
[3] - Runs a loop that repeats until they are put into/taken out of the table which subtracts/adds a set amount of stamina.
The problem is that when someone presses shift really fast, it regens/drains really fast as well. This would lead to players being able to just shift spam in order to get back to the max stamina after they run out.
(Ex. https://gyazo.com/3dc28ed6e0f9c5193d6477de1a9370af.gif)
Any ideas on what the problem could be?
Server
local PlayerService, RepStorage, RunService = game:GetService('Players'), game:GetService('ReplicatedStorage'), game:GetService('RunService') ;
local Module = require(RepStorage:WaitForChild('Modules'):FindFirstChild('MechanicsModule')) ;
local Events = RepStorage.RemoteEvents ; local Sprint, UpdateStamina = Events.Sprint, Events.StaminaUpdate ;
local MaxStamina = Module.MaxStamina ; local SprintCost, SprintModifier, SprintRegen = Module.SprintCost, Module.SprintModifier, Module.SprintRegen ;
local NormalSpeed = Module.NormalSpeed ; local SprintSpeed = Module.SprintSpeed ; local WaitTime = .01 ;
local SprintingPlayers = {} ;
function isPlayerInTable(Player)
for Index, Value in pairs(SprintingPlayers) do
if Player.Name == Value then
return true
end
end
end
function Sprinting(Stamina, Player, Humanoid)
for i, SprintingPlayer in pairs(SprintingPlayers) do
if isPlayerInTable(Player) ~= true then print'no sprint' return end
repeat
if Module.IsMoving(Humanoid) and isPlayerInTable(Player) then
if Stamina.Value >= SprintCost then
Stamina.Value = Stamina.Value - SprintCost ; Humanoid.WalkSpeed = SprintSpeed ; wait(WaitTime) ;
else
Humanoid.WalkSpeed = NormalSpeed ; wait(WaitTime) ;
end
elseif not Module.IsMoving(Humanoid) and isPlayerInTable(Player) then
if Stamina.Value < MaxStamina then
Stamina.Value = Stamina.Value + SprintRegen ; Humanoid.WalkSpeed = NormalSpeed ; wait(WaitTime) ;
end
end
wait() ;
until not isPlayerInTable(Player) or Humanoid:GetState() == Enum.HumanoidStateType.Dead
end
end
function NotSprinting(Stamina, Player, Humanoid)
if #SprintingPlayers > 0 then
for i, SprintingPlayer in pairs(SprintingPlayers) do
if not isPlayerInTable(Player) then
repeat
if Stamina.Value < MaxStamina then
Stamina.Value = Stamina.Value + SprintRegen ; Humanoid.WalkSpeed = NormalSpeed ; wait(WaitTime) ;
elseif Stamina.Value > MaxStamina then
Stamina.Value = MaxStamina
end
wait() ;
until isPlayerInTable(Player) or Humanoid:GetState() == Enum.HumanoidStateType.Dead
end
end
elseif #SprintingPlayers <= 0 and not isPlayerInTable(Player) then
repeat
if Stamina.Value < MaxStamina then
Stamina.Value = Stamina.Value + SprintRegen ; Humanoid.WalkSpeed = NormalSpeed ; wait(WaitTime) ;
elseif Stamina.Value > MaxStamina then
Stamina.Value = MaxStamina
end
wait() ;
until isPlayerInTable(Player) or Humanoid:GetState() == Enum.HumanoidStateType.Dead
end
end
function AddToTable(Stamina, Player, Humanoid)
if not isPlayerInTable(Player) then
table.insert(SprintingPlayers, Player.Name)
Sprinting(Stamina, Player, Humanoid)
end
end
function RemoveFromTable(Stamina, Player, Humanoid)
if #SprintingPlayers > 0 then
for Index, Value in pairs(SprintingPlayers) do
if Value == Player.Name then
table.remove(SprintingPlayers, Index) ;
NotSprinting(Stamina, Player, Humanoid) ;
end
end
else
NotSprinting(Stamina, Player, Humanoid) ;
end
end
PlayerService.PlayerAdded:Connect(function(Player)
Player.CharacterAdded:Connect(function(Character)
local Root = Character:WaitForChild('HumanoidRootPart') or Character:FindFirstChild('HumanoidRootPart') ;
local Stamina = Instance.new('IntValue', Root) ;
Stamina.Name = 'Stamina' ; Stamina.Value = MaxStamina ;
Stamina.Changed:Connect(function(Property)
UpdateStamina:FireClient(Player, Stamina.Value, MaxStamina)
end)
end)
end)
Sprint.OnServerEvent:Connect(function(Player, State, Tick)
local Character = Player.Character ;
local Root = Character:WaitForChild('HumanoidRootPart') or Character:FindFirstChild('HumanoidRootPart') ;
local Stamina = Root:FindFirstChild('Stamina') or Root:WaitForChild('Stamina') ; local Humanoid = Character:FindFirstChild('Humanoid') ;
if State then
if not isPlayerInTable(Player) then
AddToTable(Stamina, Player, Humanoid) ;
-- print(Player.Name, 'IS SPRINTING', State) ;
end
elseif not State then
if isPlayerInTable(Player) then
RemoveFromTable(Stamina, Player, Humanoid)
-- print(Player.Name, 'STOPPED SPRINTING', State) ;
end
end
end)
Client
InputService.InputBegan:Connect(function(Input, gameProcessed)
if not gameProcessed then
if Input.KeyCode == Enum.KeyCode.LeftShift then
-- print(Player.Name, 'began sprinting')
Sprint:FireServer(true) ;
end
end
end)
InputService.InputEnded:Connect(function(Input, gameProcessed)
if not gameProcessed then
if Input.KeyCode == Enum.KeyCode.LeftShift then
-- print(Player.Name, 'stopped sprinting')
Sprint:FireServer(false) ;
end
end
end)

7 comments
I have a function for this but for some reason it doesn't print if the player is already in the table
can i see the code? that would make it easier to solve >wO
Sorry, I'll add an edit
Also, if there's a better way to do what I'm trying to achieve please do suggest
what's the full server script, with isPlayerScripting function and Connect to the Sprint remote event
Another edit coming up
nice looking script but why dont u use table.find() in function isPlayerInTable