API
Warning
Never yield (use wait()
or asynchronous Roblox API calls) inside listener functions
Notice
Methods with Async
in their name are methods that will yield - just like wait()
ProfileService
ProfileService.ServiceLocked
ProfileService.ServiceLocked [bool]
ProfileStore
methods should not be called after this value is set to false
ProfileService.IssueSignal
ProfileService.IssueSignal [ScriptSignal](error_message [string], profile_store_name [string], profile_key [string])
ProfileService.IssueSignal:Connect(function(error_message, profile_store_name, profile_key)
pcall(function()
AnalyticsService:FireEvent(
"ProfileServiceIssue",
error_message,
profile_store_name,
profile_key
)
end)
end)
ProfileService.CorruptionSignal
ProfileService.CorruptionSignal [ScriptSignal](profile_store_name [string], profile_key [string])
ProfileService.CriticalStateSignal
ProfileService.CriticalStateSignal [ScriptSignal] (is_critical_state [bool])
ProfileService.GetProfileStore()
ProfileService.GetProfileStore(
profile_store_index,
profile_template
) --> [ProfileStore]
-- profile_store_index [string] -- DataStore name
-- OR
-- profile_store_index [table]: -- Allows the developer to define more GlobalDataStore variables
-- {
-- Name = "StoreName", -- [string] -- DataStore name
-- -- Optional arguments:
-- Scope = "StoreScope", -- [string] -- DataStore scope
-- }
-- profile_template [table] -- Profile.Data will default to
-- given table (deep-copy) when no data was saved previously
ProfileStore
objects expose methods for loading / viewing profiles and sending global updates. Equivalent of :GetDataStore() in Roblox DataStoreService API.
Notice
By default, profile_template
is only copied for Profile.Data
for new profiles. Changes made to profile_template
can be applied to Profile.Data
of previously saved profiles by calling Profile:Reconcile(). You can also create your own function to fill in the missing components in Profile.Data
as soon as it is loaded or have nil
exceptions in your personal :Get()
and :Set()
method libraries.
ProfileStore
ProfileStore:LoadProfileAsync()
ProfileStore:LoadProfileAsync(
profile_key,
not_released_handler
) --> [Profile] or nil
-- profile_key [string] -- DataStore key
-- not_released_handler nil or []: -- Defaults to "ForceLoad"
-- [string] "ForceLoad" -- Force loads profile on first call
-- OR
-- [string] "Steal" -- Steals the profile ignoring it's session lock
-- OR
-- [function] (place_id, game_job_id) --> [string] "Repeat", "Cancel", "ForceLoad" or "Steal"
-- place_id [number] or nil
-- game_job_id [string] or nil
nil
for the not_released_handler
argument.
not_released_handler
as a function
argument is called when the profile is
session-locked by a remote Roblox server:
local profile = ProfileStore:LoadProfileAsync(
"Player_2312310",
function(place_id, game_job_id)
-- place_id and game_job_id identify the Roblox server that has
-- this profile currently locked. In rare cases, if the server
-- crashes, the profile will stay locked until ForceLoaded by
-- a new session.
return "Repeat" or "Cancel" or "ForceLoad" or "Steal"
end
)
not_released_handler
must return one of the following values:
return "Repeat"
- ProfileService will repeat the profile loading proccess and may call the release handler againreturn "Cancel"
-:LoadProfileAsync()
will immediately return nilreturn "ForceLoad"
- ProfileService will indefinitely attempt to load the profile. If the profile is session-locked by a remote Roblox server, it will either be released for that remote server or "stolen" (Stealing is necessary for remote servers that are not responding in time and for handling crashed server session-locks).return "Steal"
- The profile will usually be loaded immediately, ignoring an existing remote session lock and applying a session lock for this session."Steal"
can be used to clear dead session locks faster than"ForceLoad"
assuming your code knows that the session lock is dead.
Notice
ProfileService saves profiles to live DataStore keys in Roblox Studio when Roblox API services are enabled. See ProfileStore.Mock if saving to live keys during testing is not desired.
Warning
:LoadProfileAsync()
can return nil
when another remote Roblox server attempts to load the profile at the same time.
This case should be extremely rare and it would be recommended to :Kick() the player if :LoadProfileAsync()
does
not return a Profile
object.
Do not load a profile of the same key again before it is released
Trying to load a profile that has already been session-locked on the same server will result in an error. You may, however, instantly load the profile again after releasing it with Profile:Release()
.
ProfileStore:GlobalUpdateProfileAsync()
ProfileStore:GlobalUpdateProfileAsync(
profile_key,
update_handler
) --> [GlobalUpdates] or nil
-- profile_key [string] -- DataStore key
-- update_handler [function](global_updates) -- This function is
-- called with a GlobalUpdates object
Used to create and manage Active
global updates for a specified Profile
. Can be called on any Roblox server of your game.
Updates should reach the recipient in less than 30 seconds, regardless of whether it was called on the same server the Profile
is session-locked to. See Global Updates for more information.
Example usage of :GlobalUpdateProfileAsync()
:
ProfileStore:GlobalUpdateProfileAsync(
"Player_2312310",
function(global_updates)
global_updates:AddActiveUpdate({
Type = "AdminGift",
Item = "Coins",
Amount = 1000,
})
end
)
Notice
:GlobalUpdateProfileAsync()
will work for profiles that haven't been created (profiles are created when they're
loaded using :LoadProfileAsync()
for the first time)
Yielding inside the update_handler
function will throw an error
Avoid rapid use of ProfileStore:GlobalUpdateProfileAsync()
Excessive use of ProfileStore:GlobalUpdateProfileAsync() can lead to dead session locks and event lost
Profile.Data
(latter is mostly possible only if the Profile
is loaded in the same session as :GlobalUpdateProfileAsync()
is called). This is due to a queue
system that executes every write request for the Profile
every 7 seconds - if this queue grows larger than the BindToClose timeout (approx. 30 seconds), some requests in the queue can be lost after the game shuts down.
ProfileStore:ViewProfileAsync()
ProfileStore:ViewProfileAsync(profile_key, version) --> [Profile] or nil
-- profile_key [string] -- DataStore key
-- version nil or [string] -- DataStore key version
Passing version
argument in mock mode (Or offline mode) will throw an error - Mock versioning is not supported
Attempts to load the latest profile version (or a specified version via the version
argument) from the DataStore without claiming a session lock.
Returns nil
if such version does not exist. Returned Profile
will not auto-save and releasing won't do anything.
Data in the returned Profile
can be changed to create a payload which can be saved via Profile:OverwriteAsync().
:ViewProfileAsync()
is the the prefered way of viewing player data without editing it.
ProfileStore:ProfileVersionQuery()
ProfileStore:ProfileVersionQuery(profile_key, sort_direction, min_date, max_date) --> [ProfileVersionQuery]
-- profile_key [string]
-- sort_direction nil or [Enum.SortDirection] -- Defaults to "Ascending"
-- min_date nil or [DateTime] or [number] (epoch time millis)
-- max_date nil or [DateTime] or [number] (epoch time millis)
ProfileVersionQuery:Next()
. For additional help, check the versioning example in official Roblox documentation. Date definitions are easier with the DateTime (Official documentation) library. User defined day and time will have to be converted to Unix time (Wikipedia) while taking their timezone into account to expect the most precise results, though you can be rough and just set the date and time in the UTC timezone and expect a maximum margin of error of 24 hours for your query results.
Examples of query arguments:
- Pass
nil
forsort_direction
,min_date
andmax_date
to find the oldest available version - Pass
Enum.SortDirection.Descending
forsort_direction
,nil
formin_date
andmax_date
to find the most recent version. - Pass
Enum.SortDirection.Descending
forsort_direction
,nil
formin_date
andDateTime
defining a time before an event (e.g. two days earlier before your game unrightfully stole 1,000,000 rubies from a player) formax_date
to find the most recent version of aProfile
that existed before said event.
Case example: "I lost all of my rubies on August 14th!"
-- Get a ProfileStore object with the same arguments you passed to the
-- ProfileStore that loads player Profiles. It can also just be
-- the very same ProfileStore object:
local ProfileStore = ProfileService.GetProfileStore(store_name, template)
-- If you can't figure out the exact time and timezone the player lost rubies
-- in on the day of August 14th, then your best bet is to try querying
-- UTC August 13th. If the first entry still doesn't have the rubies -
-- try a new query of UTC August 12th and etc.
local max_date = DateTime.fromUniversalTime(2021, 08, 13) -- UTC August 13th, 2021
local query = ProfileStore:ProfileVersionQuery(
"Player_2312310", -- The same profile key that gets passed to :LoadProfileAsync()
Enum.SortDirection.Descending,
nil,
max_date
)
-- Get the first result in the query:
local profile = query:NextAsync()
if profile ~= nil then
profile:ClearGlobalUpdates()
profile:OverwriteAsync() -- This method does the actual rolling back;
-- Don't call this method until you're sure about setting the latest
-- version to a copy of the previous one
print("Rollback success!")
print(profile.Data) -- You'll be able to surf table contents if
-- you're runing this code in studio with access to API services
-- enabled and have expressive output enabled; If the printed
-- data doesn't have the rubies, you'll want to change your
-- query parameters.
else
print("No version to rollback to")
end
Case example: Studying data mutation over time
-- You have ProfileService working in your game. You join
-- the game with your own account and go to https://www.unixtimestamp.com
-- and save the current UNIX timestamp resembling present time.
-- You can then make the game alter your data by giving you
-- currency, items, experience, etc.
local ProfileStore = ProfileService.GetProfileStore(store_name, template)
-- UNIX timestamp you saved:
local min_date = DateTime.fromUnixTimestamp(1628952101)
local print_minutes = 5 -- Print the next 5 minutes of history
local query = ProfileStore:ProfileVersionQuery(
"Player_2312310",
Enum.SortDirection.Ascending,
min_date
)
-- You can now attempt to print out every snapshot of your data saved
-- at an average periodic interval of 30 seconds (ProfileService auto-save)
-- starting from the time you took the UNIX timestamp!
local finish_update_time = min_date.UnixTimestampMillis + (print_minutes * 60000)
print("Fetching ", print_minutes, "minutes of saves:")
local entry_count = 0
while true do
entry_count +=1
local profile = query:NextAsync()
if profile ~= nil then
if profile.KeyInfo.UpdatedTime > finish_update_time then
if entry_count == 1 then
print("No entries found in set time period. (Start timestamp too early)")
else
print("Time period finished.")
end
break
end
print(
"Entry", entry_count, "-",
DateTime.fromUnixTimestampMillis(profile.KeyInfo.UpdatedTime):ToIsoDate()
)
print(profile.Data) -- Printing table for studio expressive output
else
if entry_count == 1 then
print("No entries found in set time period. (Start timestamp too late)")
else
print("No more entries in query.")
end
break
end
end
ProfileStore:WipeProfileAsync()
ProfileStore:WipeProfileAsync(profile_key) --> is_wipe_successful [bool]
-- profile_key [string] -- DataStore key
:WipeProfileAsync()
to erase user data when complying with right of erasure requests. In live Roblox servers :WipeProfileAsync()
must be used on profiles created through ProfileStore.Mock
after Profile:Release()
and it's known that the Profile
will no longer be loaded again.
ProfileStore.Mock
local ProfileTemplate = {}
local GameProfileStore = ProfileService.GetProfileStore(
"PlayerData",
ProfileTemplate
)
local LiveProfile = GameProfileStore:LoadProfileAsync(
"profile_key",
"ForceLoad"
)
local MockProfile = GameProfileStore.Mock:LoadProfileAsync(
"profile_key",
"ForceLoad"
)
print(LiveProfile ~= MockProfile) --> true
-- When done using mock profile on live servers: (Prevent memory leak)
MockProfile:Release()
GameProfileStore.Mock:WipeProfileAsync("profile_key")
-- You don't really have to wipe mock profiles in studio testing
ProfileStore.Mock
is a reflection of methods available in the ProfileStore
object with the exception of profile operations
being performed
on profiles stored on a separate, detached "fake" DataStore that will be forgotten when the game session ends. You may load profiles
of the same key from ProfileStore
and ProfileStore.Mock
in parallel - these will be two different profiles because the regular and mock versions of the same ProfileStore
are completely isolated from each other.
ProfileStore.Mock
is useful for customizing your testing environment in cases when you want to enable Roblox API services in studio, but don't want ProfileService to save to live keys:
local RunService = game:GetService("RunService")
local GameProfileStore = ProfileService.GetProfileStore("PlayerData", ProfileTemplate)
if RunService:IsStudio() == true then
GameProfileStore = GameProfileStore.Mock
end
- Even when Roblox API services are disabled,
ProfileStore
andProfileStore.Mock
will store profiles in separate stores. - It's better to think of
ProfileStore
andProfileStore.Mock
as two differentProfileStore
objects unrelated to each other in any way. - It's possible to create a project that utilizes both live and mock profiles on live servers!
Profile
Profile.Data
Profile.Data [table]
-- Non-strict reference - developer can set this value to a new table reference
Profile.Data
is the primary variable of a Profile object. The developer is free to read and write from
the table while it is automatically saved to the DataStore.
Profile.Data
will no longer be saved after being released remotely or locally via Profile:Release()
.
Profile.MetaData
Profile.MetaData [table] (Read-only) -- Data about the profile itself
Profile.MetaData.ProfileCreateTime [number] (Read-only)
-- os.time() timestamp of profile creation
Profile.MetaData.SessionLoadCount [number] (Read-only)
-- Amount of times the profile was loaded
Profile.MetaData.ActiveSession [table] or nil (Read-only)
-- {place_id, game_job_id} or nil
-- Set to a session link if a Roblox server is currently the
-- owner of this profile; nil if released
Profile.MetaData.MetaTags [table] (Writable)
-- {["tag_name"] = tag_value, ...}
-- Saved and auto-saved just like Profile.Data
Profile.MetaData.MetaTagsLatest [table] (Read-only)
-- the most recent version of MetaData.MetaTags which has
-- been saved to the DataStore during the last auto-save
-- or Profile:Save() call
Profile.MetaData
is a table containing data about the profile itself. Profile.MetaData.MetaTags
is saved
on the same DataStore key together with Profile.Data
.
Profile.MetaTagsUpdated
Profile.MetaTagsUpdated [ScriptSignal] (meta_tags_latest)
This signal fires after every auto-save, after Profile.MetaData.MetaTagsLatest
has been updated with the version that's guaranteed to be saved. MetaTagsUpdated
will fire regardless of whether MetaTagsLatest
changed after update.
MetaTagsUpdated
will also fire after the Profile is saved for the last time and released. Remember that changes to Profile.Data
will not be saved after release - Profile:IsActive()
will return false
if the profile is released.
MetaTagsUpdated
example use can be found in the Developer Products example code.
Profile.RobloxMetaData
Profile.RobloxMetaData [table]
-- Non-strict reference - developer can set this value to a new table reference
Be cautious of very harsh limits for maximum Roblox Metadata size - As of writing this, total table content size cannot exceed 300 characters.
Table that gets saved as Metadata (Official documentation) of a DataStore key belonging to the profile.
The way this table is saved is equivalent to using DataStoreSetOptions:SetMetaData(Profile.RobloxMetaData)
and passing the DataStoreSetOptions
object to a :SetAsync()
call,
except changes will truly get saved on the next auto-update cycle or when the profile is released.
The periodic saving and saving upon releasing behaviour is identical to that of Profile.Data
- After the profile is released further changes to this value will not be saved.
Example:
local profile -- A profile object you loaded
-- Mimicking the Roblox hub example:
profile.RobloxMetaData = {["ExperienceElement"] = "Fire"}
-- You can read from it and write to it at will:
print(profile.RobloxMetaData.ExperienceElement)
profile.RobloxMetaData.ExperienceElement = nil
profile.RobloxMetaData.UserCategory = "Casual"
-- I think setting it to a whole table at profile load would
-- be more safe considering the size limit for meta data
-- is pretty tight:
profile.RobloxMetaData = {
UserCategory = "Casual",
FavoriteColor = {1, 0, 0},
}
Profile.UserIds
Profile.UserIds [table] -- (READ-ONLY) -- {user_id [number], ...}
Profile.KeyInfo
Profile.KeyInfo [DataStoreKeyInfo]
Profile.KeyInfoUpdated
Profile.KeyInfoUpdated [ScriptSignal] (key_info [DataStoreKeyInfo])
Profile.KeyInfo
is updated with a new DataStoreKeyInfo
instance reference after every auto-save or profile release.
Profile.GlobalUpdates
Profile.GlobalUpdates [GlobalUpdates]
This is the GlobalUpdates
object tied to this specific Profile
. It exposes GlobalUpdates
methods for update processing. (See Global Updates for more info)
Profile:IsActive()
Profile:IsActive() --> [bool]
true
while the profile is session-locked and saving of changes to Profile.Data
is guaranteed.
Profile:GetMetaTag()
Profile:GetMetaTag(tag_name) --> value
-- tag_name [string]
Profile.MetaData.MetaTags[tag_name]
. See Profile:SetMetaTag() for more info.
Profile:Reconcile()
Profile:Reconcile() --> nil
Profile.Data
from profile_template
table that was provided when calling ProfileService.GetProfileStore()
. It's often necessary to use :Reconcile()
if you're applying changes to your
profile_template
over the course of your game's development after release.
The right time to call this method can be seen in the basic usage example.
The following function is used in the reconciliation process:
local function ReconcileTable(target, template)
for k, v in pairs(template) do
if type(k) == "string" then -- Only string keys will be reconciled
if target[k] == nil then
if type(v) == "table" then
target[k] = DeepCopyTable(v)
else
target[k] = v
end
elseif type(target[k]) == "table" and type(v) == "table" then
ReconcileTable(target[k], v)
end
end
end
end
Profile:ListenToRelease()
Profile:ListenToRelease(listener) --> [ScriptConnection] (place_id / nil, game_job_id / nil)
-- listener [function] (place_id / nil, game_job_id / nil)
Profile:ListenToRelease()
will be called when
the profile is released remotely (Being "ForceLoad"
'ed on a remote server) or
locally (Profile:Release()
). In common practice, the profile will rarely be released before
the player leaves the game so it's recommended to simply :Kick() the Player when this happens.
Warning
After Profile:ListenToRelease()
is triggered, it is too late to change Profile.Data
for the final time.
As long as the profile is active (Profile:IsActive()
== true
), you should store all profile related data
immediately after it becomes available. An item trading operation between two profiles must happen without
any yielding after it is confirmed that both profiles are active.
Profile:Release()
Profile:Release()
Profile
object. Profile data will be immediately saved for the last time.
Profile:ListenToHopReady()
Profile:ListenToHopReady(listener) --> [ScriptConnection] ()
-- listener [function] ()
:ListenToHopReady()
.
A listener passed to :ListenToHopReady()
will be executed after the releasing UpdateAsync call finishes.
:ListenToHopReady()
will usually call the listener in around a second, but may ocassionally take up to 7
seconds when a profile is released next to an auto-update interval (regular usage scenario - rapid
loading / releasing of the same profile key may yield different results).
Example use:
local TeleportService = game:GetService("TeleportService")
local profile, player, place_id
profile:Release()
profile:ListenToHopReady(function()
TeleportService:TeleportAsync(place_id, {player})
end)
In short, Profile:ListenToRelease()
and Profile:ListenToHopReady()
will both execute the listener function after release, but Profile:ListenToHopReady()
will
additionally wait until the session lock is removed from the Profile
.
Profile:AddUserId()
Profile:AddUserId(user_id)
-- user_id [number]
UserId
with the profile. Multiple users can be associated with a single profile by calling this method for each individual UserId
.
The primary use of this method is to comply with GDPR (The right to erasure). More information in official documentation.
The right time to call this method can be seen in the basic usage example.
Profile:RemoveUserId()
Profile:RemoveUserId(user_id)
-- user_id [number]
UserId
with the profile if it was initially associated.
Profile:Identify()
Profile:Identify() --> [string]
-- Example return: "[Store:"GameData";Scope:"Live";Key:"Player_2312310"]"
Returns a string containing DataStore name, scope and key; Used for debugging;
Profile:SetMetaTag()
Profile:SetMetaTag(tag_name, value)
-- tag_name [string]
-- value -- Any value supported by DataStore
Profile.MetaData.MetaTags[tag_name] = value
. Use for tagging your profile
with information about itself such as:
profile:SetMetaTag("DataVersion", 1)
to let your game code know whetherProfile.Data
needs to be converted after massive changes to the game.- Anything set through
profile:SetMetaTag(tag_name, value)
will be available throughProfile.MetaData.MetaTagsLatest[tag_name]
after an auto-save or a:Save()
call -Profile.MetaData.MetaTagsLatest
is a version ofProfile.MetaData.MetaTags
that has been successfully saved to the DataStore.
Notice
You can use Profile.MetaData.MetaTagsLatest
for product purchase confirmation (By storing receiptInfo.PurchaseId
values inside Profile.MetaData.MetaTags
and waiting for them to appear in Profile.MetaData.MetaTagsLatest
). Don't forget to clear really old PurchaseId
's to stay under DataStore limits.
Profile:Save()
Profile:Save() -- Call to quickly progress GlobalUpdates
-- state or to speed up save validation processes
-- (Does not yield)
Profile:Save()
to quickly progress GlobalUpdates
state or to speed up the propagation of
Profile.MetaData.MetaTags
changes to Profile.MetaData.MetaTagsLatest
.
Profile:Save()
should not be called for saving Profile.Data
or Profile.MetaData.MetaTags
-
this is already done for you automatically.
Warning
Calling Profile:Save()
when the Profile
is released will throw an error.
You can check Profile:IsActive()
before using this method.
Profile:ClearGlobalUpdates()
Profile:ClearGlobalUpdates()
Only works for profiles loaded through :ViewProfileAsync() or :ProfileVersionQuery()
Clears all global update data (active or locked) for a profile payload. It may be desirable to clear potential "residue" global updates (e.g. pending gifts) which were existing in a snapshot which is being used to recover player data through :ProfileVersionQuery().
Profile:OverwriteAsync()
Profile:OverwriteAsync()
Only works for profiles loaded through :ViewProfileAsync() or :ProfileVersionQuery()
Only use for rollback payloads (Setting latest version to a copy of a previous version)!
Using this method for editing latest player data when the player is in-game can lead to several minutes of lost progress - it should be replaced by :LoadProfileAsync() which will wait for the next live profile auto-save if the player is in-game, allowing the remote server to release the profile and save latest data.
Pushes the Profile
payload to the DataStore (saves the profile) and releases the session lock for the profile.
Global Updates
Global updates is a powerful feature of ProfileService, used for sending information to a desired player profile across servers, within the server or to a player profile that is not currently active in any Roblox server (Kind of like MessagingService, but slower and doesn't require the recipient to be active). The primary intended use of global updates is to support sending gifts among players, or giving items to players through a custom admin tool. The benefit of using global updates is it's API simplicity (This is as simple as it gets, sorry 😂) and the fact that global updates are pulled from the DataStore whenever the profile is auto-saved at no additional expense of more DataStore calls!
Global updates can be Active
, Locked
and Cleared
:
- Whenever a global update is created, it will be
Active
by default Active
updates can be changed or cleared within a:GlobalUpdateProfileAsync()
call- Normally, when the profile is active on a Roblox server, you should always progress all
Active
updates to theLocked
state Locked
updates can no longer be changed or cleared within a:GlobalUpdateProfileAsync()
callLocked
updates are ready to be processed (e.g., add gift to player inventory) and imediatelyLocked
by calling:LockActiveUpdate(update_id)
Cleared
updates will immediately disappear from the profile forever
Always available
GlobalUpdates:GetActiveUpdates()
GlobalUpdates:GetActiveUpdates() --> [table] { {update_id, update_data}, ...}
Profile
is loaded to scan and progress any pending Active
updates to Locked
state:
for _, update in ipairs(profile.GlobalUpdates:GetActiveUpdates()) do
profile.GlobalUpdates:LockActiveUpdate(update[1])
end
GlobalUpdates:GetLockedUpdates()
GlobalUpdates:GetLockedUpdates() --> [table] { {update_id, update_data}, ...}
Profile
is loaded to scan and progress any pending Locked
updates to Cleared
state:
for _, update in ipairs(profile.GlobalUpdates:GetLockedUpdates()) do
local update_id = update[1]
local update_data = update[2]
if update_data.Type == "AdminGift" and update_data.Item == "Coins" then
profile.Data.Coins = profile.Data.Coins + update_data.Amount
end
profile.GlobalUpdates:ClearLockedUpdate(update_id)
end
Only when accessed from Profile.GlobalUpdates
GlobalUpdates:ListenToNewActiveUpdate()
GlobalUpdates:ListenToNewActiveUpdate(listener) --> [ScriptConnection]
-- listener [function](update_id, update_data)
Active
updates to Locked
state:
profile.GlobalUpdates:ListenToNewActiveUpdate(function(update_id, update_data)
profile.GlobalUpdates:LockActiveUpdate(update_id)
end)
GlobalUpdates:ListenToNewLockedUpdate()
GlobalUpdates:ListenToNewLockedUpdate(listener) --> [ScriptConnection]
-- listener [function](update_id, update_data)
-- Must always call GlobalUpdates:ClearLockedUpdate(update_id)
-- after processing the locked update.
Locked
update via GlobalUpdates:ListenToNewLockedUpdate()
, the update is
ready to be proccessed and immediately locked:
profile.GlobalUpdates:ListenToNewLockedUpdate(function(update_id, update_data)
if update_data.Type == "AdminGift" and update_data.Item == "Coins" then
profile.Data.Coins = profile.Data.Coins + update_data.Amount
end
profile.GlobalUpdates:ClearLockedUpdate(update_id)
end)
GlobalUpdates:LockActiveUpdate()
GlobalUpdates:LockActiveUpdate(update_id)
-- update_id [number] -- Id of an existing global update
Active
update into a Locked
update. Will invoke GlobalUpdates:ListenToNewLockedUpdate()
after
an auto-save (less than 30 seconds) or Profile:Save()
.
Warning
Calling GlobalUpdates:LockActiveUpdate()
when the Profile
is released will throw an error.
You can check Profile:IsActive()
before using this method. ProfileService guarantees that the
Profile
will be active when GlobalUpdates:ListenToNewActiveUpdate()
listeners are triggered.
GlobalUpdates:ClearLockedUpdate()
GlobalUpdates:ClearLockedUpdate(update_id)
-- update_id [number] -- Id of an existing global update
Locked
update completely from the profile.
Warning
Calling GlobalUpdates:ClearLockedUpdate()
when the Profile
is released will throw an error.
You can check Profile:IsActive()
before using this method. ProfileService guarantees that the
Profile
will be active when GlobalUpdates:ListenToNewLockedUpdate()
listeners are triggered.
Available inside update_handler
during a ProfileStore:GlobalUpdateProfileAsync()
call
GlobalUpdates:AddActiveUpdate()
GlobalUpdates:AddActiveUpdate(update_data)
-- update_data [table] -- Your custom global update data
Active
update to the profile.
GlobalUpdates:ChangeActiveUpdate()
GlobalUpdates:ChangeActiveUpdate(update_id, update_data)
-- update_id [number] -- Id of an existing global update
-- update_data [table] -- New data that replaces previously set update_data
Active
updates can be used for stacking player gifts, particularly when
lots of players can be sending lots of gifts to a Youtube celebrity so the Profile
would not
exceed the DataStore data limit.
GlobalUpdates:ClearActiveUpdate()
GlobalUpdates:ClearActiveUpdate(update_id)
-- update_id [number] -- Id of an existing global update
Active
update from the profile completely.