Data Module Feedback

I have updated an old version of a data management module I have used in most of my games since mid-2016. I have spent a lot of time making this. My goal has been to create a module that can save, load and manipulate data easily. The module should be universal (meaning it should be easy to use on any game you make, which so far it has been for games I’ve used it in). Once I complete this, I will try to let more people use this as it’s really handy and saves lots of time and effort.

However, I’m aware that a few bugs, glitches, insecurities, and complications on usage exist in the module. I was wondering if anyone would like to either like to experiment with it a bit if they have some free time or use it in a game they’re working on and provide some feedback on what they think of it and what I could change. Thanks in advance!

The module includes a guide/API which the module is located inside of.
Link to the module: https://www.roblox.com/library/1650666977/DataModule-v2-0

2 Likes

The module overall looks pretty good, a few things I noticed though:

  1. The setup, certain folders and remotes are required to be created for it to work properly. This could potentially affect the way a game works if it happens to use the same folder names etc, I’d personally make it script only without any kind of prior setup or creation of objects, just make it a module that can be required and used on the server, allow the dev to setup client>server and server>client data things themselves.
  2. You have to use Module.SetPlayerData to set a key’s value, you have to load the player’s data before that as well. It’d be much better if Module.LoadPlayerData returned a data class, allowing you to get, set, update and save values from one simple class, the player’s data could auto-load when the player joins as well.

Other than that it looks pretty good, nice job.

2 Likes

Thank you for testing!

Response to point #1: That would probably be a good idea, it would help with adapting to other games. Will definitely do this.

Response to point #2: I really like the idea of a PlayerData class that could be used to handle each player’s data, however I’m wondering what people would like more. I plan to make this module more object oriented as I rewrite it, so should I make a separate service like “DataLoaderService” that is a singleton class that auto loads data? (because doing PlayerAdded in the module directly would attach that event every time the module is required)

Again, thanks for the feedback

What I usually do is have a ModuleScript (or just a built-in library in the main server script, depends on how i’m making a game) that goes something like this:
API:GetPlayerData(player) | returns a DataClass
API:SaveAllData() | Saves all data currently loaded
DataClass:Set(key,value) | Sets the cached value of key to value
DataClass:Get(key) | Returns the cached value of key
DataClass:Update(key,updatefunction) | Updates the key using updatefunction, returns new value
DataClass:Save() | Saves the cached data to the DataStore.

This allows me to do something like update a player’s cash with minimal effort and I don’t need to worry about saving it afterwards:

Data:GetPlayerData(player):Set("Cash",50)

I personally find this easier to use, it’s all one module, it autosaves etc. etc, obviously the way you make your data module is up to you but I’d suggest something like this.

2 Likes

I’ve already talked with you about this, but I’ll just say a couple things more - The data itself should probably not have any functions. That just complicates the serialization for the data store. And also it doesn’t really make sense for a data-carrying object to have methods on it. It should be a lightweight tool used for passing around information. The API is what should do the heavy lifting.

The practice I use is to have a singleton, as you’ve suggested, and that singleton has the following methods: Get(playerOrUserId), Set(playerOrUserId, data), Update(playerOrUserId, updateFunction), and Persist(playerOrUserId). Get only returns a deep copy of the data rather than a reference to the actual cached data so as to force the use of the Set and Update methods. I say “playerOrUserId” because my code is written such that it can take a number or a Player and it all works the same since when given the Player all I actually do is use their UserId anyway.

I do like the idea, though, that you make this just a drag-and-drop module that does not directly use any remote objects. It does seem less user-friendly if you’re forcing their hand with where to put objects.

That’s just my opinion on this. It’s a well-done module, and I look forward to seeing your continued progression! :smiley:

2 Likes

Thank you Noah! I’ve actually been working since I replied on making it more object-oriented and making it a bit more readable while working with it.

I took @xonae 's advice and created a class called PlayerData which holds the player’s data table and has functions such as GetStat, SetStat and Save, however I might change this based on your advice and what people think of the change. The only thing I have a question on is this:

Is this mainly to prevent people from doing something like this:

-- For the following, assume that the stat "List" is a table --
DataModule.GetPlayerData(player):GetStat("List")[1] = "Changed without using SetStat"

Instead of this:

DataModule.GetPlayerData(player):SetStat({"List", 1}, "Changed with SetStat")

Sidenote, I also just published the changes I’ve been working on. I updated the included guide and API for the module too so it should be pretty straight forward to use.

“___Stat” is just noise, :Get(…) and :Set(…) for a naming scheme is cleaner.

Or if you have to append a word, at least make it “Key”, since you are exposing a key-value storage from the looks of it. Key is a whole word and more standard, “Stat” is not.

Removed stat from GetStat and SetStat.

Exactly. Also, it helps to prevent data corruption if the only way to edit the cache is to very directly call :Update(...) or :Set(...).

1 Like

I just updated the DataModule. I would really appreciate if some of you could check it out and tell me what you think is wrong with it and what you like about it! If you have any suggestions please let me know as I’m still trying to make this super easy for all users to use in every type of game. Here’s what’s changed:

  • Fixed bug where player data can sometimes initialize more than once
  • Added player leaderboard support for stats you add to the module
  • PlayerData:Get and the argument in the update function of PlayerData:Set now copy data instead of passing the reference. This is useful for making sure that tables don’t get passed by reference. (Copy function found on the luausers site. Link in the module.)

Take a look at the API and instructions I’ve included inside of the DataModule object and tell me what you think of the system! Again, I’m ALWAYS open to feedback.