While this module is frikin amazing I have encountered on one of the issues which sorta gave me anxiety. I really appreciate your work but sometimes the ListenToHopReady is unreliable, most of the times testers have lost data, while I removed it the the data loss vanished completely at the cost of loading into battle place being longer.
You don’t necessarily need it, just call some function you’d wanna connect to a profile update where you’re updating the data.
What is “Profile Update”? I’ve searched the Profile Service API but couldn’t find the connection function for what you said so if you’re kind enough can you tell me what exactly this is?
Is there support for easily setting this up for external data stores ?
It’s not in the API of ProfileService. You have to create your own function that updates the data of your profile and your own signal that you fire in said function.
Example:
function setData(profile, key, value)
local oldValue = profile.Data[key]
--Checks if type of newValue is the same as oldValue for safety such as adding currency but you put in a string as an argument when the currency is an integer.
if typeof(value) ~= typeof(oldValue) then return end
profile.Data[key] = value
--Assume that you have a custom signal and fire it
dataChangedSignal:Fire(whateverYouWant)
end
ProfileService has been a huge help but one thing I’m really used to with datastores is having folder instances to store player data rather than a table because I just think it’s way easier. Is this possible to do with ProfileService in a safe way where I wouldn’t be contributing towards data loss?
When you get profiles in your script you can just make instances with it with a for loop
ListenToHopReady does not change any data and it listens to a profile being released as well so…
They already have some sort of “messaging service”, its called global updates
is there a way to do backups ? or rolebacks
also i love this module,
but im supper confused in how to store the players data i followed the tutorials on top
i am working on a rpg game so players gonna have tons of items
and i store the item id and nescessary stats and estimating with allot margin that a single non stackable item slot would be around 1000 Bytes or 0.001 MB if my math was not wrong if i reserverd 50% of the key size i still have arround 2 Trillion slots to save potentialy 2 000 000 000
but when i test this in practice i only get to 13 000 items and it exceeds the 4MB max save limit of roblox in a key am i doing somthing wrong here i thought i could store waaaaay more then this ?
any ideas or fixes i could do to increase max items i only store needed data
like
playerData = {
loginTimes = 0,
playTime = 0,
deaths = 0,
kills = 0,
itemsLooted = 0,
rank = {},
memberShip = {},
penalty = {},
flags = {},
quests = {},
coins = math.random(1,100000000),
gems = 0,
titles = {1},
equipedTitle = 1,
companion = {},
config = {["renderDistance"]=5},
-- stats {lvl,xp}
lvl_main = {1,0},
lvl_attack = {1,0},
lvl_strength = {1,0},
lvl_defense = {1,0},
lvl_ranged = {1,0},
lvl_prayer ={1,0},
lvl_magic = {1,0},
lvl_vitality = {1,0},
lvl_crafting = {1,0},
lvl_mining = {1,0},
lvl_smithing = {1,0},
lvl_fishing = {1,0},
lvl_cooking = {1,0},
lvl_firemaking = {1,0},
lvl_woodcutting = {1,0},
lvl_runecrafting = {1,0},
lvl_dungeoneering = {1,0},
lvl_fletching = {1,0},
lvl_agility = {1,0},
lvl_herblore = {1,0},
lvl_thieving = {1,0},
lvl_slayer = {1,0},
lvl_farming = {1,0},
lvl_construction = {1,0},
lvl_hunter = {1,0},
lvl_summoning = {1,0},
--equipment order = id , type , amount/nil , float , equiped , args
-- 1= 1,helmet,nil(nostackable),0.123
-- 2= 1,recource,50(stackable),nil(nofloat)
equipment = {
[1]={1,"helmet",nil,math.random(0,1000000),true},
[2]={1,"chestplate",nil,math.random(0,1000000),true},
[3]={1,"pants",nil,math.random(0,1000000),true},
[4]={1,"boots",nil,math.random(0,1000000),true},
[5]={1,"sword",nil,math.random(0,1000000),false},
[6]={1,"pickaxe",nil,math.random(0,1000000),nil,"$m:10,$a:1"},
[7]={1,"log",50,nil},
[8]={1,"cape",nil,math.random(0,1000000),nil,"$m:1"},
[9]={1,"helmet",nil,math.random(0,1000000),false,"$m:5,$a:1"},
[10]={1,"chestplate",nil,math.random(0,1000000),false,"$m:5"},
[11]={1,"pants",nil,math.random(0,1000000),false,"$m:5"},
[12]={1,"boots",nil,math.random(0,1000000),false,"$m:5"},
[13]={1,"helmet",nil,math.random(0,1000000),false,"$m:6,$a:2"},
[14]={1,"chestplate",nil,math.random(0,1000000),false,"$m:6"},
[15]={1,"pants",nil,math.random(0,1000000),false,"$m:6"},
[16]={1,"boots",nil,math.random(0,1000000),false,"$m:6"},
[17]={1,"helmet",nil,math.random(0,1000000),false,"$m:7,$a:3"},
[18]={1,"chestplate",nil,math.random(0,1000000),false,"$m:7"},
[19]={1,"pants",nil,math.random(0,1000000),false,"$m:7"},
[20]={1,"boots",nil,math.random(0,1000000),false,"$m:7"},
[21]={1,"helmet",nil,math.random(0,1000000),false,"$m:8,$a:4"},
[22]={1,"chestplate",nil,math.random(0,1000000),false,"$m:8"},
[23]={1,"pants",nil,math.random(0,1000000),false,"$m:8"},
[24]={1,"boots",nil,math.random(0,1000000),false,"$m:8"},
[25]={1,"helmet",nil,math.random(0,1000000),false,"$m:9,$a:5"},
[26]={1,"chestplate",nil,math.random(0,1000000),false,"$m:9"},
[27]={1,"pants",nil,math.random(0,1000000),false,"$m:9"},
[28]={1,"boots",nil,math.random(0,1000000),false,"$m:9"},
[29]={1,"helmet",nil,math.random(0,1000000),false,"$m:10,$a:6"},
[30]={1,"chestplate",nil,math.random(0,1000000),false,"$m:10"},
[31]={1,"pants",nil,math.random(0,1000000),false,"$m:10"},
[32]={1,"boots",nil,math.random(0,1000000),false,"$m:10"},
[33]={1,"helmet",nil,math.random(0,1000000),false,"$m:11,$a:7"},
[34]={1,"chestplate",nil,math.random(0,1000000),false,"$m:11"},
[35]={1,"pants",nil,math.random(0,1000000),false,"$m:11"},
[36]={1,"boots",nil,math.random(0,1000000),false,"$m:11"},
[37]={1,"helmet",nil,math.random(0,1000000),false,"$m:12,$a:8"},
[38]={1,"chestplate",nil,math.random(0,1000000),false,"$m:12"},
[39]={1,"pants",nil,math.random(0,1000000),false,"$m:12"},
[40]={1,"boots",nil,math.random(0,1000000),false,"$m:12"},
[41]={1,"helmet",nil,math.random(0,1000000),false,"$m:13,$a:9"},
[42]={1,"chestplate",nil,math.random(0,1000000),false,"$m:13"},
[43]={1,"pants",nil,math.random(0,1000000),false,"$m:13"},
[44]={1,"boots",nil,math.random(0,1000000),false,"$m:13"},
[45]={1,"helmet",nil,math.random(0,1000000),false,"$m:1,$a:10"},
[46]={2,"cape",nil,math.random(0,1000000),false},
[47]={3,"cape",nil,math.random(0,1000000),false},
[48]={4,"cape",nil,math.random(0,1000000),false},
[49]={5,"cape",nil,math.random(0,1000000),false},
[50]={6,"cape",nil,math.random(0,1000000),false},
[51]={7,"cape",nil,math.random(0,1000000),false},
[52]={8,"cape",nil,math.random(0,1000000),false},
}
}
i just wanna know if i can do anithing to get atleast 1 million item slots somehow or not
i mean there are many simulator games with inf inventory space (i know its not unstackables) is there a way ot do i just have to live with the 13 k and just optimize it more ?
ps i know stackables are only one slot with an ammount number i can’t do that for equipment as there unique with a random FLOAT and possible unusual or material variant
sorry for long messy post
I can highly recommend this module to everyone. It takes on a difficult task and solves it without any problems. Not even the examples of Roblox to Datastores work as reliably as this module.
I will definitely use it for all my future games.
Thank you @loleris for creating this exiting module!
Hello I have a question. When ever I add a new value I want to save in my profilestore it never adds it to the player’s data when returning it.
local ProfileStore = ProfileService.GetProfileStore(
"PlayerData.1",
-- The data this store saves
{
Cash = 0,
Cars = {}
}
)
I added a new value called Cash and when I print the player’s data returned
it prints this
{
Cars = {}
}
it does not list the Cash
How would I fix this.
You have to use reconcile on it.
I have multiple Profiles in my experience, however when I teleport, it releases the Profile, resulting in the primary
Profile:ListenToRelease()
to trigger. I want to use
Profile:ListenToHopReady()
to make sure that data doesn’t take more than 7 seconds to load when hopping between places.
Is it ok if I remove ListenToRelease from the PlayerAdded function?
local ProfileService = require(game:GetService("ServerScriptService").ProfileService)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Name = "Characters"
local DefaultProfile = {}
local ProfileStore = ProfileService.GetProfileStore("OwnedCharacters", DefaultProfile)
local Profiles = {}
Players.PlayerAdded:Connect(function(Player)
local Profile = ProfileStore:LoadProfileAsync("Player_"..Player.UserId)
if Profile then
Profile:AddUserId(Player.UserId)
Profile:Reconcile()
Profile:ListenToRelease(function()
Profile[Player] = nil
Player:Kick("/n Error Code 1: /n /n Data loaded from another server. Please close Roblox and try again.")
end)
if Player:IsDescendantOf(Players) then
Profiles[Player] = Profile
local Data = Instance.new("Folder")
Data.Name = Name
Data.Parent = Player
local function Save()
print("Saving")
local DataForProfile = {}
for _, Character in pairs(Data:GetChildren()) do
local Skins = {}
for Skin, Value in pairs(Character:GetAttributes()) do
Skins[Skin] = Value
end
DataForProfile[Character.Name] = Skins
end
print("Ready to upload")
Profile.Data = DataForProfile
print("Saved")
end
for DataType, Value in pairs(Profile.Data) do
local Character = Instance.new("BinaryStringValue")
Character.Name = DataType
Character.Parent = Data
for CharacterSkin, Value in pairs(Value) do
Character:SetAttribute(CharacterSkin, Value)
end
Character.AttributeChanged:Connect(Save)
end
Data.ChildAdded:Connect(Save)
end
end
end)
ReplicatedStorage.Teleporting.Event:Connect(function(Player)
local Profile = Profiles[Player]
if Profile then
Profile:Release()
Profile:ListenToHopReady(function()
local Released = Player:WaitForChild("Released")
local Value = Instance.new("BinaryStringValue")
Value.Name = Name
Value.Parent = Released
end)
end
end)
Players.PlayerRemoving:Connect(function(Player)
local Profile = Profiles[Player]
if Profile then
Profile:Release()
end
end)
Hello! i was wondering what is wrong with my script? im trying to save the givewarn function but nothing is working.
The datamanager
local Players = game:GetService("Players")
local ProfileService = require(game.ReplicatedStorage.ProfileService)
local BindableEvent = game.ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("SaidBadWord")
local ProfileStore = ProfileService.GetProfileStore(
"Player",
{
Warnings = 0;
Timemute = 0;
}
)
local Profiles = {}
local function GiveWarn(player, amount)
print("Working")
local data = Profiles[player]
if data ~= nil then
player.Values.Warnings.Value = player.Values.Warnings.Value + 1
else print(player .. ' was not found.') end
end
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
GiveWarn()
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)
BindableEvent.Event:Connect(GiveWarn(1))
local DataManager = {}
function DataManager:Get(player)
local profile = Profiles[player]
if Profiles[player] then
return profile.Data
end
end
return DataManager
My output
10:55:40.828 [ProfileService]: Roblox API services available - data will be saved - Server - ProfileService:2307
10:55:41.280 Working - Server - DataManager:16
10:55:41.280 ReplicatedStorage.DataManager:20: attempt to concatenate nil with string
The else line here will error if player is nil because you can’t concatenate a nil value with a string so I recommend replacing the print function with this
print("data was not found.")
Then, you run the GiveWarn function argument without passing any arguments, causing an error on the print function as i said earlier
Hi! it fixed my errors but now im having a issue by it not saving the value
You should update the code sample:
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(PlayerAdded)(player)
end
→
for _, player in ipairs(Players:GetPlayers()) do
task.spawn(PlayerAdded, player)
end