How to enable/disable certain game mechanics

I’m making a round-based game that will have a stamina mechanic once the round starts. Right now, it is enabled right when I join the game, and I’m unsure of the best way to disable it.

I have two things in mind that I could do. I could either disable the scripts and enable them once the round starts.

Or I could create a BoolValue for each player, which I can then use to put everything in a condition. Both solutions seem really inefficient.

Another problem is that the stamina is handled by both the client and the server. It is best to put everything in a local script as I heard, but I’m a little worried about it being exploited, and I don’t know how to make anti-exploits yet.

Does anyone have an approach to this? I’m also open to feedback on the code, but it is mostly from a tutorial I followed online.

Client Side
-- [[ Services ]] -- 
local Players = game:GetService("Players")
local ReplicatedService = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")

-- [[ Remote Events ]] --
local remoteEvents = ReplicatedService:WaitForChild("RemoteEvents")
local UpdateStamina = remoteEvents:WaitForChild("UpdateStamina")
local Sprint = remoteEvents:WaitForChild("Sprint")

-- [[ Variables ]] --
local localPlayer = Players.LocalPlayer

-- [[ Gui ]] --
local playerGui = localPlayer:WaitForChild("PlayerGui")
local gui = playerGui:WaitForChild("Gui")
local guiObjects = gui:WaitForChild("GuiObjects")
local playerStats = guiObjects:WaitForChild("PlayerStats")
local stamina = playerStats:WaitForChild("Stamina")

local staminaBar = stamina:WaitForChild("StaminaBar")

-- Detects when shift key is pressed
UserInputService.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.LeftShift then
		Sprint:FireServer("Began")
	end
	
end)

-- Detects when shift key is released
UserInputService.InputEnded:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.LeftShift then
		Sprint:FireServer("Ended")
	end
	
end)

-- Updates stamina gui locally
UpdateStamina.OnClientEvent:Connect(function(stamina, maxStamina)
	staminaBar.Size = UDim2.new((stamina / maxStamina) * 0.2, 0, 0.01, 0) 
end)
Server Side
-- [[ Services ]] -- 
local Players = game:GetService("Players")
local ReplicatedService = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

-- [[ Remote Events ]] --
local remoteEvents = ReplicatedService:WaitForChild("RemoteEvents")
local UpdateStamina = remoteEvents:WaitForChild("UpdateStamina")
local Sprint = remoteEvents:WaitForChild("Sprint")

-- [[ Variables ]] --
local maxStamina = 100
local staminaRegen = 0.1

local sprintModifier = 1.6
local sprintStaminaCost = 0.4

local sprintingPlayers = {}

Players.PlayerAdded:Connect(function(player)
	local stamina = player:WaitForChild("Stamina")
	stamina.Value = maxStamina
	
	-- Will update the stamina gui locally
	stamina.Changed:Connect(function(property)
		UpdateStamina:FireClient(player, stamina.Value, maxStamina)
	end)
end)

-- Detects when sprint key is pressed or released
Sprint.OnServerEvent:Connect(function(player, state)
	local humanoid = player.Character.Humanoid
	
	-- Checks if the player can sprint 
	if state == "Began" and humanoid:GetState() == Enum.HumanoidStateType.RunningNoPhysics and humanoid.MoveDirection.Magnitude > 0 then
		sprintingPlayers[player.Name] = humanoid.WalkSpeed
		humanoid.WalkSpeed = humanoid.WalkSpeed * sprintModifier
	elseif state == "Ended" and sprintingPlayers[player.Name] then
		humanoid.WalkSpeed = sprintingPlayers[player.Name]
		sprintingPlayers[player.Name] = nil
	end
end)

-- Updates stamina value
RunService.Heartbeat:Connect(function()
	for i,plr in pairs(Players:GetChildren()) do
		local stamina = plr.Stamina
		local name = plr.Name
		
		-- Changes stamina value when player is not sprinting
		if not sprintingPlayers[name] then
			if stamina.Value > maxStamina then
				stamina.Value = maxStamina
			elseif stamina.Value < maxStamina then
				stamina.Value = stamina.Value + staminaRegen
			end
		else
			-- Changes stamina value when player is sprinting
			if stamina.Value >= sprintStaminaCost then
				stamina.Value = stamina.Value - sprintStaminaCost
			else
				plr.Character.Humanoid.WalkSpeed = sprintingPlayers[name]
				sprintingPlayers[name] = nil
			end
		end
	end
end)




You could do it with values, or for each mechanic have a script and toggle “Enabled” on it. works on both sides if you do it that way. Also for the stamina you should be able to disable the localscript and it shouldn’t fire server sided events. (depends how you set it up)

1 Like

I didn’t know that! Thank you. I guess I could use both values and disabling scripts.

Ok, as of now, I can enable and disable certain mechanics right when the round starts on the

But, I ran into some problems. I have a value that would disable the stamina mechanic during the game. That means that the server could be in the middle of updating the stamina gui through a remote event to the client.

I can disable the local script, but the server script will keep firing events and try to update the stamina bar gui, which gives me errors. I tried resetting the stamina value to full locally so that the server will stop trying to update the gui, but it doesn’t work.

value.Changed:Connect(function(property)
	if property then
		staminaClient.Disabled = true	
	end
end)

I also have another mechanic where the value is constantly decreasing on the server. It will trigger a remote event to update the value’s gui, which puts me in another sticky situation where I can disable the local script, but the server will still be running, trying to fire the event to the client with no luck.

At this point, I think I have inefficient code, so if someone has a different approach please share. Below is the other mechanic’s scripts:

Client Side Snippet
-- Updates value gui locally
UpdateValue.OnClientEvent:Connect(function(value, maxValue)
	sanityBar.Size = UDim2.new((value/ maxValue) * 0.2, 0, 0.01, 0) 
	
end)
Server Side Snippet
Players.PlayerAdded:Connect(function(player)
	local playerValue = player:WaitForChild("Value")
	playerValue.Value = maxValue
	
	-- Will update the value gui locally
	playerValue.Changed:Connect(function(property)
		UpdateValue:FireClient(player, playerValue.Value, maxValue)
	end)
	
-- Decreases value every frame
RunService.Heartbeat:Connect(function()
	for i,plr in pairs(Players:GetChildren()) do
		local playerValue = plr.Value
		local name = plr.Name
		
		playerValue .Value = playerValue .Value - valueDecrease

		
	end
end)