Easy Datastore V2 | The easiest DataStore on Roblox

(Icon retrieved through Canva Premium, 2024)


Easy Datastore V2

Easy Datastore, new and improved. The most simple and powerful datastore module.


Easy Documentaton


I know the pain :face_with_symbols_over_mouth::sob:!

Datastore modules can be complex, tricky, and time-consuming! Remember all those times you went to documentation-long websites? All those hour-long YouTube tutorials? I also hate that! Let’s stop this nonsense! Introducing Easy Datastore V2. It has ALL of the fancy stuff done for you!


SOOOO easy! :blush:

Easy Datastore is designed with extreme ease! Check out the simple documentation for these basic functions

Module.get()
Module.set()

Improve script clarity and reduce the amount of effort! Some key ease of use features:

  • NO limits! Call module.set() as much as you want!
  • Autosaving + Save-on-leave. Don’t worry, we optimize saving data FOR you!

What about alternatives? :bar_chart::x:

Alternative data modules such as

  • Profile Service
  • Datastore 2
  • etc

I must admit, there are some trusted modules out there that are excellent tools. But these modules consistently have tedious setup processes, documentation, and steep learning curves. Its true the biggest limitation of Easy Datastore V2 is lack of battle testing, but it does have some experience in impoving from version 1. Throughout the months many improvements have been made such as autosaving and session locking!

Audience of EasyDatastore

While EasyDatastore is easy to use, its audience is not restricted to newer developers or smaller games.

  1. Scalability: The simplicity of EasyDatastore and its reliability make it highly scalable and adaptable to different game styles. No locks here!

  2. Capabilities: EasyDatastore supports saving all data types except for objects.

  3. Collaboration: The simpler and easier-to-understand nature of EasyDatastore allows for easy collaboration and understanding among larger studios.

  4. Debugging: Especially in larger and more complex games, having simple functions reduces errors and makes debugging simpler.


Easy Datastore V2 provides extremely complex features with practically no learning curve through a process known as Abstraction of data! Think of it as the same thing as these trusted alternatives but without redundant coding. Take Easy Datastore seriously!


Set up EasyDatastore in your game! All you have to do is add values to the data template located at the top of the EasyDatastore Module!

image

Learn to make a data template!



Easy Datastore is designed to be extremely robust and simple. Remember though that its really complex on the inside!

Optomization

  • Cache: Remembers users who played your game and restores their data without extra calls.

  • Compression: Compresses and decompresses all saved data through noob compressor in conjunction with HttpsService:JSONDecode and HttpsService:JSONEncode

  • Meaningful saves: only saves data if changes were made (both autosaving and save-on-leave

  • Attributes: sets numbered values as an attribute and updates the update when changes are made. This allows both server and client to connect a changed event to the desired attributes with a low learning curve.

Robustness

  • Ensuring player exists: The module prevents errors by yielding its functionalities until the player is loaded. For example, if you call get when the user is not fully loaded, it will yield your current script until the player is loaded. It will only wait so long before it terminates the yield to prevent infinite yields occurring.

  • Bind-To-Close: forces the server to wait for the game to save the data of all users before closing.

  • Anti corruption: using updateAsync, it checks that the data will not override existing data

  • Session locking: prevents sessions being created when existing sessions already exist.

  • Data recovery during run-time: Within the autosaves, if its detected that the users data is corrupted it will automatically restore the most up to date data.

  • Error handling The module manages any errors through a series of attempts. By default, the module will repeat calling for the data five times. You can adjust this inside the data script.

Global autosaving

  • Global save cycle: Goes on a global save cycle which cycles through each player. These players take turns autosaving to prevent conflict. The frequency of this save cycle is determined by the current number of players in the server as Roblox adjusts its limits based on this information. Specifically the equation is AUTOSAVE_FREQUENCY/#plrs:GetPlayers()

  • Optimized saving: Only autosaves if changes are made once it reaches its turn on the global save cycle.

Please let me know if I missed any features of the module as there is a LOT.

So what are you waiting for? Download NOW!

image
(Icon retrieved through Canva Premium, 2024)

17 Likes

“settup”? hm…

1 Like

I made the same mistake on the first version :person_facepalming:

thanks for pointing out the typo

I’ve fixed the typo. Let me know what you think of the module! it has come quite a long way since version 1.

Just wanted to point this typo out so you can change it. :heart:

Could you emphasize the differences between this and V1? Thanks.

1 Like

that is why I use DataStoreService alone, I don’t need datastore modules. Inshallah this post doesn’t turn into a post where KrimsonWoIf’s behavior is discussed here

8 Likes
while true do
	if not locked then

		local count=0
		repeat task.wait(0.1) count+=0.1 until count >= AUTOSAVE_FREQUENCY/#plrs:GetPlayers() 

		if not locked then

			loopIndex = loopIndex + 1

			if not plrs:GetPlayers()[loopIndex] then
				loopIndex = 1			
			end

			local plr = plrs:GetPlayers()[loopIndex]

			-- bro dont call this function
			-- its for autosaving only.

			module.lockedAutoSaveFunction(plr, "8093jhhewuh98fwe")
		end
	else
		break
	end
end

Wow, look how smart this autosaving feature is, I can find any better way to code this!

function rle.compress(message)
	local encodedMessage = ""
	local cursor = 1
	local messageLength = #message

	while cursor <= messageLength do
		local currentChar = message:sub(cursor, cursor)
		local closestInstanceWithSameValue = findClosest(message, cursor, currentChar)

		if closestInstanceWithSameValue then
			local distance = closestInstanceWithSameValue - cursor
			local pattern = message:sub(cursor, cursor + distance - 1)
			local foundInARow = 1

			while cursor + (foundInARow * distance) <= messageLength do
				local nextPattern = message:sub(cursor + (foundInARow * distance), cursor + (foundInARow * distance) + distance - 1)
				if nextPattern == pattern then
					foundInARow = foundInARow + 1
				else
					break
				end
			end

			if foundInARow > 3 then
				encodedMessage = encodedMessage .. "|" .. foundInARow .. "," .. pattern .. "|"
				cursor = cursor + foundInARow * distance
			else
				encodedMessage = encodedMessage .. currentChar
				cursor = cursor + 1
			end
		else
			encodedMessage = encodedMessage .. currentChar
			cursor = cursor + 1
		end
	end

	return encodedMessage
end

function rle.decompress(encodedMessage)
	local decodedMessage = ""
	local cursor = 1
	local messageLength = #encodedMessage

	while cursor <= messageLength do
		local currentChar = encodedMessage:sub(cursor, cursor)

		if currentChar == "|" then
			local countStart = cursor + 1
			local countEnd = encodedMessage:find(",", cursor)
			local repeatCount = tonumber(encodedMessage:sub(countStart, countEnd - 1))

			local patternStart = countEnd + 1
			local patternEnd = encodedMessage:find("|", patternStart)
			local pattern = encodedMessage:sub(patternStart, patternEnd - 1)

			decodedMessage = decodedMessage .. string.rep(pattern, repeatCount)

			cursor = patternEnd + 1
		else
			decodedMessage = decodedMessage .. currentChar
			cursor = cursor + 1
		end
	end

	return decodedMessage
end

lmao…
This code doesnt do anything, and even if it did, it causes an error.
Instead of using AI, please, learn how compression and decompression works, its much easier for you.

HttpService as stated a billion times in the past, Does not compress your code. It just converts your code to a different language, which is completely useless because standard DataStores already do it.

The only purpose you should be using it for, is to check how big it is.

6 Likes

Profile service has been used and battle-tested in many production games, this is used in none. By no means is your module tested on the same level as these other services and its extremely disingenuous to claim that it is.

7 Likes

How do you get something used if the argument for not using it is that no one uses it? Do you see how dumb that sounds, when a new resource gets made it’s unfair to immediately rule it out as unusable because it’s new. If no one uses it then it never leaves this state. It’s not like ProfileService came out with thousands of people already using it, that’s not how that works.

If you like ProfileService and have no plans to switch to something else then that’s good for you, don’t leave a comment for a swayed opinion. I am not endorsing this project but I am against your untasteful comment. It isn’t constructive by any means.

Instead, try something like this:

  • This resource is more focused on saving data for Players, but I think it would be nicer if it was bundled with a way to save data for objects.
  • I’ve read the code and it seems unoptimized using JSON since Roblox DataStores already compress themselves and handle that automatically, could you remove this?

(This is my feedback for this project)

Comment about the project constructively, even if you have no plans to use it, or, just don’t comment at all. Also, they probably use this in personal projects and have some friends using it. Sure it doesn’t have massive games using it immediately but neither did the other resources.

1 Like

He didn’t say any of what you are claiming. He just said that the claim is disingenuous, that’s all. You don’t have to make false claims to get your resource used.

3 Likes

A lot of people are not too fond of this project because of the OPs history of posting… not very useful resources.

1 Like

@GameInspectors Took about 8 hours, maybe new record?

1 Like

Thanks for the feedback regarding JSON and objects.

Here are my responses:

  1. Roblox does not support saving objects in their data store. It is the responsibility of the developer to store references to objects rather than the objects themselves. If other modules do indeed allow the saving of objects then I would love to hear how they attempt to do this feat.

However here is how I think this might work:

  • Have a folder full of items that can be saved
  • When a user saves an object, instead of actually saving an object, it saves the name of the object with a identifier than it is an object
  • When a user loads an object, retrieve the object from the folder based on the name identifier.
  1. Thank you for making me aware of JSON. I will remove it in the next update.

Thank you for telling me about the grammatical inaccuracy in my post. I want to clarify I did not mean that the module has been heavily tested, but I am hoping that by making it open source I can have the module undergo scrutiny to improve it over time.

I am correcting the post.

1 Like

Compression:
JSON is not meant to compress the data. instead, Noob Compressor, a module created by @FriendlyEvo is. Whether FriendlyEvo used AI is unknown but they said they took a class on compression. If you have any better alternatives that I can use or find inaccuracies in noob compressor, please let me know.

Smart autosaving
The script logic for the autosaving is indeed simple, but I perceive it as smart for these reasons:

  • It only commits autosaves when changes have been made.
  • It goes on a global loop cycle which ensures that each player equitably uses roblox’s limitations without conflicting with each other
  • The autosave uses a simple equation in determining the frequency of autosaves (based on amount of players) which adapts to roblox’s constraints on datastores.

So the reason I call it smart is because it takes into account multiple variables at the same time. I’m not going to say that is it the best, so I would love to hear if you have any recommendations for me.

All datastore modules use Roblox’s datastoreservice, they use a lot of best practices for you. The issue with datastore service is that it can be unreliable with issues like:

  • Slow saving - A user might leave your game and then rapidly join back. The issue with this is that the datastore service’s speed can vary, so it might not save time on the old server in contrast to the load on the new server which leads to data loss.

  • Server crashing - You need to implement some kind of autosave mechanic in case the server crashes. if the server crashes it will be unable to save the data of each player before terminating.

  • Data validation - you should use updateAsync for datastoreservice not getAsync so that you can compare the old data to the new. This prevents complete data loss in the case of the game accidentally believing that the user is new

  • Error handling - you need to ensure that you gracefully handle errors because data service is unreliable. This is done through multiple attempts to retrieve data if failure occurs.

So I understand the desire to use your system because having to learn something created by another developer is stupid. Believe me: I know. This is why I created this module. I entirely removed the learning curve of datastore modules while also addressing the tricky situations of datastore.

All you have to do is fill out the data template and then use the module. get() and module. set() to access my module (which manages roblox’s basic datastore service with fail-safes and best practices)

I was providing feedback on a specific claim made in the description of this product that I felt was inaccurate, by no means was making an “argument for not using it”.

I always aim to be constructive yet honest in all my posts, in this case I am providing feedback on a claim I believe is inaccurate in the hopes of letting people know that the comparison made was not accurate.

Also as others are mentioning in your replies, OP has had a mixed track record on previous recources (plugin code used without permission, off-topic discussions, etc.).

2 Likes

First impressions: AWESOME. The post is well formatted and thought out. Everything is described in a “hype” sort of way, making it extremely appealing. (I would update the logo a bit but whatever lol). Everything is relatable and explained thoroughly. This is a true quality post. Now let’s check out the module…


Upon opening the module in studio and testing it out, there are a few things I notice right off the bat.

Organization

Nothing about the module is what most would consider “standard” coding practice :rofl:, however, if it works, it works.

For V3 I would recommend going through and removing many of the large gaps between functions and sections. It is easier to read makes things less confusing. I do love that the template and config are all in 1 place though.

Integer Methods

Another thing I noticed was a feature to call Module.add, Module.subtract, Module.multiply, etc. when dealing with integer values, however, I see no way that the module actually checks for the value to be an integer. This likely wouldn’t cause huge issues, and it’s entirely possible that I completely missed that section, but upon first impressions of the module it seems confusing.

Documentation

As mentioned above, there are several other features to the module besides just Module.set and Module.get. These are likely useful, otherwise they probably wouldn’t be a part of the module (lol), but there isn’t a place that they are described and explained. Setting up a page dedicated to documentation might be helpful in the future. (Maybe with V3? :slightly_smiling_face: )


I would also like to address some of the concerns already mentioned.

Autosave

(@DasKairo) - While I do agree with the statement (maybe not the sarcasm…), this does seem like a very janky way to create a global loop. Using while loops can be great in certain circumstances, but inside of a ServerScript handling potentially thousands of pieces of data seems like it could be reengineered.

Usage

(@OneEDM) - I also agree (partially) with this statement. Modules like ProfileService have been used and tested in several games, however, none of them started that way. The creators of these modules released them with similar popularity to this module. They relied on other developers over time to test and experiment with their module, which is exactly what the next step is for Easy Datastore.


Conclusions

This module has extreme potential. It is extremely attractive to newer developers because of it’s simplicity and claims to work just as well as ProfileService and DataStoreV2.

Although I have yet to test it against ProfileService, DataStoreV2, and similar DataStore modules, based on what I have played with it does seem to work decently. I see great potential in this project and can’t wait for updates.

I will keep experimenting and testing this module and let you know of any issues I come across.

QUICK EDIT: Change the title of the post to be shorter and more descriptive. Don’t ask a question about your own module, as it makes it seem like you yourself don’t know whether or not it’s better. Maybe something like “Easy Datastore V2 | The easiest DataStore on Roblox”

2 Likes

Thanks for using my module noob compressor for Easy Datastore! I see a lot
of potential in the simplicity this datastore module offers! Let me know if you experience any issues with compression!

1 Like

I am really happy to hear you find the post exciting and well made. I agree with the title and I went ahead and renamed it.

Why I added “extra functions” such as module.add()
I feel as though these extra functions can clarify code that uses the module.

Without module.add() you must do:

local module = require(EasyDatastore2)
local currentCoins = module.get(plr, "coins")
module.set(plr, “coins”, currentCoins+10)

Which can make code confusing and having redundant steps.

With module.add you can just do:

local module = require(EasyDatastore2)
module.add(plr, “coins”, 10)

Which is clear and consise.

Changes I am planning to make:

  • organizing the code

  • locking integer functions (& double) to numbers only, and issuing a warning if they attempt to pass invalid object types.

  • removing spacing in the code

  • adding more comments to explain purposes

  • removing JSON functions (as roblox apparently does that automatically)

  • creating a dedicated page to documentation

Conclusion

Thank you for the feedback and words of affirmation. This feedback has been carefully considered and will be implemented. I’m very exciting to see your results in your testing, as this is exactly what I wanted when making the resource open. My module is very robust and I am excited to see if you can crack it!

1 Like