Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Same level for all players?

Hey, this question is about something I've been looking at for weeks which is now causing my project to come to a stop until it is resolved.

I have a script, and I'm sorry but for now I will have to post the whole script due to the possibility of not being able to work out my problem through a segment of it. But anyway this script gives each player their stats and levels etc... But when a player dies at the same time as another player or even after in some cases, the script will give that number of players the same level as everyone else.

For example; I'm level 3 in the game and there are two other players, level 1. When the round ends and all three of us are 'reset' the other two players in the game will be level 3 aswell as me. Or I will be level 1 the same as them.

I hope that is enough of an explanation for you to be able to understand my problem. Thanks for any help given in advance, it is highly appreciated!

local ds = game:GetService("DataStoreService"):GetDataStore("dataone")

function CharacterRemoving(newPlayer)

	p = game.Players:GetPlayers()
	for i = 1, #p do
		s = Instance.new("StringValue", p[i].Character)
		s.Name = "Playing"
	end

	local stats = Instance.new("IntValue")
	stats.Name = "leaderstats"
	
	 coins = Instance.new("IntValue")
	coins.Name = "Coins"
	
	 tokens = Instance.new("IntValue")
	tokens.Name = "Tokens"
	
	 xp = Instance.new("IntValue")
	xp.Name = "XP"

 	levels = Instance.new("IntValue")
	levels.Name = "Levels"
	
	coins.Parent = stats
	tokens.Parent = stats
	xp.Parent = stats
	levels.Parent = stats


	stats.Parent = newPlayer
	
	
	if ds:GetAsync("Key" .. newPlayer.Name) then
		coins.Value = ds:GetAsync("Key" .. newPlayer.Name)
	else
		coins.Value = 0
	end

	if ds:GetAsync("Key1" .. newPlayer.Name) then
		tokens.Value = ds:GetAsync("Key1" .. newPlayer.Name)
	else
		tokens.Value = 0
	end

	if ds:GetAsync("Key2" .. newPlayer.Name) then
		xp.Value = ds:GetAsync("Key2" .. newPlayer.Name)
	else
		xp.Value = 0
	end

	if ds:GetAsync("Key3" .. newPlayer.Name) then
		levels.Value = ds:GetAsync("Key3" .. newPlayer.Name)	
	else
		levels.Value = 1
		levels.Changed:connect(function(save)
			ds:SetAsync("Key3" .. newPlayer.Name, save)
		end)
	end

	while true do
	
	wait(1)
		coins.Changed:connect(function(save)
			ds:SetAsync("Key" .. newPlayer.Name, save)
		end)
		tokens.Changed:connect(function(save)
			ds:SetAsync("Key1" .. newPlayer.Name, save)
		end)
		xp.Changed:connect(function(save)
			ds:SetAsync("Key2" .. newPlayer.Name, save)
		end)
		
	end
end

game.Players.PlayerAdded:connect(CharacterRemoving)

-- Problem is just under here i'm guessing.
function CharacterRemoving(newPlayer)
	levels.Value = ds:GetAsync("Key3" .. newPlayer.Name)
	wait(1)
	wait(0.1)
	if xp.Value >= 100 then
		levels.Value = levels.Value + 1
		xp.Value = 0
	end
	gui=Instance.new("BillboardGui")
	gui.Parent=newPlayer.Character.Head
	gui.Adornee=newPlayer.Character.Head
	gui.Size=UDim2.new(3,0,2,0)
	gui.StudsOffset=Vector3.new(0,2,0)
	text=Instance.new("TextLabel")
	text.Text = "Level " .. newPlayer.leaderstats.Levels.Value
	text.Size=UDim2.new(1.25,0,0.5,0)
	text.Position=UDim2.new(-0.125,0,-0.25,0)
	text.BackgroundTransparency = 1
	text.Parent=gui
	text.FontSize = ("Size36")
	text.Font = ("ArialBold")
	text.TextColor3 = Color3.new(255, 255, 0)
	text.TextStrokeColor3 = Color3.new(0, 0, 0)
	text.TextStrokeTransparency = 0
	w = game.Lighting.WepsGroup:GetChildren() 
	for i = 1,#w do
		w[i]:Clone().Parent = newPlayer.Backpack
	end
end

function onPlayerEntered(newPlayer) 
	newPlayer.Changed:connect(function (property) 
		if (property == "Character") then 
			CharacterRemoving(newPlayer) 
		end 
	end) 
end 
game.Players.PlayerAdded:connect(onPlayerEntered) 
game.Players.ChildAdded:connect(CharacterRemoving)
game.Players.PlayerAdded:connect(CharacterRemoving)


8 comments

0

You're connecting hte CharacterRemoving Function 2 times with the same event, remove line 80 completely and test please

0

Three times, actually. Lines 121 and 122 are effectively the same as well.

0

Hey, thanks for the reply. I've tried removing it and i'm guessing it stopped the ' CharacterRemoving' function to stop working because the level now doesn't display above the players head.

0

DataStores coding tends to be buggy in the best of times. I highly suggest using this module: http://wiki.roblox.com/index.php?title=PlayerDataStore_module or making the rest of the code work BEFORE adding DataStore saving.

0

The datastore side of it is fine, on the leaderboard everyones levels are as they should be. It's just the billboard GUI that is messing up and its obviously confused by who is who.

0

I'm going to format your code properly and give this another look. Just one moment...

0

Alright, there is a lot going on here that could be done a LOT better. I'm gonna write an Answer describing all the fixes.

0

Okay thanks for that. I did think it was quite a mess.

1 answer

✓ Accepted answer

There are a lot of problems with your code. I'm going to go through it line by line and refactor it. This may not fix anything, but it will run a lot better.

local ds = game:GetService("DataStoreService"):GetDataStore("dataone")

function PlayerAdded(newPlayer) --This function is called when a Player gets added. Why is it called 'CharacterRemoving'?

--I'm not really sure what to do with this block of code. It definitely doesn't go inside the PlayerAdded function. What are you trying to do with this?
--[[    p = game.Players:GetPlayers()
    for i = 1, #p do
        s = Instance.new("StringValue", p[i].Character)
        s.Name = "Playing"
    end]]

    local stats = Instance.new("IntValue", newPlayer) --We can use this second argument to set the Parent on the same line.
    stats.Name = "leaderstats"

     local coins = Instance.new("IntValue", stats) --ALL of these properties are now local! If they aren't, they will overwrite each other and we don't want that.
    coins.Name = "Coins"

    local tokens = Instance.new("IntValue", stats)
    tokens.Name = "Tokens"

    local xp = Instance.new("IntValue", stats)
    xp.Name = "XP"

    local levels = Instance.new("IntValue", stats)
    levels.Name = "Levels"

	local coinKey = ds:GetAsync("Key" .. newPlayer.Name) --GetAsync called more than once is wasteful. You have a limit to the number of times you can call this per minute!
    if coinKey then
        coins.Value = coinKey
    else
        coins.Value = 0
    end

	local tokensKey = ds:GetAsync("Key1" .. newPlayer.Name)
    if  tokensKey then
        tokens.Value = tokensKey
    else
        tokens.Value = 0
    end
	local xpKey = ds:GetAsync("Key2" .. newPlayer.Name)
    if xpKey then
        xp.Value =xpKey
    else
        xp.Value = 0
    end
	local levelsKey = ds:GetAsync("Key3" .. newPlayer.Name)
    if  then
        levels.Value = ds:GetAsync("Key3" .. newPlayer.Name)    
    else
        levels.Value = 1
    end

	--This while loop was repeatedly creating these function connections once a second. Changed events will fire every single time they are fired!
        coins.Changed:connect(function(save)
            ds:SetAsync("Key" .. newPlayer.Name, save)
        end)
        tokens.Changed:connect(function(save)
            ds:SetAsync("Key1" .. newPlayer.Name, save)
        end)
	
	local xpDeb = false
        xp.Changed:connect(function() --I made this function control saving of both levels and xp, based on your formula below.
		if xpDeb then return end
		xpDeb = true
		while xp.Value >= 100 do
			xp.Value = xp.Value - 100
			levels.Value = levels.Value + 1
		end
            ds:SetAsync("Key2" .. newPlayer.Name, xp.Value)
		ds:SetAsync("Key3" .. newPlayer.Name, levels.Value)
		xpDeb = false
        end)

	local function CharacterAdded(newCharacter) --NEVER use the same global function name twice. This can cause unforeseeable bugs and errors!
		--This function had to be moved inside here so that trying to access the various ValueObjects that are now local don't cause any errors.
		--We already loaded this above! No need to do it again.
	    --levels.Value = ds:GetAsync("Key3" .. newPlayer.Name)
	    wait(1.1) --No need for two wait statements
	
	    local gui = Instance.new("BillboardGui") --This could have been your error! When this function was called more than once, the global `gui` variable got overwritten. Setting it to be a local variable makes sure that your code works as intended: only editing THIS BillboardGui.
	    gui.Parent = newPlayer.Character.Head
	    gui.Adornee = newPlayer.Character.Head
	    gui.Size = UDim2.new(3,0,2,0)
	    gui.StudsOffset = Vector3.new(0,2,0)
	
	    local text = Instance.new("TextLabel")
	    text.Text = "Level " .. newPlayer.leaderstats.Levels.Value
	    text.Size = UDim2.new(1.25,0,0.5,0)
	    text.Position = UDim2.new(-0.125,0,-0.25,0)
	    text.BackgroundTransparency = 1
	    text.Parent = gui
	    text.FontSize = ("Size36")
	    text.Font = ("ArialBold")
	    text.TextColor3 = Color3.new(255, 255, 0)
	    text.TextStrokeColor3 = Color3.new(0, 0, 0)
	    text.TextStrokeTransparency = 0
	
		for _, wep in ipairs(game.Lighting.WepsGroup:GetChildren()) do --A generic `for` is better here than a numeric.
	        wep:Clone().Parent = newPlayer.Backpack
	    end
	end
	newPlayer.CharacterAdded:connect(CharacterAdded)
end
game.Players.PlayerAdded:connect(PlayerAdded)

--All the lines after this are completely unnecessary.

If this still errors, please let me know where.

2 comments

0

Oh wow thank you, i'm glad someone has explained it to me because it makes a lot more sense now. I hate to be persevering but the Billboard Gui no longer displays above the players head. And from reading your script I cannot see what is wrong?

0

Don't worry its fine. Anyway thank you for everything! I'm pleased I can get back on track with my game. You deserve more +1's!

This discussion is preserved as it was. New answers, comments, and votes are closed.