Datastore Resource [REMADE]

(This only supports leaderstats at the moment.)
WARNING: IF YOU SWITCH FROM THE OLD DATASTORE TO THE NEW ONE, DATA
WILL BE BROKEN, DUE TO THE DATASERVERS HAVING THE SAME DATA NAME.
IT WILL DETECT THAT IT HAS DATA, BUT NOT IN THE FORMAT IT RECOGNISES,
DO NOT SWITCH FROM THE OLD DATASTORE TO THE NEW ONE BEFORE CHANGING THE DATA NAME, AND IT WILL ACCESS THE DEFAULT DATA


Introduction

Making a DataStore can be hard, but this is a simple way to create your own, which can easily support multiple different values and automatically saves them for you!


Why should I use this?

You don’t need to, but this is great for easily creating values, and super easy to customize! The main scripts are located in 2 modules. Build and DataStore. Build has only 1 function which just creates data for you to save, in the format required to save and load data and it will also create the leaderstats for you. DataStore has 4 functions, one of which is not needed to be used, as it is accessed inside the script. An example of making simple leaderstats (does not save) using the Build module:

local Resource = game.ReplicatedStorage["DataStore Resource"]
local reqBuild = require(Resource:WaitForChild("Build"))
local function playerAdded(Player)
	local data = reqBuild.BuildNewLeaderstats({
		{
			Name = "Tickets",
			TypeValue = "Int",
			Default = 200
		}
	}, Player)
end

game.Players.PlayerAdded:Connect(playerAdded)

An example of multiple is:

local Resource = game.ReplicatedStorage["DataStore Resource"]
local reqBuild = require(Resource:WaitForChild("Build"))
local function playerAdded(Player)
	local data = reqBuild.BuildNewLeaderstats({
	{
		Name = "Tickets",
		TypeValue = "Int",
		Default = 200
	},
        {
		Name = "Diamonds",
		TypeValue = "Int",
		Default = 0
	},
}, Player)
end

game.Players.PlayerAdded:Connect(playerAdded)

You need to have the function wrapped in a variable so then you can save the data, like shown in the next section.


DataStore module

This is the main module, the thing that actually… saves the data! To load the data (This will automatically check if the player does not have data) you need to do:

local Resource = game.ReplicatedStorage["DataStore Resource"]
local reqBuild = require(Resource:WaitForChild("Build"))
local reqDataStore = require(Resource:WaitForChild("DataStore")) -- We now need to access the DataStore module

local function playerAdded(Player)
	local data = reqBuild.BuildNewLeaderstats({
		{
			Name = "Tickets",
			TypeValue = "Int",
			Default = 200
		}
	}, Player)
	
	data = reqDataStore.LoadData(Player, data) -- Load the data using our new leaderstat data variable
end

game.Players.PlayerAdded:Connect(playerAdded)

But this won’t save our data it will only load it. So lets start saving the data!

local Resource = game.ReplicatedStorage["DataStore Resource"]
local reqBuild = require(Resource:WaitForChild("Build"))
local reqDataStore = require(Resource:WaitForChild("DataStore"))

local function playerAdded(Player)
	local data = reqBuild.BuildNewLeaderstats({
		{
			Name = "Tickets",
			TypeValue = "Int",
			Default = 200
		}
	}, Player)
	
	data = reqDataStore.LoadData(Player, data)
end

local function playerRemoving(Player)
	reqDataStore.SaveData(Player)
end

game.Players.PlayerAdded:Connect(playerAdded)
game.Players.PlayerRemoving:Connect(playerRemoving)

There we go! We now have a function that will save our data with it! But, what if a player loads in before the PlayerAdded event can fire? Well, just to be safe, what we do is this:

local Resource = game.ReplicatedStorage["DataStore Resource"]
local reqBuild = require(Resource:WaitForChild("Build"))
local reqDataStore = require(Resource:WaitForChild("DataStore"))

local function playerAdded(Player)
	local data = reqBuild.BuildNewLeaderstats({
		{
			Name = "Tickets",
			TypeValue = "Int",
			Default = 200
		}
	}, Player)
	
	data = reqDataStore.LoadData(Player, data)
end

local function playerRemoving(Player)
	reqDataStore.SaveData(Player)
end

game.Players.PlayerAdded:Connect(playerAdded)
game.Players.PlayerRemoving:Connect(playerRemoving)
for _, plr in pairs(game.Players:GetPlayers()) do
    playerAdded(plr)
end

There! Now, the explaining is over, go below to the Resource part if you wish to download it. Thank you for reading!


Resource

So, if you want to use this resource, you can go to

and start using it!


Outroduction

I thank you for reading this, and if you have any questions, want to send feedback or simply have a problem, PM me!

10 Likes

script.source?
what is the source code?

There are 2 modules. These are the code of them in order of shown in the information:


Build Module:

local build = {}

--[!] Please do not edit if you do not understand this!

function build.BuildNewLeaderstats(Data, Player)
	if not type(Data) == "table" then warn("Build Data is not a table!") return end
	local dataFolder = Instance.new("Folder", Player)
	dataFolder.Name = "leaderstats"
	for _, dataInfo in ipairs(Data) do
		if not type(dataInfo) == "table" then warn("dataInfo is not a table!") return end
		local newValue = Instance.new(tostring(dataInfo.TypeValue).. "Value")
		newValue.Name = dataInfo.Name
		newValue.Parent = dataFolder
	end
	return Data
end

return build

DataStore Module:

local datastore = {}

--[!] Please do not edit if you do not understand this!

datastore.ServerLoader = game:GetService("DataStoreService")
datastore.Server = datastore.ServerLoader:GetDataStore("Server")

function datastore.SaveData(Player : Player)
	local dataPushbackTable = {}
	local success, errorMessage = pcall(function()
		for _, dataInfo in pairs(Player:WaitForChild("leaderstats"):GetChildren()) do
			table.insert(dataPushbackTable, {Name = dataInfo.Name, Value = dataInfo.Value})
		end
		datastore.Server:SetAsync("-".. Player.UserId, dataPushbackTable)
	end)
	warn(success)
end

function datastore.GetDataNameFromList(Data, ReqName)
	for _, dataInfo in pairs(Data) do
		if dataInfo.Name == ReqName then
			return dataInfo
		end
	end
	return nil
end

function datastore.LoadData(Player : Player, Data)
	local dataPushback
	local dataFolder = Player:WaitForChild("leaderstats")
	local success, errorMessage = pcall(function()
		dataPushback = datastore.Server:GetAsync("-".. Player.UserId)
	end)
	
	if (success) then
		if dataPushback then
			-- Has Data
			for _, dataInfo in pairs(dataPushback) do
				if not datastore.GetDataNameFromList(dataPushback, dataInfo.Name) then warn("Cannot find data from data table") return end
				local dataInstance = dataFolder:WaitForChild(dataInfo.Name)
				dataInstance.Value = datastore.GetDataNameFromList(dataPushback, dataInfo.Name).Value
			end
		else
			-- Has Never Played
			for _, dataInfo in pairs(Data) do
				local dataInstance = dataFolder:WaitForChild(dataInfo.Name)
				dataInstance.Value = dataInfo.Default
			end
		end
	else
		warn("Could not load player ".. Player.Name.. "'s data: ".. errorMessage)
	end
end

return datastore

Though, may I ask, why do you need the source code? If you did need it you could just get the resource and check, though you might want to check for roblox viruses, so if that is the reason, I can’t blame you.

1 Like

This module saved me a lot of time!

3 Likes

why 2 modules? you could just combine both of them together…

That is true, and I was thinking of mixing them together, but for now I believe it is fine since there is nothing wrong with it, and nothing is breaking because of it.

1 Like