Stamina System Feedback

Hello, Folks! After some time working on a stamina/sprinting system (which I’m almost sure every beginner worked on before), I’ve finally finished it and I would like some feedback on it and what I can improve on it, specially since there’s 239 lines of code of it! Is that normal? Since I’m a beginner, I know for a fact that the code might be somewhat bad (so sorry in advance if you end up having any sort of nightmares while reading it). Below will be the place that has the code and also my thought while working on it. Any type of help is appreciated as it will help me learn a few things.

Stamina_Test.rbxl (63.5 KB)

Everything is located in the ServerScriptService and ReplicatedStorage. First thing first, why are the GUI’s in the ReplicatedStorage instead of StarterGui? Simple, it’s because of this post. May be outdated or something but, while unsure, I prefer keeping them into ReplicatedStorage and keep a script inside there to act like StarterGui. Secondly, I’m using a remote event to act as a remote function instead. I don’t think there’s a problem on that and I’m pretty sure I saw a certain post about it saying that some big games do that aswell. Of course, I’ll still use remote functions for important things like DataStore and whatnot.

Alright, time to tell the process while working on it. I wanted to create a stamina system where the player has somewhat of a control of their stamina, which means the server will “trust” the stamina the client send (while still doing some checks) and allow them to begin running. There are two attributes: ClientStamina and ServerStamina. As obvious as it’s, the client will deplete the ClientStamina and the server the ServerStamina. Once the ServerStamina reaches 0, the server wont change the player’s walkspeed back to walking. Instead, it will wait for the player fire the server and check the stamina the client sent. If they don’t respond within 7 seconds, they will be kicked. There could be a few problems like: “What if the player lags right when the server hits 0?” but not sure if that’s much of a problem; if they lagged for that long then they shouldn’t be in the server, to avoid a few cheats and whatnot. I’m also unsure if the player will be considered as moving to the server if the player lags and walk in place. That would be a problem if it did.

After the player stop running, I wanted the stamina to regen after 0.5 seconds. After checking that task.wait() wasn’t the best way to do so, I’ve decided to use task.delay() to schedule the regen and, if the player decided to run again while the regen was still scheduled, cancel it.

I’ve noticed that every so often there’s a certain gap from the ClientStamina and ServerStamina. For example, sometimes the ClientStamina had 76 and the ServerStamina 72. To fix this issue I decided to add 2 of stamina on the server if the gap is too big. Is there a better solution? I’ve also noticed that sometimes there were some errors happening on the StaminaService regarding the player’s character whe the player leaves during or after a run/regen loop. Added a few if but not sure if that’s the best approach.

I’ve tried checking every way this could be exploitable but I might’ve forgotten some (or could’ve tried to do it in a better way). I also tried to check everything that a player could do, even if unlikely, to avoid errors and I managed to probably work on them all (and that was rather annoying). For example, the script would break if the player spammed sprint while low on stamina. Not sure if anything slipped by.

Lastly, I wanted the stamina bar to fade in and out whenever the player starts running with full stamina or when the player reaches max stamina respectively. I’ve tested just a few times with two players and I guess it’s working alright. Of course, disconnect connections if the player leave and also clear values.

On the line 120 of the RunScript, I bind the action when the player spawn and unbind when the player dies. Why? To avoid the player from firing the server when they are unable to run. There’s also a random killbrick to test the loop whenever the player dies

Before finishing, for future reference, should I go “if it works, it works”? I know you can avoid a few unnecessary loops, if and whatnot but I want to be sure that there’s many ways to get the same result and none of them are wrong (unless you add too many unnecessary things), just like in modelling.

I’ll probably post two other code for feedback later aswell. One of them is a shop + inventory/item system and another a status effect script. The former is completed but I want to polish it a bit more. Anyways, thanks for your time and sorry for the huge text :sweat_smile:. Wanted to make sure y’all understood what were my thoughts while making it. Send me a question if you have any doubt on a certain piece of my code (which will probably happen)

1 Like

You could optimize this by using Remote Events. Manage all Stamina on the server. You should send a remote to the server which tells it that a user started running. Same with stopping. This is more effective since you don’t have to worry about cheaters messing with the stamina.

1 Like

Sorry for taking some time to reply. I’ve decided to let the player have some control of their stamina for it to be somewhat “smooth”. Not sure if that’s the wording. This way their stamina bar won’t “choke” every so often. Could fake the stamina on the client but it would be very annoying to the player see that they have 23 stamina but unable to run since they have 0 on the server. I’ve (hopefully) checked every way the stamina would be exploited and implemented safety measures. As I’ve saw in another post, exploiters can modify their speed anyways (of course, add a few anticheat against that but they can set their speed just under the limit) so might as well allow the player to have a better experience with the stamina. It’s basically the only game mechanic the exploiter can somewhat bypass even if it’s done on the server (I think). Probably could do it in a better way but for now that’s the way I thought of

This is nice, the code is beautiful, well structured and pretty high standard for Roblox.

The only thing i have to share is that, if your stamina is only meant for ‘sprinting’ then any sanity check is pointless:

This code can easily give you infinite sprint

workspace.<yourname>.Humanoid.WalkSpeed = 99
while true do task.wait() thecodeabove end

Making the stamina useless (if meant only for speed). It’s only resource consuming for the server.

You should keep your posts short, because not everyone is willing to read through it all, and will probably reply with something that you might have stated in the post, that they didn’t bother to read at all.

However, I can see that you think like a programmer.

Another thing, Roblox doesn’t really bother telling you very important and crucial development information, making you successfully fail as a developer, so that said; you shouldn’t use attributes because they can be very expensive for the server inside of loops. They have automatic replication, but it’s not the same as firing a remote event.

If you really want to take it up a notch, you should pack all the stamina changes in a buffer and send the buffer every second or so, and in the client interpolate the UI.

It should work because players with this stamina system can be found in only 3 states:

  1. you are draining stamina
  2. you are regenerating stamina
  3. nothing happens

meaning that as long as there is stamina to increase/decrease you can fake the process in the UI with interpolation and send much fewer packets.

the system also has errors at high latency (simulated network latency at 0.3 (200 ping))

image

another problem is that, if your latency is high, it takes a while to start sprinting and consuming stamina, in game development it’s recommended to prioritize player feedback, so at minimum speed change should be done in the client.

here’s a reply that i made one day about server authority over speed:

1 Like

Wow, thanks! I guess my code isn’t as bad as I initially thought.

For this scenario, the stamina is indeed only for sprinting as it was used as a learning code. I know about how exploiters could bypass the sanity checks simply by changing their speed. I was gonna add an anticheat for that (hence why I handled the toggle/untoggle run on the server. But looking further on you reply I’ll probably change it) but I ended up forgetting, probably due to the time I spent working on fixing errors (specially on my own).

In the end, should I even bother adding an anticheat for any type of movement of the player’s character (like a dash, super jump or whatnot)? They can easily do whatever they want with It anyways. Maybe I should only bother if it also did something that the player wouldn’t have much control of (like perfoming am in-game action such as block or whatever)?

Yeah, I probably should. I just thought that telling how and why I used the approach I picked would help people understand the code better. Next time I’ll probably cut it out.

Funny thing is that I was very skeptical in using attributes for the stamina but shrugged it off afterwards due to Roblox saying how it’s good like updating faster and whatnot. Gotta say that’s a really good information and I’ll definetly look out next time. I have a question though: I shouldnt use attributes only inside a loop? I’ve checked one of roblox’s template (laser tag) and saw that an attribute was being used for the round timer so is it fully bad to so or only if the loop goes rather quickly (like mine)?

Gotta say I didnt quite know about the buffer. I’ll certainly check it out later on aswell!

Whoops! I knew having a high ping would be a problem, just didnt know how to force myself to increase my ping to make sure there were no errors. Guess now I know. I’ll check that later on.

As I said before, I was planning to add an anticheat to make sure the player doesn’t go too fast unless they were sprinting. For that reason, the server toggled the sprint. However, I guess I’ll simply do as you said. There’s some games I play that also do that and it’s rather annoying that it takes some time to sprint. I guess my players wouldn’t like it either. If anything, exploiters have full control of their character anyways (just like how you said in your other post).

Thanks for your time, buddy! Gotta say that your reply really helped me learn a thing or two! Will definetly be useful on the long run

1 Like

yeah attributes are very dangerous inside of loops, they can easily clog the server but it all depends on the frequency they are used, attributes are fine if used only once in a while.

the problem is that using SetAttribute() can be visualized this way:

total_players * total_instances_being_set * each_set_attribute_call * function_overhead * replication

if you use one instance for all players, you can remove “total_instances_being_set” from the equation

and if you have a loop that runs at 1/60 hz for like 60s,

that would be equivalent to:

the equation above * 3600 frames

Remote events give you more control over who receives replication e.g. FireClient

So using RemoteEvents over Attributes, alongside buffer in your stamina system would be way more suitable and less costly for the server.

with FireClient + buffer it could be visualized this way:

function_overhead * replication (reduced bandwidth with buffers + only replicating for 1 player) * 60 frames (1s refresh rate)

function_overhard is the cost of calling the function, which is usually small but can accumulate if called frequently

1 Like