Ep 2. Player Data Service

During this episode of the Super Simple Obby series, we created the Player Data Service module script. After creating this episode I realized that there was a better way for us to handle the type of a Profile from the Profile Service module. Instead of recording the entire episode again, I recorded the portion of the episode when we create the Player Data Service. Towards the end of the episode we revisit the Player Data Service module, which contains the code of our previous implementation. To avoid any confusion, I wanted to release the full script here.

Script

ServerScriptService/Service/PlayerDataService.lua
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local ServerScriptService = game:GetService("ServerScriptService")

local ProfileService = require(ServerScriptService.Libs.ProfileService)
local DataTemplate = require(ReplicatedStorage.PlayerData)

local DATASTORE_NAME = "Production" -- DO NO MODIFY

if RunService:IsStudio() then
	DATASTORE_NAME = "Testing"
end

local ProfileStore = ProfileService.GetProfileStore(DATASTORE_NAME, DataTemplate.DEFAULT_PLAYER_DATA)

local Profiles: { [Player]: ProfileService.Profile<DataTemplate.PlayerData> } = {}

local Local = {}
local Shared = {}

function Shared.OnStart()
	Players.PlayerAdded:Connect(Local.CreateProfile)
	Players.PlayerRemoving:Connect(Local.RemoveProfile)

	for _, player in Players:GetPlayers() do
		Local.CreateProfile(player)
	end
end

function Shared.GetState(player: Player)
	local profile = Profiles[player]
	if profile then
		return profile.Data
	end
	
	return nil
end

function Local.CreateLeaderstats(player: Player)
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"

	local stage = Instance.new("NumberValue", leaderstats)
	stage.Name = "Stage"
	stage.Value = 1
end

function Local.CreateProfile(player: Player)
	local userId = player.UserId
	local profileKey = `{userId}_Data`
	local profile = ProfileStore:LoadProfileAsync(profileKey)
	
	if not profile then
		player:Kick("Unable to load your player data.")
		return
	end
	
	profile:ListenToRelease(function()
		Profiles[player] = nil
		player:Kick()
	end)
	
	profile:AddUserId(userId)
	profile:Reconcile()
	
	Profiles[player] = profile
	Local.CreateLeaderstats(player)
end

function Local.RemoveProfile(player: Player)
	local profile = Profiles[player]
	if profile then
		profile:Release()
	end
end

return Shared
Contents