Ahhh yes, thats when I updated I left the old one in there, wow will remove that right now!
Hey, I know this doesn’t have anything to do with the module really but I was wondering how did you setup the website for your documentation and stuff. I see the same thing being done with other modules and I was wondering how did they do it.
Is the kicking of the player necessary on ListenToRelease? If you use ListenToHopReady to use teleport service, the player gets kicked immediately when you release the profile. I just want to make sure that removing or delaying the kick on ListenToRelease doesn’t compromise security versus dupe or what not.
Kicking is for when the profile is acessed externally - if the profile is active before you call release in the same session you can create an exception and not kick the player.
In my own universe game I’ll probably teleport players to the hub place when their profile is ForceLoaded / Stolen externally.
Should there be any concerns with adjusting UpdateAsync to instead use another place to save data at through HttpService such as Firestore?
I hadn’t directly looked into how frequently ProfileService updates the saved data that could risk hitting a limit but I do like to continue using ProfileService for its session locking and keeping the latest version safely updated at all times. I don’t see ProfileService using GetRequestBudgetForRequestType to throttle itself so I would assume it’s very light in how much it submits an update.
ProfileService needs enough auto-save frequency to comply with external ForceLoad requests (Until they try to steal the profile) and notify the session about the release immediately after the last save.
I don’t see a problem with replacing the UpdateAsync calls with custom getters.
For mock profiles all I have to do is
local RunService = game:GetService("RunService")
local GameProfileStore = ProfileService.GetProfileStore("PlayerData", ProfileTemplate)
if RunService:IsStudio() == true then
GameProfileStore = GameProfileStore.Mock
end
right?
or is there another step I have to take to make it so the profile is mock so when testing in studio the data doesn’t save
Is there a method that will wait till the profile.Data is loaded? For example, sometimes client loads fast and the profile.Data hasn’t been created yet so Client stuff do not work sometimes.
I used ReplicaService and waited for the replica of the class for the data to be created.
My code looks like this on the client:
-- wait for replicas to be created, then create player data
ReplicaController.ReplicaOfClassCreated(DATA_CLASS_TOKEN, function(replica)
-- get player object
local replicaPlayer = replica.Tags.Player
-- create and store data object
local dataObject = Data.new(replicaPlayer, replica)
data[replicaPlayer] = dataObject
-- handle memory cleanup upon deletion
replica:AddCleanupTask(function()
dataObject:Destroy()
data[replicaPlayer] = nil
end)
-- handle and clear async binds
local binds = asyncBinds[replicaPlayer]
if binds then
-- call functions
for _, func in ipairs(binds) do
func()
end
-- clear binds
asyncBinds[replicaPlayer] = nil
end
end)
Note that Data is a custom Class that handles a specific player’s data, and loads the data by supplying a Player
and a Replica
into the constructor.
The important thing here, is where I say “handle and clear async binds”. The reason this is important is because I have a function on the client which is:
--[[
Method: waitForDataAsync
Waits for data to exist, then calls the function, will throw if the supplied player does not exist
@param {function} func: function to call when data exists, typically something containing .getValue() or .bindToChange()
@param {Player? or String?} otherPlayer: name or object of another player to get the data from, nil will default to the local player
]]
function DataCache.waitForDataAsync(func, otherPlayer) --> throws if supplied player does not exist
-- get player object
otherPlayer = otherPlayer or Player
if type(otherPlayer) == "string" then
otherPlayer = Players[otherPlayer]
end
-- player does not exist: throw an error
assert(otherPlayer ~= nil, "Supplied player does not exist")
-- asynchronously wait for the player data to exist
-- if it exists,
xpcall(function(...)
-- attempt to error
getDataObject(...)
-- no error means we can continue
func()
end, function(err)
-- error means data does not exist, and we need to wait for it to exist, then call the function
-- this is done by storing the function into a table, of which all the functions in it will be called when the data is created
local binds = asyncBinds[otherPlayer]
if not binds then
binds = {}
asyncBinds[otherPlayer] = binds
end
binds[#binds+1] = func
end, otherPlayer)
end
Basically, it will call the supplied function once the supplied player’s data loads. It will call the supplied function if the data already exists. I think you can make something like this given the code samples I have shown, but if you need any help let me know.
" Updating the template will not include missing template values in existing player profiles! ".
How would I be able to make updates to already existing player profiles when I want to add for example a new currency?
Hey,
use profile:Reconcile() in your PlayerAdded function.
Thank you man you saved my life
Hey, I was wondering how should I go about making a global profile.
Idea is to make Global Stat Tracker.
Hey watch video from @okeanskiy about Global Updates or make topic in #help-and-feedback:scripting-support.
Hey! So I’ve been making a inventory system with ProfileService, and essentially I have the empty table called: “Inventory” under data, all of the data saving works perfectly. But I can’t figure out how to add values to the table. For example:
local testTable = {
-- Already called variables.
Blue = 1
Red = 36
}
-- Both of these already exist.
print(testTable.Blue)
print(testTable.Red)
-- This doesn't exist, but when its called it'll create a value.
testTable.Yellow = 12
print(testTable.Yellow)
But! Whenever I try this with profileservice, like this:
local DataManager = require(game.ReplicatedStorage.DataManager)
local Items = game.ReplicatedStorage.Items
local function onItemAdded(obj)
obj.Main.ProximityPrompt.Triggered:Connect(function(plr)
local Data = DataManager:Get(plr)
if Data then
print(Data)
Data.Inventory[obj.Name] += 1
end
end)
end
I end up getting an error:
IGNORE “Wheat”, that was used for testing earlier.
Anyway, the main goal is to be able to pickup a box in the workspace that has a proximity prompt. When the proximity prompt is triggered, you’ll be given the time. But for some reason, I’m not able to call an entirely new value?
Can you also show your DataManager Module Script?
Yes, the data manager works currently.
local Players = game:GetService("Players")
local ProfileService = require(game.ReplicatedStorage.ProfileService)
local ProfileStore = ProfileService.GetProfileStore(
"Player",
{
Cash = 0;
LoginTimes = 0;
Avatar = {};
Inventory = {};
}
)
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(Players) then
Profiles[player] = profile
else
profile:Release()
end
else
player:Kick()
end
end
local function onPlayerRemoving(player)
local profile = Profiles[player]
if profile then
profile:Release()
end
end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
local DataManager = {}
function DataManager:Get(player)
local profile = Profiles[player]
if profile then
return profile.Data
end
end
return DataManager
I just noticed something, “avatar” doesn’t appear whenever I call for the data?
You are missing profile:Reconcile()
Okay, I think I figured it out. Is there any way I can wipe all of the stuff inside of my profile? Its full of a lot of random stuff when I was adding the reconcile