Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

How to make a localscript save Money in the DataStorage?

I am working on a small vehicle sim like game and trying to get my Local script to save the players their money on leaving the game so that when they come back they continue with the money they had when they did leave.

I just don't know how to get this done.

wait(3)

game.Players.LocalPlayer:WaitForChild("Data")
game.Players.LocalPlayer.Data.Stats:WaitForChild("Money")
game.Players.LocalPlayer:WaitForChild("Values")

MinSpeed = 15 --The player must be going faster than this in studs per second til they start earning money.

while wait(0.65) do
	if script.Parent == game:GetService("Players").LocalPlayer.Character then
	if game:GetService("Players").LocalPlayer.Values.CurrentVehicle.Value and game:GetService("Players").LocalPlayer.PlayerGui.Phone.PhoneBody.OS.AppFrames.Vehicles.Values.CurrentVehicle.Value.DriveSeat.Occupant and game:GetService("Players").LocalPlayer.PlayerGui.Phone.PhoneBody.OS.AppFrames.Vehicles.Values.CurrentVehicle.Value.DriveSeat.Occupant.Parent.Name == game:GetService("Players").LocalPlayer.Name then
		game:GetService("ReplicatedStorage").EarnMoney:InvokeServer()
	end
	end
end

1 comment

1

Using DataStores should be done on the server side. As this code provided shows no use of it then I'm assuming you have never used it. You can learn here: https://developer.roblox.com/articles/Saving-player-data-using-PlayerDataStore

2 answers

While xPolarium is right that the DataStore will only truly save values on the Server, this doesn't mean that you cant alter values on the Client to be saved, meaning you will require Remote Events / Functions.

Server Script

local DSS = game:GetService("DataStoreService")
local Storage = DSS:GetDataStore("Money")

local Players = game:GetService("Players")
local remote = game.ReplicatedStorage.EarnMoney

game.Players.PlayerAdded:Connect(function(player
	player:WaitForChild("Data")
	player.Data.Stats.Money.Value = Storage:GetAsync(player.UserId) or 0
	Storage:SetAsync(player.UserId, player.Data.Stats.Money.Value)
end)

game.Players.PlayerRemoving:Connect(function(player
	Storage:SetAsync(player.UserId, player.Data.Stats.Money.Value)
end)

remote.OnServerEvent:Connect(function(player, amount)
	player.Data.Stats.Money.Value = player.Data.Stats.Money.Value + amount
	Storage:SetAsync(player.UserId, player.Data.Stats.Money.Value)
end)

Local Script

local player = game.Players.LocalPlayer
local remote = game.ReplicatedStorage.EarnMoney

player:WaitForChild("Data")
player.Data.Stats:WaitForChild("Money")
player:WaitForChild("Values")

MinSpeed = 15 --The player must be going faster than this in studs per second til they start earning money.

while wait(0.65) do
	if script.Parent == player.Character then
		if player.Values.CurrentVehicle.Value and player.PlayerGui.Phone.PhoneBody.OS.AppFrames.Vehicles.Values.CurrentVehicle.Value.DriveSeat.Occupant and player.PlayerGui.Phone.PhoneBody.OS.AppFrames.Vehicles.Values.CurrentVehicle.Value.DriveSeat.Occupant.Parent.Name == player.Name then
			remote:FireServer(0) -- amount of money earned
		end
	end
end

I would actually change your EarnMoney to a Remote Event rather than a Remote Function for this, unless you need the callback, in which case change "Fire" and "Event" to "Invoke".

3 comments

0

I recommend having the remote event and the datastore in separate scripts in case the datastore script gets messy as more is added as needed. Also, use sanity checks. Good answer Serpentine

1

Don't do this as you're giving too much trust to the client. Sanity checks sure but a mechanic where you're checking for the occupant of vehicle can be kept on the server easily.You also fire the RemoteEvent in an infinite loop to SetAsync which can exceed data limits. Saving should only be done in specific moments.

0

Sending DS requests for every single player every 0.65 seconds makes it super easy to hit the throttle limit, which can cause major data loss for the players in your game. To add, I think you have a typo; "player.PlayerGui.Phone.PhoneBody.OS.AppFrames.Vehicles.Values.CurrentVehicle.Val" appears twice in the same if statement on line 12.

So I have made some changes here and there as none of those suggestions helped me fix the problem.

So I have some new code that I like to share that might be of better help in helping me out.

First of all I have a ServerScript and the first few lines are for the money a new player starts with.

game:WaitForChild("ReplicatedStorage")
vs = game:GetService("ReplicatedStorage"):WaitForChild("VehicleSpawns")
ps = game:GetService("ReplicatedStorage"):WaitForChild("VehiclePurchases")
remove = game:GetService("ReplicatedStorage"):WaitForChild("RemoveCar")
sell = game:GetService("ReplicatedStorage"):WaitForChild("SellCar")
em = game:GetService("ReplicatedStorage"):WaitForChild("EarnMoney")
respawn = game:GetService("ReplicatedStorage"):WaitForChild("Respawn")
rd = game:GetService("ReplicatedStorage"):WaitForChild("ResetData")
data = game:GetService("ReplicatedStorage"):WaitForChild("Load")
ba = game:GetService("ReplicatedStorage"):WaitForChild("BA")

function rd.OnServerInvoke(plr)
	if plr:FindFirstChild("Data") and plr:FindFirstChild("Stats") then
		for _,child in pairs (plr.Data.Stats:GetChildren()) do
			if child.ClassName == "BoolValue" then
				if child.Name == "Fiat 500 Purchased" then
					child.Value = true
				else
					child.Value = false
				end
			end
			if child.Name == "Money" or child.Name == "PendingMoney" then
				child.Value = 32000
			end
		end
	end
	plr:LoadCharacter()
end

function ba.OnServerInvoke(plr)
	local hum = nil
	for _,child in pairs (plr.Character:GetChildren()) do
		if child.Name == "Humanoid" or child.Name == "PhotoMode" then
			hum = child
		end
		if child.ClassName == "Accessory" then
			if hum.Sit == true then
			if child.Handle:FindFirstChild("BodyBackAttachment") then
				child.Handle.Transparency = 1
			end
			else
				if child.Handle:FindFirstChild("BodyBackAttachment") then
				child.Handle.Transparency = 0
				end
			end
		end
	end
end

function data.OnServerInvoke(player)
player:WaitForChild("Data")
player:WaitForDataReady()
repeat wait() until player:FindFirstChild("Data")
if player.DataReady then
if player:findFirstChild("Data") then
local score = player.Data.Stats:GetChildren()
for i = 1,#score do
local ScoreLoaded = player:LoadNumber(score[i].Name)
wait()
if ScoreLoaded ~= 0 then
score[i].Value = ScoreLoaded
end
end
end
else
	if player:FindFirstChild("PlayerGui") and player.PlayerGui:FindFirstChild("Notification") then
		player.PlayerGui.Notification:WaitForChild("LocalNotification").Value = "Failed to load data. Please rejoin immediately."
	end
end
end

function respawn.OnServerInvoke(plr)
   plr:LoadCharacter()
   print(plr.Name.." has respawned.")
end

function em.OnServerInvoke(plr)
   if plr:FindFirstChild("Data") and plr.Data:FindFirstChild("Stats") and plr.Data.Stats:FindFirstChild("Money") and plr.Data.Stats:FindFirstChild("PendingMoney") then
   local M = plr.Data.Stats.Money
   M.Value = M.Value + plr.Character.HumanoidRootPart.Velocity.Magnitude / 2.5
   wait(0.25)
   if plr.Data.Stats.Money.Value > plr.Data.Stats.PendingMoney.Value + 4500 then
	plr.Data.Stats.Money.Value = plr.Data.Stats.PendingMoney.Value
   end
   wait()
   plr.Data.Stats.PendingMoney.Value = plr.Data.Stats.Money.Value
   end
end

Then I do have another ServerScript that does store all my data

Alpha = true

function onPlayerEntered(newPlayer)
	if not newPlayer:FindFirstChild("Data") then
	local d = Instance.new("Configuration")
	d.Name = "Data"
	d.Parent = newPlayer
	
	local stats = Instance.new("Folder")
	stats.Name = "Stats"
	stats.Parent = d

	local cash = Instance.new("IntValue")
	cash.Name = "Money"
	cash.Parent = stats
	cash.Value = 32000
	
	local pcash = Instance.new("IntValue")
	pcash.Name = "PendingMoney"
	pcash.Parent = stats
	pcash.Value = cash.Value
	
	local lang = Instance.new("StringValue")
	lang.Parent = stats
	lang.Value = "English"
	lang.Name = "Language"
	
	local alpha = Instance.new("BoolValue")
	alpha.Name = "AlphaPlayer"
	alpha.Value = false
	if Alpha == true then
		alpha.Value = true
	end
	alpha.Parent = stats

for _,child in pairs (game.Lighting.Vehicles:GetChildren()) do
	if stats:FindFirstChild(child.Name.." Purchased") then
		
	else
		local I = Instance.new("BoolValue")
		I.Parent = stats
		I.Name = child.Name.." Purchased"
		if child.Name == "Fiat 500" then
		I.Value = true
	else
		I.Value = false
		end
	end
end

	end
end

function leaving(player)
	if player.ClassName == "Player" then
if player:FindFirstChild("Data") and player.Data:FindFirstChild("Stats") and player.Data.Stats:FindFirstChild("Money") and player:FindFirstChild("Values") and player.Values:FindFirstChild("Leaving") then
	local saving = false
if player.Data.Stats.Money.Value == 32000 then
	error("Failed to save "..player.Name.."'s Data")
else
	if saving == false then
		saving = true
local score = player.Data.Stats:GetChildren()
for i = 1,#score do
player:SaveNumber(score[i].Name,score[i].Value)
end
print("Successfully saved "..player.Name.."'s Data")
saving = false
	end
	end
end
end
end

game:GetService("Players").PlayerRemoving:connect(leaving)
game:GetService("Players").ChildAdded:connect(onPlayerEntered)

and then there is the make money script which was the first request which gives the player new money.

I would love it if the DataStores the vehicles the player does own and the money the player has and that as soon as the player leaves the game his stats are being saved and he is able to continue with those the first time he joins again.

Atm the vehicles and money is getting wiped and as soon as the player rejoins he starts back with 32k Cash and has no cars anymore.

I really do love the support you guys gave me so far and hopefully you guys are able to help me fix this.

1 comment

0

I currently wanted to use the open sourced DataStore2 as I hoped that would solve my problem but it does not as well.

This discussion is preserved as it was. New answers, comments, and votes are closed.