I am making my first game; a sword simulator, and am having a hard time waiting for everything to load in from the instances I make in the datastore script. Among others, I have a damage instance with the players base damage on it, and every weapon gets this instance every time it attacks. I also have a gamepass for double damage that also needs to be checked in the weapon’s scripts. This results in a lot of error codes when the data fails to load everything fast enough.
For now I have been using fx:
repeat task.wait()
until player. Damage.Value ~= nil
or just plain:
task.wait(5)
but I am worried that this slows the game significantly or just isn’t error proof.
Could it be an idea to create a damage value instance in each weapon and sync the value on that? That way the weapon wouldn’t have to get the damage from the player every time it reloads because the player dies.
– Update to show scripts:
Datastore
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local DatastoreService = game:GetService("DataStoreService")
local DataBase = DatastoreService:GetDataStore("data") -- all data that is saved (I changed the name because error in saved data)
local sessionData = {} -- data that is currently in the game (depending on the players present)
function playerAdded(player)
-- finding humanoid from player
while true do wait()
if player.Character or player.CharacterAdded:Wait() then break end
end
local humanoid = player.Character:WaitForChild("Humanoid")
-- creating empty instances under the added player
local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"
local Kills = Instance.new("IntValue", leaderstats) -- creating intvalue for amount of kills
Kills.Name = "Kills"
local Skulls = Instance.new("IntValue", player)
Skulls.Name = "Skulls"
-- Map wins
local MountainWins = Instance.new("IntValue", player)
MountainWins.Name = "MountainWins"
local IslesWins = Instance.new("IntValue", player)
IslesWins.Name = "IslesWins"
local Wins = Instance.new("IntValue", leaderstats) -- doesn't need saving
Wins.Name = "Wins"
Wins.Value = MountainWins.Value + IslesWins.Value
-- damage and health stats
local Damage = Instance.new("NumberValue", player)
Damage.Name = "Damage"
local Health = Instance.new("IntValue", player)
Health.Name = "Health"
-- Weapons owned
local LumberAxeOwned = Instance.new("BoolValue", player)
LumberAxeOwned.Name = "LumberAxeOwned"
local TheOarOwned = Instance.new("BoolValue", player)
TheOarOwned.Name = "TheOarOwned"
local success = nil
local playerData = nil
local attempt = 1
repeat -- trying to get the data a couple of times
success, playerData = pcall(function() -- making sure game gets the data
return DataBase:GetAsync(player.UserId) -- getting any data with the right ID
end)
attempt += 1
if not success then
warn(playerData)
task.wait(3)
end
until success or attempt == 5
if success then
if not playerData then -- checking if the playerdata is empty: this is a new player
-- default playerdata
playerData = {
["kills"] = 0,
["skulls"] = 0,
["mountainwins"] = 0,
["isleswins"] = 0,
["damage"] = 5,
["health"] = 100,
["lumberaxeowned"] = false,
["theoarowned"] = false,
}
end
sessionData[player.UserId] = playerData -- if not new player, set saved data
else
warn("Unable to get data for", player.UserId)
player:Kick("Unable to load data. Try again later") -- kick player if game doesn't find the players data
end
-- first connecting the empty instances with the data saved on datastoes
-- afterwards, when the instances values changes midgame, the stores will save it
Kills.Value = sessionData[player.UserId].kills
Kills.Changed:Connect(function() -- if amount of kills change, sync values
sessionData[player.UserId].kills = Kills.Value
end)
Skulls.Value = sessionData[player.UserId].skulls
Skulls.Changed:Connect(function()
sessionData[player.UserId].skulls = Skulls.Value
end)
MountainWins.Value = sessionData[player.UserId].mountainwins
MountainWins.Changed:Connect(function()
sessionData[player.UserId].mountainwins = MountainWins.Value
Wins.Value = MountainWins.Value + IslesWins.Value
end)
IslesWins.Value = sessionData[player.UserId].isleswins
IslesWins.Changed:Connect(function()
sessionData[player.UserId].isleswins = IslesWins.Value
Wins.Value = MountainWins.Value + IslesWins.Value
end)
Wins.Value = MountainWins.Value + IslesWins.Value -- update on change in above functions
Damage.Value = sessionData[player.UserId].damage
Damage.Changed:Connect(function()
sessionData[player.UserId].damage = Damage.Value
end)
Health.Value = sessionData[player.UserId].health
Health.Changed:Connect(function()
sessionData[player.UserId].health = Health.Value
end)
LumberAxeOwned.Value = sessionData[player.UserId].lumberaxeowned
LumberAxeOwned.Changed:Connect(function()
sessionData[player.UserId].lumberaxeowned = LumberAxeOwned.Value
end)
TheOarOwned.Value = sessionData[player.UserId].theoarowned
TheOarOwned.Changed:Connect(function()
sessionData[player.UserId].theoarowned = TheOarOwned.Value
end)
end
Players.PlayerAdded:Connect(playerAdded)
function playerLeaving(player)
if sessionData[player.UserId] then -- checking if the player has any data saved, otherwise can lead to data loss
local success = nil
local errorMsg = nil
local attempt = 1
repeat -- trying to get the data a couple of times
success, errorMsg = pcall(function() -- to make sure the game finds the data that is to be saved
DataBase:SetAsync(player.UserId, sessionData[player.UserId]) -- if there is data to save, data will be saved to player
end)
attempt += 1
if not success then
warn(errorMsg)
task.wait(3)
end
until success or attempt == 5
if success then
print("Data saved for", player.Name)
else
warn("Unable to save for", player.Name)
end
end
end
Players.PlayerRemoving:Connect(playerLeaving)
function serverShutDown() -- in case of a server shutdown
if RunService:IsStudio() then
return
end
print("server shutting down")
for i, player in pairs(Players:GetPlayers()) do
task.spawn(function()
playerLeaving(player)
end)
end
end
game:BindToClose(serverShutDown)
Loading gear:
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- give items and remove skulls when buying in the gui
ReplicatedStorage.GiveWeapon.OnServerEvent:Connect(function(player, args)
local Skulls = player:FindFirstChild("Skulls")
local LumberAxeOwned = player:FindFirstChild("LumberAxeOwned")
local TheOarOwned = player:FindFirstChild("TheOarOwned")
if args == "BuyingAxe" then
Skulls.Value -= 15
LumberAxeOwned.Value = true
local AxeCopy = ServerStorage.LumberAxe:Clone()
AxeCopy.Parent = player.Backpack
end
if args == "BuyingOar" then
Skulls.Value -= 15
TheOarOwned.Value = true
local OarCopy = ServerStorage.TheOAR:Clone()
OarCopy.Parent = player.Backpack
end
end)
Players.PlayerAdded:Connect(function(player) -- give players stuff they have already bought
-- all about the gamepasses
local DoubleDamageOwned = Instance.new("BoolValue", player)
DoubleDamageOwned.Name = "DoubleDamageOwned"
DoubleDamageOwned.Value = false
local DoubleHealthOwned = Instance.new("BoolValue", player)
DoubleHealthOwned.Name = "DoubleHealthOwned"
DoubleHealthOwned.Value = false
if MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690312761) then -- double damage
DoubleDamageOwned.Value = true
end
if MarketplaceService:UserOwnsGamePassAsync(player.UserId, 694696047) then -- double health
DoubleHealthOwned.Value = true
end
player.CharacterAdded:Connect(function()
task.wait(3)
-- all about the weapons
-- connect to gui to fill inventory when the player already owns weapon
-- copy to backpack for weapon now, copy to startergear for weapon after respawn or death
if player:WaitForChild("LumberAxeOwned").Value == true then
local LumberAxe = ServerStorage:FindFirstChild("LumberAxe"):Clone()
LumberAxe.Parent = player.Backpack
ReplicatedStorage.GiveWeapon:FireClient(player, "LumberAxe")
end
if player:WaitForChild("TheOarOwned").Value == true then
local TheOar = ServerStorage:FindFirstChild("TheOAR"):Clone()
TheOar.Parent = player.Backpack
ReplicatedStorage.GiveWeapon:FireClient(player, "TheOar")
end
-- checks to see if new players own an object gamepass and gives them their item on entry
task.wait(1)
local OwnsSpeed = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690123446)
if OwnsSpeed then -- returned true
local SpeedCoil = game.ServerStorage:WaitForChild("SpeedCoil"):Clone()
SpeedCoil.Parent = player.Backpack
end -- no need for an else
local OwnsGravity = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690360123)
if OwnsGravity then
local GravityCoil = game.ServerStorage:WaitForChild("GravityCoil"):Clone()
GravityCoil.Parent = player.Backpack
end
local OwnsFusion = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 690434007)
if OwnsGravity then
local FusionCoil = game.ServerStorage:WaitForChild("FusionCoil"):Clone()
FusionCoil.Parent = player.Backpack
end
end)
end)
SwordScript:
local tool = script.Parent
local Players = game:GetService("Players")
local player = tool.Parent.Parent -- owner of tool
local Debris = game:GetService("Debris")
local candmg = false
-- adding and removing creatortag
function TagHumanoid(humanoid, player)
local Creator_Tag = Instance.new("ObjectValue")
Creator_Tag.Name = "creator"
Creator_Tag.Value = player
Debris:AddItem(Creator_Tag, 2) -- removes tag after two seconds!
Creator_Tag.Parent = humanoid
end
function UntagHumanoid(humanoid)
for i, v in pairs(humanoid:GetChildren()) do
if v:IsA("ObjectValue") and v.Name == "creator" then
v:Destroy()
end
end
end
function determineDamage()
repeat task.wait()
until player.DoubleDamageOwned ~= nil
local DoubleDamageOwned = player.DoubleDamageOwned
if DoubleDamageOwned.Value == true then
x = 2 else x = 1
end
return x
end
tool.Head.Touched:Connect(function(hit)
if candmg then
local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
repeat task.wait()
until player:FindFirstChild("Damage") ~= nil
local Damage = player:FindFirstChild("Damage")
determineDamage() -- returns with x and y
humanoid:TakeDamage(Damage.Value * x)
tool.Head.Hit:Play()
candmg = false
-- tagging hit player
UntagHumanoid(humanoid)
TagHumanoid(humanoid, player)
end
end
end)
tool.Client.Attack.OnServerEvent:Connect(function()
if not candmg then
candmg = true
wait(.2)
tool.Head.Woosh:Play()
tool.Head.Woosh.Ended:Wait()
candmg = false
end
end)