Save Slots & Profile Service

Hi! Just finished setting up profile service so it saves and loads my very basic template data.

  1. I want to achieve a character / save slot system using profile service.

I’m trying to achieve a save slot system where there is a choice between two races (two save slots) and after choosing one the data will be loaded/saved into that slot.

2, Just can’t seem to wrap my head around this topic and I can’t find much online that gives many answers so I would really appreciate any guidance.

I have read through the data store and profile service documentation and understand it to a certain extent, but I don’t feel this is the best approach for me to understand how to achieve this.

  1. So far from what I’ve read, I need to create a different key for each save slot and use LoadProfileAsync() depending on which of the two data slots the player picked.

Here is just the code for the player data handler module:

local PlayerDataHandler = {}


local dataTemplate = {
	Currency = 0,
	Rank = "D",
}

local ProfileService = require(game.ServerScriptService:WaitForChild("ProfileService"))
local Players = game:GetService("Players")

local ProfileStore = ProfileService.GetProfileStore(
	"PlayerProfile",
	dataTemplate
)

local Profiles = {}

local function playerAdded(player)
	local profile = ProfileStore:LoadProfileAsync("Player_"..player.UserId)
	
	if profile then
		profile:AddUserId(player.UserId)
		profile:Reconcile()
		profile:ListenToRelease(function()
			Profiles[player] = nil
			player:Kick()
		end)
		
		if not player:IsDescendantOf(Players) then
			profile:Release()
		else
			Profiles[player] = profile
			
			print(Profiles[player].Data)
		end
	else
		player:Kick()
	end
end

function PlayerDataHandler:Init()
	for _, player in game.Players:GetPlayers() do
		task.spawn(playerAdded, player)
	end
	
	game.Players.PlayerAdded:Connect(playerAdded)
	
	game.Players.PlayerRemoving:Connect(function(player)
		if Profiles[player] then
			Profiles[player]:Release()
		end
	end)
end


local function getProfile(player)
	assert(Profiles[player], string.format("Profile does not exist for %s", player.UserId))
	
	return Profiles[player]
end


function PlayerDataHandler:Get(player, key)
	local profile = getProfile(player)
	assert(profile.Data[key], string.format("Data does not exist for key: %s", key))
	
	return profile.Data[key]
end

function PlayerDataHandler:Set(player, key, value)
	local profile = getProfile(player)
	assert(profile.Data[key], string.format("Data does not exist for key: %s", key))
	
	assert(type(profile.Data[key]) == type(value))
		
	profile.Data[key] = value
end

function PlayerDataHandler:Update(player, key, callback)
	local profile = getProfile(player)
	
	local oldData = self:Get(player, key)
	local newData = callback(oldData)
	
	self:Set(player, key, newData)
end


return PlayerDataHandler

Appreciate any guidance big or small :grin:

4 Likes

Alright I’ll try my best to give you an answer of what you are looking for.

I would recommend following the advice that you’ve been given of creating separate keys to load.

For example, I would do:

local profileSave1 = ProfileStore:LoadProfileAsync("Player_Save1_"..player.UserId)

if the player chose the first save OR do

local profileSave2 = ProfileStore:LoadProfileAsync("Player_Save2_"..player.UserId)

if the player chose the second save.

This would activate two separate keys used in order to load the profile. If you are worried about data being mixed for example leaderstats, leaderstats just copies the data from that current profile onto the player.

As long as the player’s userId is part of each key, there should be no problem.

1 Like

This makes sense to me thank you

2 Likes

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