I’m pretty sure there’s an example in the ReplicaService page.
I know that but how would I go about making a profile and replicate that to the client. The example just shows how to set up a class token. Could you help by showing me an example?
Can anyone show me an example of how to use GlobalUpdates? The API docs confuse me
Shout out to okeanskiy and his amazing video that is explaining how it works.
Watch it here: Global Updates: ProfileService Tutorial Part 2 (Roblox Studio) - YouTube
umm Im kinda of a noob so i do not know much about how to deal with my problem, so i have the data saving fine for the most part but for some reason one of the data key thingies gets deleted or something and turns into nil for some reason. but its just one of the data thingies(im basically saying that if there was levels coins and exp to save, exp for some reason just gets nil SOMETIMES for some reason.) that turns into nil. The other ones like level and coins never did turn into nil. i do not know why it happenned, i set the script up with the video of okeanskiy. I hope you can help me.
local ServerScriptService = game:GetService("ServerScriptService")
local RS = game:GetService("ReplicatedStorage")
local ProfileService = require(RS.ProfileService)
local UiColorTable = {{1,1,134},{10,124,134},{12,255,247},{26,255,129},{23,135,6},{167,255,2}
,{255,255,3},{255,158,1},{255,74,14},{255,0,0},{255,6,72},{255,6,160},{96,0,103}}
local profileStore = ProfileService.GetProfileStore(
"Player",{
UiColorTheme = UiColorTable[math.random(1,13)];
Sectoriat = 0;
Level = 1;
Exp = 0;
}
)
local Profiles = {}
local function onPlayerAdded(player)
local profile = profileStore:LoadProfileAsync(
"Player_" .. player.UserId,
"ForceLoad"
)
if profile then
profile:ListenToRelease(function()
Profiles[player] = nil
player:Kick()
end)
if player:IsDescendantOf(PlayerService)then
Profiles[player] = profile
else
profile:Release()
end
else
player:Kick()
end
end
local function onPlayerRemoved(player)
local profile = Profiles[player]
if profile then
profile:Release()
end
end
PlayerService.PlayerAdded:Connect(onPlayerAdded)
PlayerService.PlayerRemoving:Connect(onPlayerRemoved)
local DataManager = {}
function DataManager:Get(player)
local profile = Profiles[player]
if profile then
return profile.Data
end
end
function DataManager:GetProfileStore()
return profileStore
end
return DataManager```
Note: Sectoriat is basically coins.
What about it isn’t working? Also use ``` on the top and below code.
Well as i stated, for some reason exp just keeps on turning into nil while the others have no problem, btw i have never changed any of the values to nil in my scripts so im kinda scared like if this happened to me a few times already, what would happen when i release my game. People would lose their exp and worst part is since it turns into nil i can’t do anything with exp since it causes a lot of errors like some parts of the scripts would just stop. Thats why i thought i would ask it here.
Did you add the Exp key into the profile template after originally testing it? If so, you’ll need to call :Reconcile()
upon finding a profile to ensure that they have the most updated template.
Well then, i will try to write reconcile function , if i can’t get it to work hopefully you guys can help me.
I just want to point out that this method of saving player data has probably saved me from potential major headache, since working with datastores is a very delicate and tedious process that every new developer on the Roblox platform will eventually have to tackle with.
If done incorrectly, you could accidentally shoot yourself on the foot in the future. Having to deal with hundreds if not thousands of player lodging complaints at you on why their data is suddenly gone while having to rework on your hard-worked but to failed datastore system is a situation I and anyone else wouldn’t want to be in.
In this case, thank you very much for creating this ProfileService. As an inexperienced developer I had underestimated just how much this Service could save me not just time but also health.
I’m putting my player inventory data in an inventory folder. But this loop isn’t working and I don’t know what to do… please help
for i, v in ipairs(profile.Data.Inventory) do
local InvItem = Instance.new("IntValue")
InvItem.Value = v
InvItem.Name = i
InvItem.Parent = Inventory
end
What is the ‘Inventory’ and try to use pairs not ipairs for the loop.
Ok inventory is a folder in player
Thanks, It works. TYSM
Why do I always get this when playing in real game, but not in studio. I am using ProfileService btw.
Are you using :Reconcile()?
This seems like a you problem, the leaderstats for YOU aren’t being created.
Additionally, check if the PlayerAdded event doesn’t get connected after something yields, like a require(assetId)
Try making the PlayerAdded connection into a function, and then have it handle it like this:
for _, plr in ipairs(game.Players:GetPlayers()) do
coroutine.wrap(onPlayerAdded)(plr)
end
game.Players.PlayerAdded:Connect(onPlayerAdded)
Loleris, I have a question, does the :ListenToHopReady()
signal, additionally check with another UpdateAsync request, to see if the profile is released?
Thank you this worked! I didn’t do courtine for all players and did it outside of iteration of players.
Profile:ListenToHopReady() triggers after the last DataStore UpdateAsync call has finished (It’s a yielding method) for said Profile - This is the last non-arbitrary event that we can get in terms of having a profile we just saved be instantly loaded elsewhere swiftly (Instead of receiving a session lock in the process of being removed which can prolong loading time). It has no additional DataStore API cost.
My profile doesn’t save, and I don’t even know why. Code:
ServerScript:
_G.forces = {
[1] = {
Name = "Default Force";
Cost = 0;
Force = 50;
};
[2] = {
Name = "Fast Force";
Cost = 15;
Force = 120;
};
};
local profileServiceTemplate = {
Wins = 0;
Has = _G.forces[1].Name;
Force = _G.forces[1].Force;
Purchased = { _G.forces[1] };
}
local profileService = require(script:WaitForChild("ProfileService"))
local store_Key = ("forcesAndWins")
local profileStore = profileService.GetProfileStore(store_Key, profileServiceTemplate)
local profiles = {}
local dataHandler = require(script:WaitForChild("DataHandler"))
local function playerAdded(plr)
if plr then
script:WaitForChild("leaderstats"):Clone().Parent = plr;
local force = Instance.new("IntValue");
force.Name = "Force";
force.Parent = plr;
local profile = profileStore:LoadProfileAsync(store_Key .. plr.UserId, "ForceLoad")
if (profile ~= nil) then
profile:Reconcile()
profile:ListenToRelease(function()
profile:Release()
plr:Kick("Your data was released");
end)
if (plr:IsDescendantOf(Players)) then
profiles[plr] = profile
dataHandler:setUpDataWithProfile(plr, profile);
else
profile:Release()
end
else
plr:Kick()
end;
end
end
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(playerAdded)(player)
end
Players.PlayerRemoving:Connect(function(plr)
if (profiles[plr]) then
profiles[plr]:Release()
end
end)
Players.PlayerAdded:Connect(playerAdded);
My purchase and data saver handler:
local data = {}
local replicatedStorage = game:GetService("ReplicatedStorage")
local dataTransferEvent = Instance.new("RemoteEvent")
dataTransferEvent.Name = "DataTransfer"
dataTransferEvent.Parent = replicatedStorage.Remotes
local serverEquip = Instance.new("RemoteFunction")
serverEquip.Name = "serverEquip"
serverEquip.Parent = replicatedStorage.Remotes
data.profiles = {}
function data:getProfile(plr)
return self.profiles[plr]
end
function data:setUpDataWithProfile(plr, profile)
self.profiles[plr] = profile
local forces = _G.forces
local playerWins = plr:WaitForChild("leaderstats"):WaitForChild("Wins")
if (not profile.Wins) then
profile.Wins = 700 -- For testing purchases
end
if (not playerWins) then return end
playerWins.Value = profile.Wins
playerWins:GetPropertyChangedSignal("Value"):Connect(function()
-- Wins have been changed, update it in the profile, too!
profile.Wins = playerWins.Value
end)
playerWins.Value = profile.Wins
if (not profile.Has) then
profile.Has = forces[1].Name
end
if (not profile.Purchased) then
profile.Purchased = { forces[1] }
end
local playerForce = plr:WaitForChild("Force")
if (not profile.Force) then
profile.Force = forces[1].Force
end
if (not playerForce) then return end
playerForce.Value = profile.Force
playerForce:GetPropertyChangedSignal("Value"):Connect(function()
profile.Force = playerForce.Value
end)
print(profile.Has, profile.Purchased)
dataTransferEvent:FireClient(plr, profile.Has, profile.Purchased, forces)
end
data.findForceByName = function(t,n)
for _, fTable in pairs(t) do
if fTable.Name == n then
return fTable
end
end
end
data.checkRequirements = function(t,n,playerAmount)
local force = data.findForceByName(t,n)
if (force.Cost <= playerAmount) then
return {true,force.Cost}
end
return nil
end
data.add = function(t,p,n)
local force = data.findForceByName(t,n)
if (force) then
-- Insert it into a table
table.insert(p,force)
return true
end
end
data.serverInvoke = function(player,name)
if (not name or not (typeof(name) == "string")) then return end
local playerProfile = data:getProfile(player)
if (not playerProfile) then return end;
local purchased = playerProfile.Purchased
local forces = _G.forces
local force = data.findForceByName(forces,name)
if (not force) then player:Kick() return end
local isFound = data.findForceByName(purchased,name)
if (not isFound) then
-- Player does not own the force
local leaderstats = player:FindFirstChild("leaderstats")
if (not leaderstats) then return end
local wins = leaderstats:FindFirstChild("Wins")
if (not wins) then return end
local canPurchase = data.checkRequirements(forces,name,wins.Value)
if (canPurchase and canPurchase[1]) then
-- Player can buy this
local cost = canPurchase[2]
local wasSuccessful = data.add(forces,purchased,name)
if (wasSuccessful) then
-- Purchase was successful
-- warn("The purchase was successful")
local forceInt = player:FindFirstChild("Force")
if (not forceInt) then
return;
end
wins.Value -= cost
dataTransferEvent:FireClient(player,playerProfile.Has,playerProfile.Purchased,forces)
end
end
else
-- Player owns the force
local _has = playerProfile.Has
if (_has and _has ~= name) then
-- Player wants to equip a different force
playerProfile.Has = force.Name
local playerForce = player:FindFirstChild("Force")
if (not playerForce) then return end
playerForce.Value = force.Force
dataTransferEvent:FireClient(player,playerProfile.Has,playerProfile.Purchased,forces)
end
end
end;
serverEquip.OnServerInvoke = data.serverInvoke
return data
Would appreciate help
EDIT: Lol. I forgot to add in profile.Data
.