Player Skills: Equipping and Saving

How would you go about making skills. And I don’t mean the actual skills, what I mean is how would you assign the skill to the player and also how would you save what skills the player has bought.

How would I store the skills that he owns and save the last one he equipped so when he gets back on the game he has the same skill equipped. Would that require 2 data stores?

The closest example that I could’ve think of is how Blade Ball handles skills (one skill equipped at a time).

The best way you could do this is by using a StringValue to control what skill the player has equipped, and then a folder of BoolValues to note what skills the player owns.

Then, save an array to the DataStore, something like:

local dataToSave = {
    ["EquippedSkill"] = player.EquippedSkill.Value,
    ["OwnedSkills"] = {
        --array of skills the player owns, in strings (use the names)
    }
}

Would something like this work?

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local SkillsDataStore = DataStoreService:GetDataStore("PlayerSkills")

local Skills = {
	[1] = "Run",
	[2] = "Jump"
}

local function savePlayerData(player)
	local key = "Player_".. player.UserId

	local dataToSave = {
		EquippedSkill = player.Info.EquippedSkill,
		OwnedSkills = player.Info.OwnedSkills
	}

	local success, error = pcall(function()
		SkillsDataStore:SetAsync(key, dataToSave)
	end)
end

local function loadPlayerData(player)
	local key = "Player_".. player.UserId

	local success, data = pcall(function()
		return SkillsDataStore:GetAsync(key)
	end)

	if success and data then
		player.Info.EquippedSkill = data.EquippedSkill
		player.Info.OwnedSkills = data.OwnedSkills
	else
		local Info = Instance.new("Folder", player)
		Info.Name = "Info"
		local EquippedSkill = Instance.new("StringValue", Info)
		EquippedSkill.Name = "EquippedSkill"
		local OwnedSkills = Instance.new("Folder", Info)
		OwnedSkills.Name = "OwnedSkills"
		player.Info.EquippedSkill.Value = "None"
		for i, v in Skills do
			local BoolValue = Instance.new("BoolValue", OwnedSkills)
			BoolValue.Name = Skills[i]
			BoolValue.Value = false
		end
		savePlayerData(player)
	end
end

Players.PlayerAdded:Connect(function(player)
	loadPlayerData(player)
	player.Changed:Connect(function(property)
		if property == "EquippedSkill" or property == "OwnedSkills" then
			savePlayerData(player)
		end
	end)
end)

Players.PlayerRemoving:Connect(function(player)
	savePlayerData(player)
end)

No, it probably wouldn’t - I think you’re trying to save an instance value.

For the BoolValues folder, you want to have every skill in your game and have the value to true for ones the player owns.

So, when you save:

local ownedSkills = {}
for _, skill in ipairs(player.Info.OwnedSkills:GetChildren()) do
    if skill.Value == true then
        table.insert(ownedSkills, skill.Name)
    end
end

local data = {
    ["EquippedSkill"] = player.Info.EquippedSkill.Value,
    ["OwnedSkills"] = ownedSkills
}

local success, result = pcall(function()
    SkillsDataStore:UpdateAsync(key, function(old)
        --UpdateAsync is better for helping to prevent data loss
        --you can insert comparison code here as well btw
        return data
    end)
end)

You mean like this? Probably not, cuz the second time I enter the game I no longer have the folder.

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local SkillsDataStore = DataStoreService:GetDataStore("PlayerSkills")

local Skills = {
	[1] = "Run",
	[2] = "Jump"
}

local function savePlayerData(player)
	local key = "Player_".. player.UserId

	local ownedSkills = {}
	for _, skill in ipairs(player.Info.OwnedSkills:GetChildren()) do
		if skill.Value == true then
			table.insert(ownedSkills, skill.Name)
		end
	end

	local data = {
		["EquippedSkill"] = player.Info.EquippedSkill.Value,
		["OwnedSkills"] = ownedSkills
	}

	local success, result = pcall(function()
		SkillsDataStore:UpdateAsync(key, function(old)
			return data
		end)
	end)
end

local function loadPlayerData(player)
	local key = "Player_".. player.UserId

	local success, data = pcall(function()
		return SkillsDataStore:GetAsync(key)
	end)

	if success and data then
		player.Info.EquippedSkill.Value = data.EquippedSkill
		for _, skillName in ipairs(data.OwnedSkills) do
			local skillValue = player.Info.OwnedSkills[skillName]
			if skillValue then
				skillValue.Value = true
			end
		end
	else
		local Info = Instance.new("Folder", player)
		Info.Name = "Info"
		local EquippedSkill = Instance.new("StringValue", Info)
		EquippedSkill.Name = "EquippedSkill"
		local OwnedSkills = Instance.new("Folder", Info)
		OwnedSkills.Name = "OwnedSkills"
		player.Info.EquippedSkill.Value = "None"
		for i, v in ipairs(Skills) do
			local BoolValue = Instance.new("BoolValue", OwnedSkills)
			BoolValue.Name = v
			BoolValue.Value = false
		end
		savePlayerData(player)
	end
end

Players.PlayerAdded:Connect(function(player)
	loadPlayerData(player)
	player.Changed:Connect(function(property)
		if property == "EquippedSkill" or property == "OwnedSkills" then
			savePlayerData(player)
		end
	end)
end)

Players.PlayerRemoving:Connect(function(player)
	savePlayerData(player)
end)

No, the folder doesn’t save with the data - you cannot save an instance. You would still have to set up the folder and values, but then you can iterate over them and set whatever ones they have to true.

Alright, I got it working. Thank you so much!

1 Like

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