I was making a datastore until I realised it could be abused by exploiters. I was wondering how I could protect it from being used. One way was putting
a script inside the button to check if I had enough currency then it would save the data. Another way was a local script would trigger a script sending the value and data it needs to save and the script, using communication, would check if they have the currency and it would save the data after. Although I don’t know if they are the best way to secure a datastore. I want to create a secure datastore so I can finally use it for my shop.
give me a video, photo or the code you use to store data in the cloud. I need something else to help you.
You should put all of the data store functions inside of a server script inside of ServerScriptService. You should also put all of the currency, items, and inventory data inside of that script. You should also verify their current amount of owned currency and inventory items in that script. Putting them inside a local script is an inevitable disaster. The button should only send something like a billing request where it asks the server for a particular item. The server checks how much currency that player has, and if they don’t have enough, just don’t give them the item. If they do, add that item inside of the inventory data and subtract their currency with the price of that item. You should also only save data when the player exits the game and at a set time interval so your data store isn’t queued for updates. Here’s a script for example;
local dataRam = {
["2737739283"] = { --player id
["inventory"] = {["coconut"] = 28, ["fish launcher"] = 3},
["currency"] = 72774827
}
}
Players.PlayerRemoving:Connect(function(player)
storeData(player, dataRam[player.UserId])
end)
should I save the data when the player leaves or when it is bought.
Save the data when a player leaves, and load it when a player joins.
Additionally, you can have a table for all the players’ data on the server.
So create your table:
local serverdata = {}
Then you can have a subtable for each player on the server, that you can access using the player’s user id:
serverdata[plr.UserId]
So, if you wanted to modify the coins of a player, you would do:
serverdata[plr.UserId].Coins += 100
Now, to save memory, you can delete all of a player’s data from the table whenever that player leaves (after you saved their data of course):
serverdata[plr.UserId] = nil
This is done so that if a server is up for a long time, a lot of values will be contained in that table, most of which are irrelevant since the players that left the server don’t need their data in there anymore, so you save up memory by deleting their information from the table once they leave.
I hope I could help. Also let me know if anything doesn’t work I’m writing this on my phone
Here’s a simple example of a data saving system:
data = {}
data.service = game:GetService("DataStoreService")
data.events = game.ReplicatedStorage.Events.Data
data.ram = {}
data.stores = {}
data.stores.PlayerData = {
store = data.service:GetDataStore("PlayerData"),
structure = {
dversion = 1.0,
statistics = {
survivals = 0,
coins = 0,
},
inventory = {},
badgeProgress = {},
warnings = {},
maxWarnings = 3
},
versionCheck = function(aver:number, bver:number) --returns true if version is in check
return aver == bver
end,
}
function data:speakChange(player, vdata)
data.events.LISTEN:FireClient(player, vdata) --allows clients to listen to their data changes inside of the server's ram
end
function data:getRam(player:Player)
local userId = player.UserId
return data.ram[userId], userId
end
function data:setRam(player:Player, vdata)
local userId = player.UserId
data.ram[userId] = vdata
data:speakChange(player, data.ram[userId])
end
function data:load(player:Player, store:{ ["store"]:DataStore, ["structure"]:{["dversion"]:number}, ["versionCheck"]:(number, number) -> ("aver", "bver") })
local userId = tostring(player.UserId)
local success, vdata = pcall(function()
return store.store:GetAsync(userId)
end)
if success and vdata then
if not store.versionCheck(vdata.dversion, store.structure.dversion) then
vdata = store.structure
end
else
--last resort (not recommended, you should revert to the previous version if possible, this is just an example)
vdata = store.structure
end
return vdata
end
function data:save(player:Player, store:{ ["store"]:DataStore, ["structure"]:{["dversion"]:number}, ["versionCheck"]:(number, number) -> ("aver", "bver") })
local vdata, userId = data:getRam(player)
local success, errorMessage = pcall(function()
store.store:SetAsync(userId, vdata)
end)
if not success then
warn("Failed to save data for player " .. player.Name .. ": " .. errorMessage)
end
end
function data:save_clearFromRam(player:Player, store)
data:save(player, store)
data:setRam(player, nil)
end
function data:load_toRam(player:Player, store)
local d = data:load(player, store)
data:setRam(player, d)
return d
end
function data:modifyRam(player, path, value)
local paths = string.split(path, ".") or string.split(path, "/") or string.split(path, " ")
local d = data:getRam(player)
local dx = d
for i = 1, #paths - 1 do
dx = dx[paths[i]]
if not dx then warn("Data: Invalid path: " .. path) return end
end
local lastKey = paths[#paths]
if dx[lastKey] == nil then warn("Data: Invalid path: " .. path) return end
dx[lastKey] = value
data:setRam(player, d)
leaderstats:update(player)
end
data.events.GET.OnServerInvoke = function(player:Player, ...) --not recommended (this is just an example)
local keys = {...}
local dx = data:getRam(player)
for i, v in pairs(keys) do
if typeof(v) ~= "string" then warn("Data: Type mismatch: "..player.Name) return end
local dy = dx[v]
if not dy then
warn("Data: Invalid key \""..v.."\": "..player.Name)
else
dx = dy
end
end
return dx
end
_G.data = data
leaderstats = {} --example leaderstats changes
function leaderstats:setupPlayer(player:Player)
local folder = Instance.new("Folder")
folder.Name = "leaderstats"
folder.Parent = player
for i, v in pairs(data:getRam(player).statistics) do
local s = Instance.new("IntValue")
s.Name = i
s.Value = v
s.Parent = folder
end
end
function leaderstats:update(player:Player)
local statistics = player:FindFirstChild("leaderstats")
if statistics then
local d = data:getRam(player).statistics
for _, v in pairs(statistics:GetChildren()) do
if not v:IsA("IntValue") then continue end
v.Value = d[v.Name]
end
else
leaderstats:setupPlayer(player)
end
end
_G.leaderstats = leaderstats
sorry if I confused you but I mean’t if I bought the item I needed. Would I save it to the data store immediately or do it when the game closes or player leaves or both.
can i ask you what is data ram
just do not trust the client
– krant19worlddv
Don’t save data immediately!
You should save data on PlayerRemoving
How would I know if the player bought the item when saving the data on remove?
i use folders under the player instance to store the player items , clients can not play with these because the server will no see the changes that the client made
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.