--|| Services ||--
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ServerStorage = game:GetService("ServerStorage")
local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local dataStore = DataStoreService:GetDataStore("Testing")
local TycoonCloneHolder = ServerStorage.TycoonCloneHolder
local TycoonsToDestroy = ServerStorage.TycoonsToDestroy
local TycoonSetup = ServerScriptService.TycoonSetup
local UpdateDeaths = ReplicatedStorage.RemoteEvents.UpdateDeath
local SetColorTheme = ServerScriptService.SetColorTheme
--|| Variables ||--
local requestAmount = 1
local TycoonsHolder = workspace.Tycoons
local TycoonTable = {}
--|| Functions ||--
local function waitForRequestBudget(requestType)
local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
while currentBudget < requestAmount do
currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
wait(5)
end
end
local function CharacterAdded(character, SpawnPos)
character.PrimaryPart.CFrame = SpawnPos.CFrame * CFrame.new(0,5,0)
print("Loaded character to their island!")
end
local function setUp(player)
local userId = player.UserId
local key = "Player_" .. userId
local StatsFolder = Instance.new("Folder")
StatsFolder.Name = "StatsFolder"
local BuildingsFolder = Instance.new("Folder")
BuildingsFolder.Name = "BuildingsFolder"
local SpecialPurchaseFolder = Instance.new("Folder")
SpecialPurchaseFolder.Name = "SpecialPurchaseFolder"
--// Stats to be saved \\--
local Cash = Instance.new("NumberValue")
Cash.Name = "Cash"
local OwnsTycoon = Instance.new("BoolValue")
OwnsTycoon.Name = "OwnsTycoon"
local TycoonSavedCash = Instance.new("NumberValue")
TycoonSavedCash.Name = "TycoonSavedCash"
local inGroup = Instance.new("BoolValue")
inGroup.Name = "inGroup"
local TimePlayed = Instance.new("NumberValue")
TimePlayed.Name = "TimePlayed"
local TotalMoneyEarned = Instance.new("NumberValue")
TotalMoneyEarned.Name = "TotalMoneyEarned"
local Kills = Instance.new("NumberValue")
Kills.Name = "Kills"
local Deaths = Instance.new("NumberValue")
Deaths.Name = "Deaths"
local OwnsAutoCollector = Instance.new("BoolValue")
OwnsAutoCollector.Name = "OwnsAutoCollector"
local OwnsColorChanger = Instance.new("BoolValue")
OwnsColorChanger.Name = "OwnsColorChanger"
local Owns2xCash = Instance.new("BoolValue")
Owns2xCash.Name = "Owns2xCash"
local ColorTheme1 = Instance.new("Color3Value")
ColorTheme1.Name = "ColorTheme1"
local ColorTheme2 = Instance.new("Color3Value")
ColorTheme2.Name = "ColorTheme2"
local ColorTheme3 = Instance.new("Color3Value")
ColorTheme3.Name = "ColorTheme3"
--|| Stats to not be saved ||--
local PlayerBools = Instance.new("Folder")
PlayerBools.Name = "PlayerBools"
PlayerBools.Parent = player
local AlreadyOwnsTycoon = Instance.new("BoolValue")
AlreadyOwnsTycoon.Name = "AlreadyOwnsTycoon"
AlreadyOwnsTycoon.Parent = PlayerBools
local TouchedAirDrop = Instance.new("BoolValue")
TouchedAirDrop.Name = "TouchedAirDrop"
TouchedAirDrop.Value = false
TouchedAirDrop.Parent = PlayerBools
local CurrentTycoon = Instance.new("StringValue")
CurrentTycoon.Name = "CurrentTycoon"
CurrentTycoon.Parent = PlayerBools
local success, returnValue
repeat
waitForRequestBudget(Enum.DataStoreRequestType.GetAsync)
success, returnValue = pcall(dataStore.GetAsync, dataStore, key)
until success or not Players:FindFirstChild(player.Name)
if success then
if returnValue == nil then
print("Player has no data!")
returnValue = {
Cash = 0,
OwnsTycoon = false,
TycoonSavedCash = 0,
inGroup = false,
TimePlayed = 0,
TotalMoneyEarned = 0,
Kills = 0,
Deaths = 0,
OwnsAutoCollector = false,
OwnsColorChanger = false,
Owns2xCash = false,
ColorTheme1 = Color3.fromRGB(91, 154, 76),
ColorTheme2 = Color3.fromRGB(51, 88, 130),
ColorTheme3 = Color3.fromRGB(17, 17, 17),
}
end
--// Loads all the player's saved data from returnValue in DataStore
Cash.Value = returnValue["Cash"] or 0
OwnsTycoon.Value = returnValue["OwnsTycoon"] or false
TycoonSavedCash.Value = returnValue["TycoonSavedCash"] or 0
inGroup.Value = returnValue["inGroup"] or false
TimePlayed.Value = returnValue["TimePlayed"] or 0
TotalMoneyEarned.Value = returnValue["TotalMoneyEarned"] or 0
Kills.Value = returnValue["Kills"] or 0
Deaths.Value = returnValue["Deaths"] or 0
OwnsAutoCollector.Value = returnValue["OwnsAutoCollector"] or false
OwnsColorChanger.Value = returnValue["OwnsColorChanger"] or false
Owns2xCash.Value = returnValue["Owns2xCash"] or false
ColorTheme1.Value = Color3.new(returnValue["ColorTheme1"].R, returnValue["ColorTheme1"].G, returnValue["ColorTheme1"].B) or Color3.fromRGB(91, 154, 76)
ColorTheme2.Value = Color3.new(returnValue["ColorTheme2"].R, returnValue["ColorTheme2"].G, returnValue["ColorTheme2"].B) or Color3.fromRGB(51, 88, 130)
ColorTheme3.Value = Color3.new(returnValue["ColorTheme3"].R, returnValue["ColorTheme3"].G, returnValue["ColorTheme3"].B) or Color3.fromRGB(17, 17, 17)
if returnValue["Building"] ~= nil then
for _, building in pairs(returnValue["Building"]) do
if building ~= nil and type(building) == "string" then
local createdBuilding = Instance.new("StringValue")
createdBuilding.Name = building
createdBuilding.Value = building
createdBuilding.Parent = BuildingsFolder
end
end
end
if returnValue["SpecialPurchase"] ~= nil then
for _, purchase in pairs(returnValue["SpecialPurchase"]) do
if purchase ~= nil and type(purchase) == "string" then
local savedPurchase = Instance.new("StringValue")
savedPurchase.Name = purchase
savedPurchase.Value = purchase
savedPurchase.Parent = SpecialPurchaseFolder
end
end
end
--// Parent the values into their respective folders
Cash.Parent = StatsFolder
OwnsTycoon.Parent = StatsFolder
TycoonSavedCash.Parent = StatsFolder
inGroup.Parent = StatsFolder
TimePlayed.Parent = StatsFolder
TotalMoneyEarned.Parent = StatsFolder
Kills.Parent = StatsFolder
Deaths.Parent = StatsFolder
OwnsAutoCollector.Parent = StatsFolder
OwnsColorChanger.Parent = StatsFolder
Owns2xCash.Parent = StatsFolder
ColorTheme1.Parent = StatsFolder
ColorTheme2.Parent = StatsFolder
ColorTheme3.Parent = StatsFolder
StatsFolder.Parent = player
BuildingsFolder.Parent = player
SpecialPurchaseFolder.Parent = player
print("Data was loaded for player.")
coroutine.wrap(function()
while task.wait(1) do
TimePlayed.Value += 1
end
end)()
for _, Tycoon in pairs(TycoonsHolder:GetChildren()) do
if Tycoon:FindFirstChild("Occupied").Value == false then
if not table.find(TycoonTable, player.Name) then
Tycoon:FindFirstChild("Occupied").Value = true
table.insert(TycoonTable, player.Name)
print(TycoonTable)
local Components = Tycoon:FindFirstChild("Components")
local Tycoon_Owner = Tycoon:FindFirstChild("TycoonOwner")
local Cash_To_Collect = Tycoon:FindFirstChild("CashToCollect")
local Owner = Tycoon:FindFirstChild("Owner")
local PlayerPicture = Components:FindFirstChild("PlayerPicture"):FindFirstChild("ImageLabel")
local Claimpad = Components:FindFirstChild("Claim Pad")
local Claim = Claimpad:FindFirstChild("Pad")
local Current_Owner = Claimpad:FindFirstChild("Gui"):FindFirstChild("CurrentOwner")
local userId = player.UserId
local thumbType = Enum.ThumbnailType.HeadShot
local thumbSize = Enum.ThumbnailSize.Size420x420
local content, isReady = Players:GetUserThumbnailAsync(userId, thumbType, thumbSize)
Owner.Value = player.Name
Tycoon_Owner.Value = player
PlayerPicture.Image = content
Current_Owner.Text = "Owner: "..tostring(Tycoon_Owner.Value)
player.RespawnLocation = Components:FindFirstChild("Spawn")
CurrentTycoon.Value = Tycoon.Name
local char = player.Character or player.CharacterAdded:Wait()
if char then
CharacterAdded(char, Components:FindFirstChild("Spawn"))
end
if OwnsTycoon.Value == false then
OwnsTycoon.Value = true
print("New tycoon!")
elseif OwnsTycoon.Value == true then
Cash_To_Collect.Value = StatsFolder.TycoonSavedCash.Value
TycoonSetup:Fire(Tycoon.Name, player)
SetColorTheme:Fire(Tycoon, ColorTheme1.Value, ColorTheme2.Value, ColorTheme3.Value)
print("Loading tycoon info.")
end
end
end
end
else
warn("There was an error!" .. returnValue)
end
end
local function save(player, dontWait)
local userId = player.UserId
local key = "Player_" .. userId
local StatsFolder = player:FindFirstChild("StatsFolder")
local BuildingsFolder = player:FindFirstChild("BuildingsFolder")
local SpecialPurchaseFolder = player:FindFirstChild("SpecialPurchaseFolder")
if StatsFolder then
local Building;
local SpecialPurchase;
local CT1 = {}
CT1.R = StatsFolder.ColorTheme1.Value.R
CT1.G = StatsFolder.ColorTheme1.Value.G
CT1.B = StatsFolder.ColorTheme1.Value.B
local CT2 = {}
CT2.R = StatsFolder.ColorTheme2.Value.R
CT2.G = StatsFolder.ColorTheme2.Value.G
CT2.B = StatsFolder.ColorTheme2.Value.B
local CT3 = {}
CT3.R = StatsFolder.ColorTheme3.Value.R
CT3.G = StatsFolder.ColorTheme3.Value.G
CT3.B = StatsFolder.ColorTheme3.Value.B
local StatsTable = {
Cash = StatsFolder.Cash.Value,
OwnsTycoon = StatsFolder.OwnsTycoon.Value,
TycoonSavedCash = StatsFolder.TycoonSavedCash.Value,
inGroup = StatsFolder.inGroup.Value,
TimePlayed = StatsFolder.TimePlayed.Value,
TotalMoneyEarned = StatsFolder.TotalMoneyEarned.Value,
Kills = StatsFolder.Kills.Value,
Deaths = StatsFolder.Deaths.Value,
OwnsAutoCollector = StatsFolder.OwnsAutoCollector.Value,
OwnsColorChanger = StatsFolder.OwnsColorChanger.Value,
Owns2xCash = StatsFolder.Owns2xCash.Value,
ColorTheme1 = CT1,
ColorTheme2 = CT2,
ColorTheme3 = CT3,
Building = {},
SpecialPurchase = {},
}
if #BuildingsFolder:GetChildren() ~= 0 then
for _, building in pairs(BuildingsFolder:GetChildren()) do
table.insert(StatsTable.Building, building.Name)
end
end
if #SpecialPurchaseFolder:GetChildren() ~= 0 then
for _, purchase in pairs(SpecialPurchaseFolder:GetChildren()) do
table.insert(StatsTable.SpecialPurchase, purchase.Name)
end
end
local success, returnValue
repeat
if not dontWait then
waitForRequestBudget(Enum.DataStoreRequestType.SetIncrementAsync)
end
success, returnValue = pcall(dataStore.SetAsync, dataStore, key, StatsTable)
until success
if success then
print("Data was saved successfully.")
else
print("There was an error! " .. returnValue)
end
end
end
local function onShutdown()
if RunService:IsStudio() then
wait(2)
else
local finished = Instance.new("BindableEvent")
local allPlayers = Players:GetPlayers()
local leftPlayers = #allPlayers
for _, player in ipairs(allPlayers) do
coroutine.wrap(function()
save(player)
leftPlayers -= 1
if leftPlayers == 0 then
finished:Fire()
end
end)()
end
finished.Event:Wait()
end
end
local function DeleteTycoon(player)
print(player.Name.." has left the game!")
for _, Tycoon in pairs(TycoonsHolder:GetChildren()) do
local TycoonOwner = Tycoon:FindFirstChild("TycoonOwner").Value
local CashToSave = Tycoon:FindFirstChild("CashToCollect")
if TycoonOwner then
if TycoonOwner == player then
local StatsFolder = player:FindFirstChild("StatsFolder")
local TycoonSavedCash = StatsFolder:FindFirstChild("TycoonSavedCash")
TycoonSavedCash.Value = CashToSave.Value
local StatsFolder = player:FindFirstChild("StatsFolder")
local TimePlayed = StatsFolder:FindFirstChild("TimePlayed")
Tycoon:Destroy()
TycoonCloneHolder:FindFirstChild(Tycoon.Name).Parent = TycoonsHolder
print(player.Name.." has left the game. Successfully destroyed their tycoon!")
end
end
end
end
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(setUp)(player)
end
Players.PlayerAdded:Connect(function(player)
print(player.Name.." has joined the experience!")
delay(1, function()
setUp(player)
end)
end)
Players.PlayerRemoving:Connect(function(player)
table.remove(TycoonTable, TycoonTable[player.Name])
DeleteTycoon(player)
save(player)
print(TycoonTable)
print(player.Name.. " has left the experience!")
end)
game:BindToClose(onShutdown)
UpdateDeaths.OnServerEvent:Connect(function(player)
local StatsFolder = player:FindFirstChild("StatsFolder")
local Deaths = StatsFolder:FindFirstChild("Deaths")
Deaths.Value += 1
end)
while true do
wait(300)
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(save)(player)
end
print("Data has been auto-saved.")
end
Hello I’m currently working on a tycoon game and have followed a beginner Datastore Tutorial from the devforum. Currently, everything works as intended however I do receive datastore throttling queues when the player leaves after an autosave has already occurred. So I believe it saves twice. (There are 8 players per server). I have few questions:
- Should I just have autosave be the main way of saving data and not have saving on leaving?
- How can I prevent queue throttling and does it save data after it finishes queuing or does it completely void the saving?
- Should I be worried about it throttling and adding the requests to the queue?
- Lastly, how could I possibly improve my code?
Thank you!