Suphi's DataStore Module

Thank you very much being French I had a little trouble on the video, now I know how it works thank you very much for your help you had me a lot help

Hey there seems to be a missspelling here


Unless I’m mistaken…

Thank you for pointing that out I have fixed it :slight_smile:

`local Players = game:GetService("Players")
local DataStoreModule = require(game.ServerStorage.DataStore)
local Red = require(game.ReplicatedStorage.Red)

local remoteEvent = Red.Server("AllEvent")

local template = {
 --[[
 IN LEADERSTATS
 ]]
	Wins = 0,
--[[
IN OTHER
]]
    Grade = "Beginer",
	StoreCoins = 0,
	Codes = {}
}

local function StateChanged(state, dataStore, player)
	while dataStore.State == false do
		if dataStore:Open(template) ~= "Success" then
		   task.wait(6) 
		end
	end
end

Players.PlayerAdded:Connect(function(player)
	local dataStore = DataStoreModule.new("Player", player.UserId)
	dataStore.StateChanged:Connect(StateChanged)
	StateChanged(dataStore.State, dataStore, player)
	remoteEvent:Fire(player, "dataStoreEvent", player, dataStore.Value) --EVENT WITH RED
end)

Players.PlayerRemoving:Connect(function(player)
	local dataStore = DataStoreModule.find("Player", player.UserId)
	if dataStore ~= nil then
		dataStore:Destroy()
	end
end)`

Suphis vairement desoler de te rederanger, but when I create a remote event in playerData it works but the dataStore (in RemoteEvent) since it is under playerAdded it will take the game start data while I want that if there is a data change during the game the event takes it into account. I look for a lot of things but I’m nothing

Thank you for your help I hope not to bother.

Use a metatable.

Code:

local Players = game:GetService("Players")
local DataStoreModule = require(game.ServerStorage.DataStore)
local Red = require(game.ReplicatedStorage.Red)

local remoteEvent = Red.Server("AllEvent")

local template = {
 --[[
 IN LEADERSTATS
 ]]
	Wins = 0,
--[[
IN OTHER
]]
	Grade = "Beginer",
	StoreCoins = 0,
	Codes = {}
}

local function StateChanged(state, dataStore, player)
	while dataStore.State == false do
		if dataStore:Open(template) ~= "Success" then
			task.wait(6) 
		end
	end
end

Players.PlayerAdded:Connect(function(player)
	local dataStore = DataStoreModule.new("Player", player.UserId)
	dataStore.StateChanged:Connect(StateChanged)
	StateChanged(dataStore.State, dataStore, player)
	
	local proxyTable = dataStore.Value
	dataStore.Value = {}

	setmetatable(dataStore.Value, {
		__index = function(self, index)
			return proxyTable[index]
		end,

		__newindex = function(self, index, value)
			proxyTable[index] = value
			remoteEvent:Fire(player, "dataStoreEvent", player, dataStore.Value)
		end,
	})

	remoteEvent:Fire(player, "dataStoreEvent", player, proxyTable)
end)

Players.PlayerRemoving:Connect(function(player)
	local dataStore = DataStoreModule.find("Player", player.UserId)
	if dataStore ~= nil then
		dataStore:Destroy()
	end
end)

Whenever you edit dataStore.Value, it will send the event.

@5uphi, if there is a built in way to do this, please tell me.

One option is to use custom functions

-- Custom functions that we will add to all player datastore objects
local function Set(dataStore, key, value)
    if dataStore.State ~= true then return false end 
    dataStore.Value[key] = value
    remoteEvent:Fire(dataStore.Player, key, value) -- Tell the client there data changed
    return true
end

local function Increment(dataStore, key, delta)
    if dataStore.State ~= true then return false end 
    dataStore.Value[key] += delta
    remoteEvent:Fire(dataStore.Player, key, dataStore.Value[key]) -- Tell the client there data changed
    return true
end

game.Players.PlayerAdded:Connect(function(player)
    local dataStore = DataStoreModule.new("Player", player.UserId)
    dataStore.Player = player -- Add what player owns this datastore object
    dataStore.Set = Set -- Add the set function to the datastore object
    dataStore.Increment = Increment -- Add the increment function to the datastore object
end)

once you have added the function inside the datastore object you can call it from any script like this

local dataStore = DataStoreModule.find("Player", player.UserId)
if dataStore == nil then error("DataStore not found") end

-- lets use are custom functions
local success = dataStore:Set("StoreCoins", 100)
local success = dataStore:Increment("Wins", 1)

and by calling the set function it will also fire the remote event

2 Likes

@5uphi, I tried your method but I still can’t I’ll show you my scripts

--PlayerData (ServerScriptService)
local Players = game:GetService("Players")
local DataStoreModule = require(game.ServerStorage.DataStore)
local Red = require(game.ReplicatedStorage.Red)

local remoteEvent = Red.Server("AllEvent")

local template = {
 --[[
 IN LEADERSTATS
 ]]
	Wins = 0,
--[[
IN OTHER
]]
	Grade = "Beginer",
	StoreCoins = 0,
	Codes = {}
}

local function StateChanged(state, dataStore, player)
	while dataStore.State == false do
		if dataStore:Open(template) ~= "Success" then
			task.wait(6) 
		end
	end
end

Players.PlayerAdded:Connect(function(player)
	local dataStore = DataStoreModule.new("Player", player.UserId)
	dataStore.StateChanged:Connect(StateChanged)
	StateChanged(dataStore.State, dataStore, player)
end)

Players.PlayerRemoving:Connect(function(player)
	local dataStore = DataStoreModule.find("Player", player.UserId)
	if dataStore ~= nil then
		dataStore:Destroy()
	end
end)
--the script you sent me (ServerScriptService)
local DataStoreModule = require(game.ServerStorage.DataStore)
local Red = require(game.ReplicatedStorage.Red)

local remoteEvent = Red.Server("AllEvent")
local function Set(dataStore, name, value)
	if dataStore.State ~= true then return false end 
	dataStore.Value[name] = value
	remoteEvent:Fire(dataStore.Player, name, value)
	return name
end

local function Increment(dataStore, name, delta)
	if dataStore.State ~= true then return false end 
	dataStore.Value[name] += delta
	remoteEvent:Fire(dataStore.Player, name, dataStore.Value[name])
	return true
end

game.Players.PlayerAdded:Connect(function(player)
	local dataStore = DataStoreModule.new("Player", player.UserId)
	dataStore.Player = player
	dataStore.Set = Set
	dataStore.Increment = Increment
end)
-- Custom Function (ServerScriptService)
local DataStoreModule = require(game.ServerStorage.DataStore)

game.Players.PlayerAdded:Connect(function(player)
	local dataStore = DataStoreModule.new("Player", player.UserId)
	local state = dataStore.StateChanged:Wait()
	if state ~= true then return end

	local success = dataStore:Set("Grade", dataStore.Value.Grade)
	local success = dataStore:Increment("Codes", dataStore.Value.Codes)
end)
--ManageCode (ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local player = game.Players.LocalPlayer
local Red = require(ReplicatedStorage.Red)
local rewardModule = require(ReplicatedStorage.InformationModule)

local remoteEvent = Red.Client("AllEvent")
local codeFrame = player.PlayerGui.CenterGui.CodeFrame.InfoFrame

local code = {}
code.__index = code

function code.new(text: string?, storeCoins: number?, Expired)
	local newCode = {}
	setmetatable(newCode, code)
	newCode.Code = text
	newCode.StoreCoins = storeCoins
	newCode.Expired = Expired
	newCode.Redeem = false
	return newCode
end

function code:CodeEnter(codesValue)
	if self.Expired == true then
		rewardModule:cloneVotingText(codeFrame, "This code Expired")
	else
		if table.find(codesValue, self.Code) then
			rewardModule:cloneVotingText(codeFrame, "Code already Redeem")
		else
			remoteEvent:Fire("codeRedeem", self.Code, self.StoreCoins)
			rewardModule:cloneVotingText(codeFrame, "Code Redeem")
		end
	end
end
return code


--MainScript (Client)
--CodeFrame:
remoteEvent:On("Codes", function(codesValue)
	enterCode.FocusLost:Connect(function()
		local code = orderedCode[enterCode.Text]
		if code then
			code:CodeEnter(codesValue)
		else
			informationModule:cloneVotingText(codeGui, "This Code Doesnt exist")
		end
	end)
end)
1 Like

I understood your method, but this is not what I seek I badly forumulate excuse me what I wanted to say is that when we insert a value in "codes(in the dataStore) bah the problem is that its reverifies not every time the dataStore so when I enter an example code ("Code"1) its tells me well “Redeem” but when I rerentre its me “Redeem” instead of "Code already reedem) and its adds the code in the code(dataStore)

I really apologize for the derangement

1 Like

If I add something to the template it adds it to dataStore.Value, but when I remove it from the template again, it doesn’t remove it from dataStore.Value. Is it possible to make a fix for this?

1 Like

I enjoyed your video comparing DataStore2 vs ProfileService vs Suphi’s DataStore Module and it was very interesting to learn about how each module’s method works and the pros and cons of them.

The API of the module is concise and the code is relatively easy to read compared to ProfileService. I also like how it’s built on newer Roblox technologies like Memory Stores.

I think the only thing holding it back is that the other modules are so old and have been deployed in massive games to the point where most people have confidence in them being battle-tested.

I attached a place file I used for testing the module and built a PlayerData module around it that utilizes both this module and ReplicaService together. It works perfectly but is there anything I should look out for by utilizing it in this way?
datastores.rbxl (98.5 KB)

Unfortunately that is not possible without you writing custom code to remove values

The reason why is let’s say you give the player a sword that is not in the template if the module removed things not in the template the player would lose there sword

So hopefully that shows why the module is not able to workout what things to keep and what things to remove

But if you want to remove something manually all you have to do after you have opened the datastore is dataStore.Value.Key = nil

Hey there! The datastore seems to work well from the tests i’ve made. But everytime i test my game this error pops up, i’m not sure what it means, nor what it can cause to my game.
The error code is the following:

MemoryStoreService: RequestThrottled: Recent MemoryStores requests hit one or more limits. API: SortedMap.Update, Data Structure: Bob/global/Good.

Just curious, if I set the data of a player like “dataStore.Value = “Test”” from one server and the player is in a different server. Will they get the data without having the other server having to close and save the datastore?

It’s a current bug affecting everyone right now.

No because the player in the other server will be using a locally cached version

in the advanced video I show how you can use Queue + ProcessQueue to communicate between servers you can also make your own communication system

Would you consider adding a third find constructor that takes a DataStore.Id as its sole argument? My wrapper (a word I am using loosely as I feel that I have added so much that “wrapper” does not properly describe it anymore) for your module is cross-state and I use DataStore.Id for keying items like Changed events I have been implementing. I can do the string manipulation in the wrapper itself, I just think it is a feature worthy of being a built-in.

Lets say I want to save if a player has an emote or a sword equipped through intvalues though the player that is cloned to the player to get an animation id, should I use this module or another module such as ProfileService?

Whenever I try to open a hidden datastore it says failed and the datastore value is nil. Am I doing something wrong?

both modules can work

you would simply do
datasStore.Value.Key = intvalue.Value

and

intvalue.Value = dataStore.Value.Key

to move the values back and forth

1 Like

what does the error say if you have the same key open already then you cannot open the same key twice