SimplyStore | Automatic Datastore System

SimplyStore
SimplyStore is a data storing system for games. The system’s goal is to be as easy and intuitive as possible.


What Does It Do?
SimplyStore saves and loads players’ leaderstats folders. When a new player joins, their data is retrieved, created, then added to the player.

This removes may of the dependencies and complexities of other data storing systems: once the leaderstats folder is added, the data is loaded and can be accessed from anywhere.

Timeline:
1. Player Added
2. (Delay) Data retrieved
3. Data created
4. Process Function*
5. Data added to Player

* [OPTIONAL] The process function is for versioning (updating your data structure to the newest layout).


Supported Instances
All value instances are supported. In addition to value instances, three container type instances are supported: Folders, Configurations, and Models.

More Details

Edge cases:

  • ObjectValues’ values don’t save and are loaded as nil. This is because saving a reference to an object between games is not possible.
  • Unfortunately there is a maximum table depth in datastores, so there is a maximum ancestry depth in SimplySave. Don’t go past about a dozen ancestors.

Why SimplyStore?
As mentioned above, SimplyStore is meant to be easy and intuitive. All the DataStore code is done automatically behind the scenes.

In addition to this, SimplyStore uses DataStore2 under the hood. Not only does this make SimplyStore reliable*, it means you can use SimplyStore and your own DataStore2 code, without running into read and write limits.
* Although SimplyStore has been tested, it has yet to be used in any large games. It could potentially have bugs that haven’t been fixed yet. If you find a bug, please message @PersonifiedPizza.

Showcase
As an example, I made a simple game using SimplyStore. This game has a few simple game elements that use data storing: daily chests, single time collectable items, and checkpoints. It also has a nice animated loading screen. You can check that out here:
SimplyStore (Example Game) - Roblox

SimplyStore Stylized TextFindableItemsAndFlagDailyChestOpenDailyChestCooldownUp

More Example Games

Get SimplyStore


Starting SimplyStore

  1. Insert the Script into either ServerScriptService or the Workspace
  2. Adjust the default data
    • The default data is a folder called “DefaultData” inside the SimplySave script. When a new player joins the game, their leaderstats folder is loaded with the default data.
    • To change the default data, just add what you’d like inside leaderstats to the folder. This could be a Folder called “Data” or an IntValue called “Coins”
  3. If API services aren’t enabled:
    • If you haven’t yet, publish the game to access the game settings menu
    • Go to the security tab, and check the box to enable API services

Using SimplyStore

  • Here is a #resources:community-tutorials post that explains using SimplyStore:
  • Here is a quick, general guide:
    1. Don’t create leaderstats yourself. SimplySave does that for you.
    2. If a value instance doesn’t exist and you want to set it, just create it and continue with your code.
    3. To store data that doesn’t show up on the leaderboard, use a container Instance. In the examples, the internal data is inside a Folder called “Data” that’s parented to leaderstats.

Resources

Resource List

Last Bit
SimplyStore is brand new, so if any bugs are found please message @PersonifiedPizza.

21 Likes

Amazing, just a quick question though. Can i make a new value, and put it inside someone’s leaderstats mid session, and when they leave, they still have the stat?

1 Like

Sounds interesting enough!
I hate to deal with DS, this is where my game projects usually ends :slight_smile:
So I give it a chance (and a big like as well!), thank you for sharing!

1 Like

So, is this some sort of DataStore2 but simplified?

1 Like

Yep!

Here’s how the system works: the system adds a leaderstats folder with the previous data to the player (after a short data request delay); you can add, delete, reparent, and change any Values and Folders(*) inside leaderstats; then when the player rejoins the process repeats.

(*) also Configurations and Models (as in the container, not like parts and stuff)

Something to note:

  • Like DataStore2 (because it uses DataStore2), to save in studio add a BoolValue to ServerStorage named “SaveInStudio” and set the BoolValue to true/on/checked (this will make studio take a tiny bit longer to close)

For example, here is some code you could use:

Code
local Players = game:GetService("Players")

-- When a player is added:
Players.PlayerAdded:Connect(function(player)
    -- Wait for leaderstats to be added by system
    local leaderstats = player:WaitForChild("leaderstats") 

   -- See if the player already has a coins value from their last game
    local coins = leaderstats:FindFirstChild("Coins")

   -- If they don't have a coins value, add one:
    if not coins then
        coins = Instance.new("IntValue")
        coins.Name = "Coins"
        coins.Parent = leaderstats
    end
    
    -- While the player is in the game, give the player 50 coins every 5 seconds
    while player do
        coins.Value += 50
        task.wait(5)
    end
end)

In 14 lines, you can create a saving coins value and give players coins for how long they play.


Yep! It’s sort of like a wrapper for DataStore2. All the data storing is done by the system, so all you need to do is get leaderstats and manage the data inside of it.

in developing the data get’s a bit clogged lol, but anyways it’s a good module, you just have to reset the player’s data with manually putting the values and stuff into the player.

You can also use the DefaultData folder to add default data to the player. For example, you could add an IntValue named “Coins” to the default data, then when players join they get an IntValue named Coins.

I’d also recommend making/using a function called findOrCreate to simplify the code:

local function findOrCreate(instance, name, type, value)
    local found = instance:FindFirstChild(name)
    if not found then
        found = Instance.new(type)
        found.Name = name
        if value then
            found.Value = value
        end
        found.Parent = instance
    end
    return found
end

Then you can just use that function to get values:

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    local leaderstats = player:WaitForChild("leaderstats") 

    local coins = findOrCreate(leaderstats, "Coins", "IntValue")

    while player do
        coins.Value += 50
        task.wait(5)
    end
end)

well, if you already had some values stored it wouldn’t give you new values that are in the default
even tho, i can just add a check and then add it, it would be nice if this was done by default.
game.Players.PlayerAdded
and then you go trough their leaderstats and compare the default leaderstats to make sure none are missing, ye?
Just a suggestion tho.
Edit: How can i wipe the datastore? (delete)

1 Like

Good idea!

You could do this by adding some code to the built in process function:

Process Function Code
local simplyStoreScript
do
	simplyStoreScript = game:GetService("ServerScriptService"):FindFirstChild("SimplyStore", true) or game:GetService("Workspace"):FindFirstChild("SimplyStore", true)
	if not simplyStoreScript then
		error("Process function couldn't find the \"SimplyStore\" script!")
	end
end

-- Couldn't think of a descriptive name. Function abstracted anyways.
local function copyPasta(copy, paste)
	for _, copyChild in ipairs(copy:GetChildren()) do
		local pasteChild = paste:FindFirstChild(copyChild.Name)
		if not pasteChild then
			pasteChild = copyChild:Clone()
			for _, subPasteChild in ipairs(pasteChild:GetChildren()) do
				subPasteChild:Destroy()
			end 
			pasteChild.Parent = paste
		end
		copyPasta(copyChild, pasteChild)
	end
end

local function UpdateWithDefaultData(leaderstats)
	local defaultData = simplyStoreScript.DefaultData
	copyPasta(defaultData, leaderstats)
end

local function process(leaderstats)
	UpdateWithDefaultData(leaderstats)
	return
end

return process

Then removing one line of code from the SimplyStore script:

script.DefaultData:Destroy()
--script.DefaultData:Destroy()

(line 22)

(If you don’t see that line around line 22, that’s probably because I’m removing it from new versions of SimplyStore. There isn’t a super good reason to keep that data only inside the script, and it’s nice to have it accessable)
Edit:
Changed that line for new SimplyStores.

Hello! I already have a leaderstats folder, but whenever I join, there is another leaderstats folder. I only want the one I made for a specific reason, how can I make it not make another leaderstats through the code that you made? Or at least be able to change the name of the leaderstats folder that is being created.

image

1 Like

That is not how you set up GitHub. There’s no point in having a GitHub page if you’re just placing a .rbxm file on it.

.rbxm files should be in releases, source code should be in the repo.

image

1 Like

Hey @Annexsohn,

The code automatically creates a leaderstats folder. There are duplicates because your code creates one then SimplyStore creates one.

To change your code, instead of creating a new leaderstats folder, just use player:WaitForChild("leaderstats"). This gets the synced folder that SimplyStore creates and allows your code to use that instead.

Yep! I set that up quickly. I’ll update it tomorrow.

Thanks for the tip :happy2:

image
That seems to be occurring now? I fixed it showing 3, but it still does 2

You also need to get synced values. When the player is added, there is a slight delay, then the leaderstats folder is added with all of the old Values. Before creating new values, you’ll need to check if that value already exists from the last session.

Here is a code example (with too many comments :wink:) from above:

local Players = game:GetService("Players")

-- When a player is added:
Players.PlayerAdded:Connect(function(player)
    -- Wait for leaderstats to be added by system
    local leaderstats = player:WaitForChild("leaderstats") 

   -- See if the player already has a coins value from their last game
    local coins = leaderstats:FindFirstChild("Coins")

   -- If they don't have a coins value, add one:
    if not coins then
        coins = Instance.new("IntValue")
        coins.Name = "Coins"
        coins.Parent = leaderstats
    end
    
    -- While the player is in the game, give the player 50 coins every 5 seconds
    while player.Parent == Players do
        coins.Value += 50
        task.wait(5)
    end
end)

Before creating a coins value, the code needs to check if one already exists from the last session.

Alright, but is there a way to not make the SimplyStore script not make a leaderstats folder?

You could go into the code and change the name of the folder it creates. You can also change your process function to:

local SYNC_FOLDER_NAME = "Folder Name Here"
local function process(leaderstats)
	leaderstats.Name = SYNC_FOLDER_NAME
	return
end

return process

And where can I put these lines of code?

There should be a module script called process. Open that up and replace its contents with that code.

1 Like

Alright, thank you! That should be it!

1 Like