Hi, I’m making a game where you bring your unit from inventory into the game place kind of like a Tower Defense.
I’m new to profileservice (literally like 3 hours ago) and I need help with how would I:
-Update/Save/Store data
-Get data from profileservice from server/local scripts
-Get data that’s not in the leaderboard (I don’t want the roblox leaderboard)
Also I’m having problem with loading the name to my GUI
codes:
Code in the GUI
local player = game.Players.LocalPlayer
local spawnevent = game.ReplicatedStorage.SpawnEvent
local folderownerevent = game.ReplicatedStorage.FolderOwnerEvent
local datamanager = require(game.ServerScriptService.Modules.DataManager)
local playerfolder = nil
while playerfolder == nil do
for i, v in pairs(game.Workspace.Bots:GetChildren()) do
if v.Name == player.Name then
playerfolder = v
print("Got "..player.Name.."'s folder")
end
end
end
script.Parent.TextLabel.Text = player:WaitForChild("Unit1", math.huge).Value
script.Parent.MouseButton1Up:Connect(function()
local Unit = player:WaitForChild("Unit1", math.huge).Value
spawnevent:FireServer(playerfolder, Unit)
end)
Data Manager:
local Players = game:GetService("Players")
local serverscriptservice = game:GetService("ServerScriptService")
local mod = serverscriptservice:WaitForChild("Modules")
local ProfileService = require(mod:WaitForChild("ProfileService"))
local template = require(script:WaitForChild("Template"))
local leaderstats = require(script:WaitForChild("Leaderstats"))
local datakey = "_DataStore"
local profileStore = ProfileService.GetProfileStore(datakey, template)
local datamanager = {}
datamanager.Profiles = {}
local function PlayerAdded(player: Player)
local profile = profileStore:LoadProfileAsync("Player_"..player.UserId)
if profile ~= nil then
profile:AddUserId(player.UserId)
profile:Reconcile()
profile:ListenToRelease(function()
datamanager.Profiles[player] = nil
player:Kick("Cannot Find Player's Data Profile")
end)
if player:IsDescendantOf(Players) then
datamanager.Profiles[player] = profile
leaderstats:Create(player, profile)
else
profile:Release()
end
else
player:Kick("Cannot Find Player's Data Profile")
end
end
local function PlayerRemoving(player: Player)
local profile = datamanager.Profiles[player]
if profile ~= nil then
profile:Release()
end
end
for _, player in Players:GetPlayers() do
task.spawn(PlayerAdded, player)
end
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving)
return datamanager
If you want to have easy access of read and write, I’d recommend replicating the data in folders, for example: Cash goes in leaderstats, Unit1->Unit6 goes in Units. Whenever any of the value are changed in the folders, update the profile accordingly, this is how i usually do it
Then whenever you want to edit the data, just change the value in the server!
Hmm, I think the easiest thing to do for saving/loading player data is to simply create a method for them. Example:
function datamanager:GetData(player)
local profile = datamanager.Profiles[player]
if profile ~= nil then
return profile.Data
end
end
function DataManager:UpdateData(player, dataToUpdate, newData)
local data = self:GetData(player)
if data ~= nil then
local oldDataValueType = typeof(data[dataToUpdate])
if oldDataValueType == typeof(newData) then
data[dataToUpdate] = newData
if dataToUpdate == "Something" then -- remove this if you do not need to update any leaderstats value (those values displayed on game leaderboard)
player.leaderstats["Something"].Value = newData
end
end
end
end
As for displaying your data to a GUI, you can’t access DataStore from client (I see you requiring the datamanager module which is inside ServerScriptService → the client can’t even see whats inside lol)
So, I recommend you to use ReplicaService: ReplicaService
If you do use ReplicaService tho, you need to change your :UpdateData() method
function DataManager:UpdateData(player, dataToUpdate, newData)
local data = self:GetData(player)
local dataReplica = -- reference the replica of player's data here
if data ~= nil then
local oldDataValueType = typeof(data[dataToUpdate])
if oldDataValueType == typeof(newData) then
data[dataToUpdate] = newData
dataReplica:SetValue({dataToUpdate}, newData)
if dataToUpdate == "Something" then -- remove this if you do not need to update any leaderstats value (those values displayed on game leaderboard)
player.leaderstats["Something"].Value = newData
end
end
end
end
not exactly, the way i potray is: the data within the profile data will be synced with the leaderstats/other folders (not sure if theres any flaws but this is how I go with it in my games)
for example, if you change the cash value, it will update the profile data’s cash value as well
I took one of my module for replication that supports multidimensional arrays, it works like the thing i just said but practically.
Module
-- // Package
local DataReplication = {}
-- // Functions
function DataReplication:BindProfileToFolder(folder: Folder, linkedData, path)
local function ConnectDataReference(ref: ValueBase)
local function OnValueChanged()
if path then
local DataTokens = path:split('.')
local BufferName = table.remove(DataTokens, 1)
local Buffer = linkedData[BufferName]
for _, token in DataTokens do
Buffer = Buffer[token]
BufferName = token
end
Buffer[ref.Name] = (ref:IsA('ObjectValue') and ref.Name or ref.Value)
else
linkedData[ref.Name] = ref.Value
end
end
ref:GetPropertyChangedSignal('Value'):Connect(OnValueChanged)
OnValueChanged()
end
local function ConnectDataReferenceOnRemove(ref: ValueBase)
if path then
local DataTokens = path:split('.')
local BufferName = table.remove(DataTokens, 1)
local Buffer = linkedData[BufferName]
for _, token in DataTokens do
Buffer = Buffer[token]
BufferName = token
end
Buffer[ref.Name] = nil
else
linkedData[ref.Name] = nil
end
end
folder.ChildAdded:Connect(ConnectDataReference)
folder.ChildRemoved:Connect(ConnectDataReferenceOnRemove)
for _, reference: ValueBase in folder:GetChildren() do
ConnectDataReference(reference)
end
end
-- ex paths: { 'Inventory.Gears', 'Inventory.Accessories' }
function DataReplication:ReplicateData(paths: {string}, player: Player, linkedData)
for _, path in paths do
local DataTokens = path:split('.')
local BufferName = table.remove(DataTokens, 1)
local Buffer = linkedData[BufferName]
for _, token in DataTokens do
Buffer = Buffer[token]
BufferName = token
end
local Folder = Instance.new('Folder')
Folder.Name = BufferName
for k, v in Buffer do
local ReferenceName = type(k) == 'number' and v or k
local ValueType = type(v)
ValueType = ValueType == 'boolean' and 'bool' or ValueType
local DataReference = Instance.new(`{ValueType:gsub('^.', string.upper)}Value`)
DataReference.Name = ReferenceName
DataReference.Value = v
DataReference.Parent = Folder
end
DataReplication:BindProfileToFolder(Folder, linkedData, path)
Folder.Parent = player
end
end
return DataReplication
Usage Example:
DataReplication:BindProfileToFolder(
playerProfile:CreateProfileLeaderstats(player, { 'PartBux', 'Minutes' }), -- creates the leaderstats
ProfileData
) -- binds it
DataReplication:ReplicateData(
{
'DialogueMemory',
'Inventory.Gears', 'Inventory.Accessories', 'Inventory.BoxSkins',
'EquippedAccessories'
},
player, ProfileData
) -- create the folders and values, then bind it automatically