I’m not quite sure I understand what you mean by structures, do you mean builds that a player did? i.e A house built with f3x?
Yes. Like a custom building system with blueprints and the blueprints saving with their position and extra properties like colors or wood types, etc.
The module creates a datastore queue warning, because it makes a GetAsync request to check if it can save in studio. That makes sense, but I had to remove this part in the module. Is there not any other way to check if you can save in studio?
(Wrong reply)
I mean, like any DataStore module you can technically do that by making your own methods.
A function like that isn’t baked in ProfileService for obvious reasons, it’s up to the developer to add what they want, the only thing ProfileService provides you with is a nice way to save data for players, but to save anything other than normal types such as a string, arrays, numbers etc you will have to make your own method.
You can make a method like […]:SaveModelBlueprint(model: Model)
which transforms it into an array of arrays. It’s complicated but look at this post: How do i create a saving system for parts using DataStores? - #17 by OnlyJaycbee
Thanks for the information, but i do have one more question. Since the datastore limits got increased, can i just save them in an array instead of using compression or json conversion? Id much rather make a structures table in the default profile and table.insert when a player places their structure rather than compression, decompression, etc. Would this work well with it?
Hey, I’m glad my previous message helped you.
As for the Datastore limit, it’s 4MB per key (aka per player). It’s hard to tell whether or not it’ll be enough, I’m not sure how big the builds will be and how much data you will be saving. I haven’t really thought of Data limits ever.
Say you are saving something like this (NOTE: I can’t find the actual byte size):
export type data = {
Color: string,
Material: string,
Size: string,
CFrame: string,
}
If you do this to every part, it’ll stack up pretty quickly I assume.
I strongly recommend making your own module, or like I said before, a Method such as […]:SaveModelBlueprint(model: Model) to save the data. If you make everything in a ModuleScript it’ll be a flawless transition
Here are some tips for compression which I advise you to look at: This how do i extremely reduced data packet size
Ideas:
local Blueprinter = {}
export type Blueprint = {
Data: { [string]: { [string]: { any } | string } },
Date: number,
Creator: string,
}
local function Compress(blueprint: Blueprint): Blueprint
end
local function Decompress(blueprint: Blueprint): Blueprint
end
function Blueprinter:ConstructBlueprint(parent: any): Blueprint -- Makes a blueprint of your model
--TODO: Make the layout of the blueprint, example:
--[[
{
["Model1"] = {
["Part1"] = {
Color = "1,1,1",
Material = "Plastic",
Size = "1,1,1",
CFrame = "...",
type = "Part",
}
type = "Model",
}
}
]]--
local layout = {}
return Compress(layout)
end
function Blueprinter:ConstructModel(data: { any })
end
function Blueprinter:ReadBlueprint(blueprint: Blueprint) -- Converts that blueprint in an actual model
local layout = Decompress(blueprint)
return self:ConstructModel(layout)
end
return Blueprinter
Hello, Is it possible to convert the datastore2 module I’m using to profileservice without losing data?
Yes. In the template, you can have a variable called PreviousDataLoaded which should be set to false. When the profile is loaded, if the PreviousDataLoaded variable is false, you check to see if there is old data. If there is old data, then add it to the profile. Then you set PreviousDataLoaded to true (even if there was no previous data). This has worked for me in the past without any issues.
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ReplicaService = require(ServerScriptService.ReplicaService)
local ProfileService = require(ServerScriptService.ProfileService)
local ProfileTemplate = {
CurrentCar = "",
Vehicles = {},
}
for _, VH in pairs(game:GetService("ReplicatedStorage").Vehicles:GetChildren()) do
local CarData = {
VehicleName = VH.Name,
aOwnedV = false,
Primary = tostring(VH.Body:FindFirstChild("PrimaryColor").Color) or "1, 1, 1",
RimColor = "1, 1, 1",
}
table.insert(ProfileTemplate.Vehicles, CarData)
end
local ReplicaTestServer = {
}
local plrCars = {}
local UpdateEvent = ReplicatedStorage.Events.UpdateCustomization
local PlayerProfileClassToken = ReplicaService.NewClassToken("PlayerProfile")
local GameProfileStore = ProfileService.GetProfileStore(
"PlayerData",
ProfileTemplate
)
local PlayerProfile -- PlayerProfile object
local PlayerProfiles = {} -- [player] = {Profile = profile, Replica = replica}
local LastPayout = os.clock()
local function LoadData(player, profile)
local CurrentCar = Instance.new("StringValue", player)
CurrentCar.Name = "CurrentCar"
CurrentCar.Value = profile.Data.CurrentCar
local folder = Instance.new("Folder", player)
folder.Name = "Vehicles"
for i, v in pairs(game:GetService("ReplicatedStorage").Vehicles:GetChildren()) do
local Cars = Instance.new("BoolValue", folder)
Cars.Name = v.Name
for o, a in pairs(profile.Data.Vehicles) do
if a.VehicleName == v.Name then
for q, e in pairs(a) do
Cars:SetAttribute(q, e)
end
end
end
end
end
local function PlayerAdded(player)
local profile = GameProfileStore:LoadProfileAsync(
"#Game" .. player.UserId,
"ForceLoad"
)
if profile ~= nil then
profile:AddUserId(player.UserId)
profile:Reconcile()
profile:ListenToRelease(function()
PlayerProfiles[player].Replica:Destroy()
PlayerProfiles[player] = nil
player:Kick()
end)
if player:IsDescendantOf(Players) == true then
local player_profile = {
Profile = profile,
Replica = ReplicaService.NewReplica({
ClassToken = PlayerProfileClassToken,
Tags = {Player = player},
Data = profile.Data,
Replication = "All",
}),
_player = player,
}
setmetatable(player_profile, PlayerProfile)
PlayerProfiles[player] = player_profile
LoadData(player, profile)
else
profile:Release()
end
else
player:Kick()
end
end
----- Public functions -----
-- PlayerProfile object:
PlayerProfile = {
--[[
_player = player,
--]]
}
PlayerProfile.__index = PlayerProfile
function PlayerProfile:IsActive() --> is_active
return PlayerProfiles[self._player] ~= nil
end
----- Initialize -----
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(PlayerAdded)(player)
end
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(function(player)
local player_profile = PlayerProfiles[player]
if player_profile ~= nil then
player_profile.Profile:Release()
end
end)
i want it when i add new car the old cars data stays it does that but it dont add the data for the new cars, im using the boolvalue and the data is the attributes
Hey, is it possible to make a guild system using profileservice? Since it does session locking and stuff it looks hard to share data across multiple servers, except for using the Global Updates
API. I was thinking of making a new profile for every guild created and store it the usual way, but if I want to edit the info such as the players in it, or make a ranking system within the guild, I would need to access and modify data on multiple servers and this could happen at the same time. Is it safe to do it with Profileservice and will using the Global Updates
API work?
Please let me know if someone has done something similar or can give me the basic ways to implement it. Thanks
How would you use ProfileService for things other than players?
sorry for bumping, but yes how would i go on about saving things other than players, like cars? honestly this is a good dataservice. and have been using for alot of my games but. one thing i have not figured out yet is things other than leaderstats.
I don’t think it’s recommended to use it for non-players, due to datastore limits. Make sure to keep track of datastore ‘queue’ warnings in the output.
You can create a new ProfileStore. Then use it to store profiles for your cars. Every profile needs to have a unique key (UUID probably). Then use the profile as you would normally.
This is assuming the cars have the same behavior as players: they are created/destroyed during server runtime.
Perhaps using regular datastores would be best depending on your usecase.
i was thinking of using StringValues instead, so pretty much save string values with profile service, have their values be as the names of the cars, store that in a folder in replicatedstorage called “Cars” , have profileservice make a new folder called “Car Lists” inside the player, and when a player buys a car, it would find the stringvalue inside the Cars Folder and just put it inside Cars List. and then just have profile service save that. would that work? i havent tested it yet at all.
If you want to save cars of a specific player then yes.
But if cars aren’t linked to a player, you shouldn’t have it be in a player’s data.
You can always go without StringValue instances, giving you more control over replication.
got it to work, but hey appreciate for helping though.
Hi to be honest I won’t use ProfileService to make a guild system I would make my own system with UpdateAsync()
is it needed to kick the player when the profile is released? this functionality makes ListenToHopReady unusuable unless I’m missing something, if I am please guide me in the right direction
I don’t think it is necessary to kick the player when the profile is released, but I do believe it is good practice to “tie” the player with their profile. From my understanding, I believe ProfileService is very good as an abstract management for PlayerData, so I would generally kick the player if we are not keeping their profile in said server. I think there are particular niche cases, where to be on the safe side, you could kick them while releasing their profile.
Hi! I really want to try this module and just started working with Rojo in VS Code, and I was wondering if there was a way to install this in my packages with Rojo and Wally?
Thanks a bunch!