Help on setting the player's MaxHealth through the Server

So I’ve been working on an RPG system. The player’s MaxHealth is increased each time he/she levels up. When the player dies and respawns, it resets the MaxHealth to 100 (the default).

Health Formula:

function info.GetHealth(level)
	
	if level < 10 then
		
		return 100 + (5 * (level - 1))
		
	else
		
		return 150 + (10 * (level - 1))
		
	end
	
end

Server Script (messy):

local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local PlayerBase = DataStoreService:GetDataStore("PlayerBase" .. 6)

local weaponsFolder = ReplicatedStorage:WaitForChild("Weapons")
local armorsFolder = ReplicatedStorage:WaitForChild("Armors")
local infoModule = require(ReplicatedStorage:WaitForChild("Info"))

local function playerAdded(player)
	
	local billboard

	print(player.Name, "has joined the game!")
	
	local success = nil
	local playerData = nil
	local attempt = 1
	
	repeat
		success, playerData = pcall(function()
			return PlayerBase:GetAsync(player.UserId)
		end)

		attempt += 1
		if not success then
			warn(playerData)
			task.wait()
		end

	until success or attempt == 3
	
	if success then
		
		print("Successfully retreived data for", player.Name)
		
		if not playerData then
			
			print("Giving new data to", player.Name)
			
			playerData = {
				["Gold"] = 0,
				["Level"] = 1,
				["XP"] = 0,
				["SelectedWeapon"] = "Wooden Sword",
				["SelectedArmor"] = "Wooden Armor",
				["Weapons"] = {},
				["Armors"] = {},
			}
			
			for i, v in pairs(weaponsFolder:GetChildren()) do
				
				if v:FindFirstChild("StarterTool") then
					
					playerData.Weapons[v.Name] = true
					
				else
					
					playerData.Weapons[v.Name] = false	
					
				end
				
			end
			for i, v in pairs(armorsFolder:GetChildren()) do

				if v:FindFirstChild("StarterArmor") then

					playerData.Armors[v.Name] = true

				else

					playerData.Armors[v.Name] = false	

				end

			end
			
		end
		
		local character = player.Character or player.CharacterAdded:Wait()
		
		for i, v in pairs(character:GetDescendants()) do
			
			if v:IsA("BasePart") then
				
				v.CollisionGroup = "Players"
				
			end
			
		end

		local leaderstats = Instance.new("Folder", player)
		leaderstats.Name = "leaderstats"

		local gold = Instance.new("NumberValue", leaderstats)
		gold.Name = "Gold"
		gold.Value = tonumber(playerData.Gold) or 0

		local level = Instance.new("NumberValue", leaderstats)
		level.Name = "Level"
		level.Value = tonumber(playerData.Level) or 1

		local xp = Instance.new("NumberValue", leaderstats)
		xp.Name = "XP"
		xp.Value = tonumber(playerData.XP) or 0

		local weapon = Instance.new("StringValue", player)
		weapon.Name = "SelectedWeapon"
		
		local armor = Instance.new("StringValue", player)
		armor.Name = "SelectedArmor"

		weapon:GetPropertyChangedSignal("Value"):Connect(function()

			for i, v in pairs(weaponsFolder:GetChildren()) do

				if player.Backpack:FindFirstChild(v.Name) then

					player.Backpack:FindFirstChild(v.Name):Destroy()

				end
				if character:FindFirstChild(v.Name) then

					character:FindFirstChild(v.Name):Destroy()

				end

			end

			local tool = weaponsFolder:FindFirstChild(weapon.Value).Tool:Clone()
			tool.Name = weapon.Value
			tool.Parent = player.Backpack

		end)
		armor:GetPropertyChangedSignal("Value"):Connect(function()
			
			if billboard then
				
				billboard.Holder.CharacterDefense.Text = "Defense: " .. armorsFolder:FindFirstChild(armor.Value).Defense.Value
				
			end
			
		end)
		
		local healthMod = infoModule.GetHealth(level.Value)
		character.Humanoid.MaxHealth = healthMod
		
		player.Backpack.ChildAdded:Connect(function(child)

			if child:IsA("Tool") then

				local healthMod = infoModule.GetHealth(level.Value)
				character.Humanoid.MaxHealth = healthMod

			end

		end)
		
		player.CharacterAdded:Connect(function()
			
			local healthMod = infoModule.GetHealth(level.Value)
			character.Humanoid.MaxHealth = healthMod
			character.Humanoid.Health = healthMod

			billboard = workspace.Billboards.CharacterBillboard:Clone()
			billboard.Parent = character:WaitForChild("Head")
			billboard.Holder.CharacterLevel.Text = "[" .. tostring(level.Value) .. "]"
			billboard.Holder.CharacterName.Text = player.DisplayName
			
			billboard.Holder.CharacterDefense.Text = "Defense: " .. armorsFolder:FindFirstChild(armor.Value).Defense.Value

			billboard.PlayerToHideFrom = player
			
			for i, v in pairs(weaponsFolder:GetChildren()) do

				if player.Backpack:FindFirstChild(v.Name) then

					player.Backpack:FindFirstChild(v.Name):Destroy()

				end
				if character:FindFirstChild(v.Name) then

					character:FindFirstChild(v.Name):Destroy()

				end

			end

			local tool = weaponsFolder:FindFirstChild(weapon.Value).Tool:Clone()
			tool.Name = weapon.Value
			tool.Parent = player.Backpack
			
		end)

		weapon.Value = playerData.SelectedWeapon or "Wooden Sword"
		armor.Value = playerData.SelectedArmor or "Wooden Armor"

		local weapons = Instance.new("Folder", player)
		weapons.Name = "Weapons"
		
		local armors = Instance.new("Folder", player)
		armors.Name = "Armors"

		for i, v in pairs(weaponsFolder:GetChildren()) do

			local weaponOBJ = Instance.new("BoolValue", weapons)
			weaponOBJ.Name = v.Name
			
			if v:FindFirstChild("StarterWeapon") then

				weaponOBJ.Value = playerData.Weapons[v.Name] or true

			else

				weaponOBJ.Value = playerData.Weapons[v.Name] or false	

			end

		end
		for i, v in pairs(armorsFolder:GetChildren()) do

			local armorOBJ = Instance.new("BoolValue", armors)
			armorOBJ.Name = v.Name
			
			if v:FindFirstChild("StarterArmor") then
				
				armorOBJ.Value = playerData.Armors[v.Name] or true
				
			else
				
				armorOBJ.Value = playerData.Armors[v.Name] or false	
				
			end

		end

		xp:GetPropertyChangedSignal("Value"):Connect(function()

			local nextEXP = infoModule.GetNextExp(level.Value)

			if xp.Value >= nextEXP then

				xp.Value -= nextEXP
				level.Value += 1

			end

		end)

		level:GetPropertyChangedSignal("Value"):Connect(function()

			local healthMod = infoModule.GetHealth(level.Value)
			character.Humanoid.Health = healthMod
			
			if billboard then
				
				billboard.Holder.CharacterLevel.Text = "[" .. tostring(level.Value) .. "]"
				
			end

		end)
		
		character.Humanoid.HealthChanged:Connect(function(newHealth)
			
			if character then
				
				if billboard then
					
					billboard.Holder.Health.Health.Text = math.floor(newHealth) .. "/" .. tostring(character.Humanoid.MaxHealth)
					billboard.Holder.Health.Current.Size = UDim2.new(newHealth / character.Humanoid.MaxHealth, 0, 1, 0)
					
				end
				
			end
			
		end)
		
	else
		
		player:Kick("Our Server failed to save your data. Please try again!")	
		
	end
	
end

local function playerRemoved(player)
	
	print(player.Name, "has left the game!")
	
	local success = nil
	local playerData = nil
	local attempt = 1
	
	local saveTable = {
		["Gold"] = player.leaderstats.Gold.Value,
		["Level"] = player.leaderstats.Level.Value,
		["XP"] = player.leaderstats.XP.Value,
		["SelectedWeapon"] = player.SelectedWeapon.Value,
		["SelectedArmor"] = player.SelectedArmor.Value,
		["Weapons"] = {},
		["Armors"] = {},
	}
	
	for i, v in pairs(player.Weapons:GetChildren()) do
		
		if v:FindFirstChild("StarterTool") then
			
			saveTable.Weapons[v.Name] = true
			
		else
			
			saveTable.Weapons[v.Name] = v.Value	
			
		end

	end
	for i, v in pairs(player.Armors:GetChildren()) do

		if v:FindFirstChild("StarterArmor") then

			saveTable.Armors[v.Name] = true

		else

			saveTable.Armors[v.Name] = v.Value	

		end

	end
	
	repeat
		success, playerData = pcall(function()
			return PlayerBase:UpdateAsync(player.UserId, function()
				return saveTable
			end)
		end)

		attempt += 1
		if not success then
			warn(playerData)
			task.wait()
		end

	until success or attempt == 3
	
end

game.Players.PlayerAdded:Connect(playerAdded)
game.Players.PlayerRemoving:Connect(playerRemoved)

game:BindToClose(function()
	for i, player in pairs(game.Players:GetPlayers()) do
		task.spawn(function()
			playerRemoved(player)
		end)
	end	
end)

ReplicatedStorage:WaitForChild("Events"):WaitForChild("SetWeapon").OnServerEvent:Connect(function(player, weaponName)
	
	player.SelectedWeapon.Value = weaponName
	
end)
ReplicatedStorage:WaitForChild("Events"):WaitForChild("SetArmor").OnServerEvent:Connect(function(player, weaponName)

	player.SelectedArmor.Value = weaponName

end)
ReplicatedStorage:WaitForChild("Events"):WaitForChild("WeaponPurchased").OnServerEvent:Connect(function(player, weaponName, cost)
	
	player.leaderstats.Gold.Value -= cost
	player.Weapons:FindFirstChild(weaponName).Value = true
	
end)
ReplicatedStorage:WaitForChild("Events"):WaitForChild("ArmorPurchased").OnServerEvent:Connect(function(player, armorName, cost)

	player.leaderstats.Gold.Value -= cost
	player.Armors:FindFirstChild(armorName).Value = true

end)
3 Likes

Is this intended? You haven’t told us what’s wrong.

Your code is also really prone to exploits, because all of your RemoteEvents have 0 checks, which means players can send over any value.

2 Likes

Well, it’s supposed to set the player’s health to a formula.

1 Like

What I would do is set the health when CharacterAdded fires, and also when their level is changed.

The reason it seems to not be working for you is that you’re storing a character variable, and that character variable only stores the character that the player first had when they joined. You need to access player.Character instead of using that character variable.

Elaborate with the challenge output of the script please.

I am not entirely sure why this isn’t working but I think that maybe that the humanoid isn’t entirely loaded in. I would try the following:

  • Ensure the GetHealth() function is returning the desired value
  • Ensure the character value is actually still pointing to the correct character
  • Use character:WaitForChild("Humanoid").MaxHealth = healthMod
  • Use a print statement to check their humanoid’s health value after setting it

then use the information above to pinpoint where the problem might be

Unfortunately, all those steps failed…

1 Like

make sure character is loaded in like this

local character = player.CharacterAdded:Wait()
	repeat task.wait() until character.Parent == workspace
1 Like

It sadly did not work. If you’d like to see what it is for yourself, heres the link: The Game

try this out and lmk if this works:

replace your:

player.CharacterAdded:Connect(function()
			
			local healthMod = infoModule.GetHealth(level.Value)
			character.Humanoid.MaxHealth = healthMod
			character.Humanoid.Health = healthMod

			billboard = workspace.Billboards.CharacterBillboard:Clone()
			billboard.Parent = character:WaitForChild("Head")
			billboard.Holder.CharacterLevel.Text = "[" .. tostring(level.Value) .. "]"
			billboard.Holder.CharacterName.Text = player.DisplayName
			
			billboard.Holder.CharacterDefense.Text = "Defense: " .. armorsFolder:FindFirstChild(armor.Value).Defense.Value

			billboard.PlayerToHideFrom = player
			
			for i, v in pairs(weaponsFolder:GetChildren()) do

				if player.Backpack:FindFirstChild(v.Name) then

					player.Backpack:FindFirstChild(v.Name):Destroy()

				end
				if character:FindFirstChild(v.Name) then

					character:FindFirstChild(v.Name):Destroy()

				end

			end

With this version:

		player.CharacterAdded:Connect(function(char)

			local healthMod = infoModule.GetHealth(level.Value)
			char:WaitForChild("Humanoid").MaxHealth = healthMod
			char:WaitForChild("Humanoid").Health = healthMod

			billboard = workspace.Billboards.CharacterBillboard:Clone()
			billboard.Parent = character:WaitForChild("Head")
			billboard.Holder.CharacterLevel.Text = "[" .. tostring(level.Value) .. "]"
			billboard.Holder.CharacterName.Text = player.DisplayName

			billboard.Holder.CharacterDefense.Text = "Defense: " .. armorsFolder:FindFirstChild(armor.Value).Defense.Value

			billboard.PlayerToHideFrom = player

			for i, v in pairs(weaponsFolder:GetChildren()) do

				if player.Backpack:FindFirstChild(v.Name) then

					player.Backpack:FindFirstChild(v.Name):Destroy()

				end
				if char:FindFirstChild(v.Name) then

					char:FindFirstChild(v.Name):Destroy()

				end

			end

			local tool = weaponsFolder:FindFirstChild(weapon.Value).Tool:Clone()
			tool.Name = weapon.Value
			tool.Parent = player.Backpack

		end)

Edit: To elaborate on this, the char variable that is passed into the .CharacterAdded() is what is going to hold the new character that spawns in every time. I see some other parts of your script are relying on the older character variable. If this is intentional, all good. If not just keep that in mind in case you run into more undefined behavior!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.