I’m working on an obby game, and I’m trying to fetch the player’s leaderstats when they join the game. However, it often fails to retrieve the data, resulting in an error that unfortunately breaks my entire script. Since I’m running this on the server, it immediately stops for the entire server.
When you join the game for the first time, it works as expected. But when you quickly leave and rejoin the game, the problems start to appear.
Helpful to know: I’m using ProfileService, ReplicaService, and Knit (Knit is only used in the datastore code). For anyone that will be-able to make this fail-proof, you are a life-saver.
The problem lies here.
players.PlayerAdded:Connect(function(player)
local plot = findSmallestPlot()
if plot then
assignPlotToPlayer(player, plot)
spawnPlayerOnPlot(player, plot)
handleStageObject(player, plot)
end
player.CharacterRemoving:Connect(function(Character)
task.defer(Character.Destroy, Character)
end)
task.wait(5)
local Stage = player:WaitForChild("leaderstats").Stage -- Here (You see task.wait() cuz i've been trying to fix this)
Stage.Changed:Connect(function(newValue)
placePlayerBack(player, plot)
stageChanged(player, plot)
end)
end)
This is the entire code:
local PhysicsService = game:GetService("PhysicsService")
PhysicsService:RegisterCollisionGroup("Character")
PhysicsService:RegisterCollisionGroup("OwnerStage")
PhysicsService:CollisionGroupSetCollidable("Character", "OwnerStage", true)
local serverScriptService = game:GetService("ServerScriptService")
local replicatedStorage = game:GetService("ReplicatedStorage")
local players = game:GetService("Players")
local DataService = require(serverScriptService.Services.DataService)
local Manager = require(serverScriptService.Services.DataService.Data)
local Plots = workspace.Obby.Platforms
local Debounce = false
local playerDebounce = {}
-- Character Cancollide
local function setCharacterCollisionGroup(descendant)
if descendant:IsA("BasePart") and descendant.Parent:IsA("Character") then
descendant.CollisionGroup = "Character"
end
end
local function playerReplica(player, plot)
DataService:GetReplica(player):andThen(function(playerDataReplica)
local playerStage = playerDataReplica.Data.Stage
local currentStage = replicatedStorage.obbyStages.DCO:FindFirstChild(playerStage)
if currentStage then
local clonedStage = currentStage:Clone()
clonedStage.Name = "ClonedStage"
clonedStage:PivotTo(plot.Platform:FindFirstChild("StartPart").CFrame)
clonedStage.Parent = plot.Platform.Stage
end
end)
end
-- Finds the smallest available plot
local function findSmallestPlot()
local smallestPlot = nil
local smallestPlotNumber = math.huge
for _, plot in ipairs(Plots:GetChildren()) do
if plot:GetAttribute("Taken") then continue end
local plotNumber = tonumber(plot.Name)
if plotNumber and plotNumber < smallestPlotNumber then
smallestPlot = plot
smallestPlotNumber = plotNumber
end
end
return smallestPlot
end
-- Assigns a plot to a player and spawns their stage
local function assignPlotToPlayer(player, plot)
plot:SetAttribute("Taken", true)
plot:SetAttribute("Owner", player.UserId)
playerReplica(player, plot)
end
-- Spawns a player on their assigned plot and sets up collision groups
local function spawnPlayerOnPlot(player, plot)
player.CharacterAdded:Connect(function(character)
character:PivotTo(plot.Platform.StartPosition.CFrame * CFrame.new(0, 3, 0))
for _, descendant in character:GetDescendants() do
setCharacterCollisionGroup(descendant)
end
character.DescendantAdded:Connect(setCharacterCollisionGroup)
end)
end
-- Removes a player from their plot and cleans up
local function removePlayerFromPlot(player)
for _, plot in Plots:GetChildren() do
if plot:GetAttribute("Owner") == player.UserId then
plot:SetAttribute("Taken", nil)
plot:SetAttribute("Owner", nil)
for _, child in plot.Platform.Stage:GetChildren() do
if child.Name == "ClonedStage" then
child:Destroy()
break
end
end
print("Plot has been removed from " .. player.Name .. "!") -- On release verwijderen
end
end
end
local function handleStageObject(player, plot)
local stageFolder = plot:WaitForChild("Platform").Stage
local currentConnection
stageFolder.ChildAdded:Connect(function(instance)
local endPosition = instance:FindFirstChild("EndPosition")
if endPosition then
if currentConnection then
currentConnection:Disconnect()
end
currentConnection = endPosition.Touched:Connect(function(hit)
local hitPlayer = players:GetPlayerFromCharacter(hit.Parent)
if not hitPlayer then return end
if playerDebounce[hitPlayer.UserId] then
return
end
if plot:GetAttribute("Owner") == hitPlayer.UserId then
print(hitPlayer.UserId)
print(hitPlayer.Name)
playerDebounce[hitPlayer.UserId] = true
local profile = Manager.Profiles[player]
if not profile then return end
local leaderstatStage = player:WaitForChild("leaderstats").Stage
profile.Data.Stage += 1
leaderstatStage.Value = profile.Data.Stage
task.wait(0.5)
playerDebounce[hitPlayer.UserId] = nil
end
end)
end
end)
end
local function stageChanged(player, plot)
for _, child in plot.Platform.Stage:GetChildren() do
if child.Name == "ClonedStage" then
child:Destroy()
break
end
end
playerReplica(player, plot)
end
local function placePlayerBack(player, plot)
player.Character:PivotTo(plot.Platform.StartPosition.CFrame * CFrame.new(0, 3, 0))
end
-- Main logic
players.PlayerAdded:Connect(function(player)
local plot = findSmallestPlot()
if plot then
assignPlotToPlayer(player, plot)
spawnPlayerOnPlot(player, plot)
handleStageObject(player, plot)
end
player.CharacterRemoving:Connect(function(Character)
task.defer(Character.Destroy, Character)
end)
task.wait(5)
local Stage = player:WaitForChild("leaderstats").Stage
Stage.Changed:Connect(function(newValue)
placePlayerBack(player, plot)
stageChanged(player, plot)
end)
end)
players.PlayerRemoving:Connect(function(player)
removePlayerFromPlot(player)
task.defer(player.Destroy, player)
end)