Hi Guys,
I am just curious what the best way to save data such as money, my current set up when selling an item for money is to save it to local data then to server data then onto the datastore.
Would it be best to send a money value from a local script straight over to server data then to datastore skipping local data saving completely and when writing to server data does it write to local data?
2 Likes
NEVER send money (as an example for data) through a localscript. Exploiters can very very easily edit this. One of the most secure ways to save game data is below.
-- MAKE A SCRIPT AND PLACE THAT SCRIPT IN SERVERSCRIPTSERVICE, USE THE CODE BELOW FOR IT
local dataStoreService = game:GetService("DataStoreService");
local gameData = dataStoreService:GetDataStore("GameData1");
game.Players.PlayerAdded:Connect(function(player)
local folder = Instance.new("Folder", player);
folder.Name = "Leaderstats";
local cash = Instance.new("IntValue", folder);
cash.Name = "Cash"
cash.Value = 50
local playerData = gameData:GetAsync(player.UserId) or false;
spawn(function() -- this function is optional to have. this function saves data automatically every 1 minute.
while player do
wait(60) -- waits 1 minute before autosaving data.
local success, err = pcall(function()
gameData:SetAsync(player.UserId, player:FindFirstChild("Leaderstats").Cash.Value)
end)
if not success then
warn("Failed to autosave data for " .. player.Name .. ".")
else return;
end
end)
if playerData then
cash.Value = playerData
end
end)
game.Players.PlayerRemoving:Connect(function(player)
if player:FindFirstChild("Leaderstats").Cash then
local success, err = pcall(function()
gameData:SetAsync(player.UserId, player:FindFirstChild("Leaderstats").Cash.Value)
end)
if not success then
warn("Failed to save data for " .. player.Name .. ".")
else return;
end
end)
Whats the rules on manipulating cash??? I have a local gui that when selling an item it gives you money then sends it to a server script which from there saves it to you Server side player data
Saving GPU Entity which sends the local information to server script to save to server
indent preformatted text by 4 spaces
--Initialize Bindable Event
local saveGPUEquipment = game.GUI.Main.GlobalEvents:WaitForChild("SaveGPUEquipment")
--Initializing Player Services
local Players = game:GetService("Players")
local currentPlayer = Players.LocalPlayer
--Initializing Replicated Storage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local isSaving = ReplicatedStorage:WaitForChild("IsSaving")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local saveData = ReplicatedStorage:WaitForChild("SaveDataToServer")
local isSavingBoolean = false
--Initializing Variables
local globalGPUEntity
saveGPUEquipment.Event:Connect(function(entityN, cashV, powerUsedV, cryptoV)
--Initializing Function Variables
local i = 1
local g = 1
--Pausing Data Save Till Saving Has Finished
isSavingBoolean = isSaving:InvokeServer()
while isSavingBoolean == true do
if isSavingBoolean == false then
print("Saving Finalised Continuing With Save")
break
else
isSavingBoolean = isSaving:InvokeServer()
print("Waiting For Saving To Finalise")
wait(1)
end
end
if isSavingBoolean == false then
print("Saving Hasnt Started")
end
while true do
--Finding Power Slot Object
local gpuSlot = "slot"..g
gpuSlot = currentPlayer.GPUEntities:FindFirstChild(gpuSlot)
if gpuSlot.Value == nil or gpuSlot.Value == "nil" or gpuSlot.Value == "Deleted" then
--Setting Power Equipment Entity Value
gpuSlot.Value = entityN
globalGPUEntity = entityN
--Saving Updated Player Stats
currentPlayer.stats.Money.Value = currentPlayer.stats.Money.Value - cashV
currentPlayer.stats.ElectricityUsed.Value = currentPlayer.stats.ElectricityUsed.Value +
powerUsedV
currentPlayer.stats.CryptoGen.Value = currentPlayer.stats.CryptoGen.Value + cryptoV
currentPlayer.stats.TotalGPUS.Value = currentPlayer.stats.TotalGPUS.Value + 1
local playerData = {
["Money"] = currentPlayer.stats.Money.Value,
["ElectricityUsed"] = currentPlayer.stats.ElectricityUsed.Value,
["CryptoGen"] = currentPlayer.stats.CryptoGen.Value,
["TotalGPUs"] = currentPlayer.stats.TotalGPUS.Value
}
saveData:FireServer(g,i,globalGPUEntity, "Nil", playerData)
while true do
local invSlot = "slot"..i
invSlot = currentPlayer.Inventory:FindFirstChild(invSlot)
if invSlot.Value == nil or invSlot.Value == "nil" or invSlot.Value == "Deleted" then
invSlot.Value = gpuSlot.Value
local playerData = {}
saveData:FireServer(i,i,globalGPUEntity, "Inv", playerData)
break
else if i >= 200 then
break
end
end
i = i + 1
end
break
else
print("GPU Equiptment Slot Full")
g = g + 1
if g >= 100 then
break
end
end
end
end)
Saving to Server Script is a server script that save data to server side
indent preformatted text by 4 spaces
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local saveData = ReplicatedStorage:WaitForChild("SaveDataToServer")
local function SaveDataServer(player, i, secondI, entity, InvIdentifier, playerData)
if string.find(entity, "gpu") and string.find(InvIdentifier, "Inv") then
local invSlot = "slot"..i
invSlot = player.Inventory:FindFirstChild(invSlot)
invSlot = entity
else if string.find(entity, "gpu") then
player.stats.Money.Value = playerData["Money"]
player.stats.ElectricityUsed.Value = playerData["ElectricityUsed"]
player.stats.CryptoGen.Value = playerData["CryptoGen"]
player.stats.TotalGPUS.Value = playerData["TotalGPUs"]
local gpuSlot = "slot"..i
gpuSlot = player.GPUEntities:FindFirstChild(gpuSlot)
gpuSlot.Value = entity
end
end
if string.find(entity, "power") and string.find(InvIdentifier, "Inv") then
local invSlot = "slot"..i
invSlot = player.Inventory:FindFirstChild(invSlot)
invSlot = entity
else if string.find(entity, "power") then
player.stats.Money.Value = playerData["Money"]
player.stats.ElectricityMade.Value = playerData["ElectricityMade"]
local powerSlot = "slot"..i
powerSlot = player.PowerEntities:FindFirstChild(powerSlot)
powerSlot.Value = entity
end
end
if string.find(entity, "pc") then
player.stats.Money.Value = playerData["Money"]
player.stats.GPUCapacity.Value = playerData["GPUCapacity"]
local pcSlot = "slot"..i
pcSlot = player.PCEquipmentEntities:FindFirstChild(pcSlot)
pcSlot.Value = entity
end
if string.find(entity, "server") then
player.stats.Money.Value = playerData["Money"]
player.stats.Multiplication.Value = playerData["Multiplication"]
local serverSlot = "slot"..i
serverSlot = player.ServerEquipmentEntities:FindFirstChild(serverSlot)
serverSlot.Value = entity
end
if string.find(InvIdentifier, "InDelete") then
player.stats.Money.Value = playerData["Money"]
player.stats.ElectricityMade.Value = playerData["ElectricityMade"]
player.stats.ElectricityUsed.Value = playerData["ElectricityUsed"]
player.stats.CryptoGen.Value = playerData["CryptoGen"]
player.stats.TotalGPUS.Value = playerData["TotalGPUs"]
local invSlot = "slot"..i
invSlot = player.Inventory:FindFirstChild(invSlot)
invSlot.Value = "Deleted"
if string.find(entity, "gpu") then
local gpuSlot = "slot"..secondI
gpuSlot = player.GPUEntities:FindFirstChild(gpuSlot)
gpuSlot.Value = "Deleted"
else if string.find(entity, "power") then
local powerSlot = "slot"..secondI
powerSlot = player.PowerEntities:FindFirstChild(powerSlot)
powerSlot.Value = "Deleted"
end
end
end
if string.find(InvIdentifier, "Business") then
player.Business.BName.Value = playerData["Name"]
end
end
saveData.OnServerEvent:Connect(SaveDataServer)
Curious if this is bad practice
The proper way to manipulate any currency is for the client to send a request to the server, such as purchase or sell, then have the server validate that request to make sure the client can actually have that action done. If the request is valid, continue on with your function. Otherwise, break out of the function
1 Like
Cheers excellent answer, thanks mate