Hey! I have been working on a game which requires the use of checkpoints and money, and of course I would like both to save with datastore considering the players leaving and rejoining.
function OnPlayerAdded(plr)
plr.CharacterAdded:Connect(OnCharacterAdded)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = plr
local stage = Instance.new("IntValue")
stage.Name = "Stage"
stage.Parent = stats
local money = Instance.new("IntValue")
money.Name = "Money"
money.Parent = stats
money.Value = 0
The issue is that I have not been able to do so when it comes to saving the money. I have found the perfect checkpoints and I cannot save both money and stages (checkpoints) without messing them up. Right now I don’t have the money value in any datastore, well because I haven’t been able to do so, and so I want to see if anyone knows a way to modify the script for both the checkpoints to be working and the money and stages value to save to the datastore:
local DS = game:GetService("DataStoreService"):GetDataStore("Shut")
local key = "id_" .. plr.userId
local data = DS:GetAsync(key)
if data then
stage.Value = data
TeleStage.Value = stage.Value
else
DS:GetAsync(key, stage)
end
end
game.Players.PlayerAdded:Connect(OnPlayerAdded)
function OnPlayerRemoved(plr)
local key = "id_" .. plr.userId
local data = plr.leaderstats.Stage.Value
DS:SetAsync(key, data)
end
game.Players.PlayerRemoving:Connect(OnPlayerRemoved)
local RS = game:GetService("ReplicatedStorage")
repeat wait() until script.Main ~= nil
local main = require(script.Main)
function recived(plr, direction)
if direction == "up" then
main.up(plr, direction)
elseif direction == "down" then
main.down(plr, direction)
elseif plr.Stages > main.TOTAL_STAGES_IN_GAME then
print("Player is in an older version of the game!")
end
end
RS.StageTransfer.OnServerEvent:Connect(recived)
I have been trying to figure out a way to make it so that this can all work for about 3-4 months now and I have spent countless hours watching tutorials and even trying to do it on my own (which didn’t work so well because I’m a beginner)
If anyone is willing to help, and would need more of the script or anything else let me know.
I decided to recode this portion of the original code:
local Players = game:GetService("Players");
local DataStorage = game:GetService("DataStoreService");
-- [[ Your data key, for DataStoreService;
local DataKey = DataStorage:GetDataStore("leaderstats");
local DefaultValues = {
["Stage"] = 0;
["Money"] = 0;
};
-- [[ Saves the data to a player, using tables.
function Save(ObjPlayer: Player)
local PlayerLeaderstats = ObjPlayer:FindFirstChild("leaderstats");
local Data = {
["Stage"] = PlayerLeaderstats:FindFirstChild("Stage").Value;
["Money"] = PlayerLeaderstats:FindFirstChild("Money").Value;
};
local _, na = pcall(function()
DataKey:SetAsync(ObjPlayer.UserId, Data);
end);
if na then
warn(na, ObjPlayer); -- This will run if an error occurs whilst loading or saving data.
end
end;
-- [[ Unpacks the data saved to a player.
function Load(ObjPlayer: Player)
local Data;
local _, na = pcall(function()
Data = DataKey:GetAsync(ObjPlayer.UserId);
end);
if Data == nil and type(Data) ~= "table" then
Data = DefaultValues; -- Adds the default values, to new players that have not been added to the database.
end; print(Data)
local stats = Instance.new("Folder");
stats.Name = "leaderstats";
stats.Parent = ObjPlayer;
local Stage = Instance.new("IntValue", stats);
Stage.Name = "Stage";
Stage.Value = Data[Stage.Name];
local Money = Instance.new("IntValue", stats);
Money.Name = "Money";
Money.Value = Data[Money.Name];
if na then
warn(na, ObjPlayer); -- This will run if an error occurs whilst loading or saving data.
end
end;
Players.PlayerAdded:Connect(Load)
Players.PlayerRemoving:Connect(Save)
Also, make sure you have API enabled for data storage in the first place.
The datastore works great, but how would I make it work with the checkpoints, when I tried to replace the old datastore with the new one, it doesn’t work I think I might be doing something wrong
It basically spawns me off the the checkpoints but with the stage value saved as 3
I put this part at the end of the script and I think I did this wrong because might need to add something there where it allows me to spawn on the checkpoints.
for _, v in pairs(workspace.Checkpoints:GetChildren()) do
v.Touched:Connect(function(hit)
if v ~= nil then
if v.Parent == workspace.Checkpoints then
local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if player then
if player.leaderstats.Stage.Value == tonumber(v.Name) - 1 then
player.leaderstats.Stage.Value += 1
player.TeleportedStage.Value = player.leaderstats.Stage.Value
end
end
end
end
end)
end
Make sure, it is only a one-way function and not a table function. [Not really important]
Third, make a CharacterAdded connection to the player & change the load function accordingly to this:
function Load(ObjPlayer: Player)
ObjPlayer.CharacterAdded:Connect(function(ObjModel: Model)
require(script.SpawnModule)(ObjPlayer, ObjModel);
end);
local Data;
local _, na = pcall(function()
Data = DataKey:GetAsync(ObjPlayer.UserId);
end);
if Data == nil and type(Data) ~= "table" then
Data = DefaultValues; -- Adds the default values, to new players that have not been added to the database.
end; print(Data)
local stats = Instance.new("Folder");
stats.Name = "leaderstats";
stats.Parent = ObjPlayer;
local Stage = Instance.new("IntValue", stats);
Stage.Name = "Stage";
Stage.Value = Data[Stage.Name];
local Money = Instance.new("IntValue", stats);
Money.Name = "Money";
Money.Value = Data[Money.Name];
if na then
warn(na, ObjPlayer); -- This will run if an error occurs whilst loading or saving data.
end
end;
Now, inside the spawning module there you will be able to set it to do whatever you so see fit.
For example, how I would do it is:
local Stages = workspace.Stages:GetChildren();
local function GetStage(StageNumber: number): Instance
local ToStage, HighestNumber = nil, 0;
for _, Inst in pairs(Stages) do if tonumber(Inst.Name) > HighestNumber then
HighestNumber = tonumber(Inst.Name);
end; -- Get the highest number, in table.
if tonumber(Inst.Name) == StageNumber then
ToStage = Inst;
end; -- Checks if a stage number matches the players stage number.
end
local Result;
if not ToStage and StageNumber > HighestNumber then
Result = Stages[HighestNumber];
elseif ToStage then
Result = ToStage;
end
return Result;
end;
return function(ObjPlayer: Player, ObjModel: Model)
local LeaderStats = ObjPlayer:WaitForChild("leaderstats", 1);
local StageNumber = LeaderStats:FindFirstChild("Stage").Value; -- Yes, I could've added another parameter with the players stats with.
local GetStage = GetStage(StageNumber);
local _, e1 = pcall(function()
task.spawn(function()
task.wait(1);
ObjModel:SetPrimaryPartCFrame(GetStage.CFrame * CFrame.new(Vector3.new(0, 5, 0)));
end);
end);
if e1 then
warn(ObjPlayer, e1);
end
end;