ProfileHandler || A data module with session locking and backups!

ProfileHandler

Download | Documentation | Source

ProfileHandler is an open-sourced data module developed by @iamtryingtofindname , which makes use of session locking for saving player data and using ordered data stores for backups. It was designed to be intuitive enough for a beginner to understand, while still powerful for experienced scripters. In addition, this module provides the option to save player data using a player instance, but also provides the option to save with a key.

Where can I download it?

You can download and view the module with the following links:

Roblox Download
Github

What about documentation?

For complete understanding of the module, it is highly recommended you view the documentation for this module.

Link to documentation

How do I stay updated?

To keep in touch with the latest-and-greatest of this module, check the update log, which provides the history of every update.

Link to Update Log

Example of use:

local Players = game:GetService("Players")

local ProfileHandler = require(script.ProfileHandler) -- Reference to module, can be wherever, in this case, parented to the script

local KillsStore = ProfileHandler:GetPlayerStore("Kills") -- Gets a store called 'Kills', which is meant to save player data

Players.PlayerAdded:Connect(function(player) -- When a player joins
	local plrKills = KillsStore(player) -- Gets the key for 'player' from the 'Kills' store
	
	local leaderstats = Instance.new("Folder") -- Creating a leaderboard
	leaderstats.Name = "leaderstats"
	
	local Kills = Instance.new("IntValue")
	Kills.Name = "Kills"
	Kills.Parent = leaderstats
	
	Kills.Value = plrKills:Get(0) -- Gets 'Kills' data for player, and updates the leaderboard
	plrKills:Bind(Kills) -- Binds the leaderboard 'Kills' to the store
	
	leaderstats.Parent = player -- Finalize the leaderboard
end)

local function incrementKills(player) -- Call this function when you want to increment a player's Kills
	local plrKills = KillsStore(player) -- Gets the key for 'player' from the 'Kills' store

	-- Now we increment it by 1
	plrKills:Increment(1) -- It is that simple!
end

while wait(1) do -- Runs the following code every second
	for _,player in pairs(Players:GetPlayers()) do -- Increments for all players
		incrementKills(player)
	end
end

-- No need to deal with saving data, that is already covered by :GetPlayerStore()!

If you have any questions at all, do not hesitate to post a reply to this thread. Thanks for reading!

2 Likes

can’t you just use datastores, don’t get it

This module expands upon datastores. Also, it uses datastores in a way that allows for session locking and backups. It is like a regular datastore, except it is more intuitive and more powerful. So yes, this does use regular datastores, but what this module does is makes it easier to use with more functionality.

I added an example of use for this thing, although the example is a very basic example of using it.

Why use this over ProfileService?

1 Like

Also, backups now, now even a big deal since DataStore 1.1 will support backups internally. (versioning) I literally released DataSave+ 3 days ago, I actually made it 15/20 days ago, and it seems to do the same as what yours does.

As someone who has experience with messing with the berezaa method, I can tell you, it gets quite expensive in the way of how many versions you end up needing to save and such, it gets messy, the way I’m doing is having a main version, and only keeping backups to the developer. I only update the main version when doing session locking, that’s for me personally.

This is a good alternative to use over profile service because this provides easy ways to store player data. Also, this includes backups with ordered data stores, which ProfileService doe snot provide.

This module is really cool and seems useful! Bookmarked.

Adding on to what @iamtryingtofindname said, I agree. I took at look at your module, and it does not seem to make much sense the way it is written. Also, I looked into your code, and I saw some bad practices. For example, in many places, you did this:

if not profiles[self.ProfileStore] then
	profiles[self.ProfileStore] = {}
end

when you could simply do this:

profiles[self.ProfileStore] = profiles[self.ProfileStore] or {}

Also, I saw you use newproxy() a lot. I did some research, and it is deprecated, and has pretty much no use. Also, it isn’t entirely clear how to use your module or how it can possibly be better than this one. Also, backups for developers only isn’t really backups.

1 Like

Thanks for linking my post!

I think the last sentence of my post is misleading, it turns out newproxy was deprecated in Lua 5.1, but it was still around. In 5.2, it got completely removed.

Since Luau is based on Lua 5.1, which is what Roblox was using, it inherits anything Lua 5.1 had. Therefore it inherited the deprecated state of the newproxy function.

newproxy was even an undocumented function, so using it can make code obscure.

2 Likes

That isn’t a bad practice, that is just a preference.

Responding to this topic:

How is this module useful despite being easy to work with? There is no additional functionality which anyone would find useful.

2 Likes

It simplifies everything and provides easy backup and session locking implementation.

You’re claiming that this module is “powerful” for advanced scripters, how is that? Only a beginner would find the benefits you provided useful. It doesn’t provide any useful functionality which an advanced scripter would find useful.

You’re also not handling session lock properly:

which renders the session locking benefit of this module completely useless.

So how exactly would you handle it then?

(session locking doesn’t require it to use the same as the “ForceLoad” to be session locking, it’s just better)

There is no point to have session locking when you just want to kick players just because their data is session locked.

@iamtryingtofindname

You would handle it by successively loading data for the key that is session locked and check if the session lock is assumed “dead” or expired, then set it a new session lock and save it.

That is one way to do it, but not the way I resorted to. However, if you wish to do it this way, you can use the Profile:BindToLock function to bind a new function to locking, so you can change the method used.