I am trying to do a system like Grow A Garden Offline but for my game. The purpose of my Offline system is that Swords will keep running in the Anvil. When the Swords are offline and the player comeback it does some weird behavior in which the ScrollingFrame are getting frozen and the cooldown stops running.
Here’s the code of the player when he comes back in the game :
if #playerData.OfflineSwords > 0 then
if not DataLoaded[player.UserId] then
print("DATA LOADED IS : ", DataLoaded[player.UserId])
DataLoaded[player.UserId] = true
local TotalTimeTextLabel = playerPlot.Forge:FindFirstChild(AnvilOwned):FindFirstChild(AnvilOwned).Description.Frame:FindFirstChild("Total Time")
local TimeLeftCooldown = CurrentTime - LastTimePlayerOnline
local elapsed = TimeLeftCooldown
for index, sword in ipairs(playerData.OfflineSwords) do
local sword = playerData.OfflineSwords[index]
if index <= NumberRunningSwordAllowed then
if elapsed >= sword.Countdown then
sword.Countdown = 0
sword.IsFinished = true
sword.IsRunning = false
local RackService = require(ServerScriptService:WaitForChild("Services"):WaitForChild("RackService"))
local MoneyService = require(ServerScriptService:WaitForChild("Services"):WaitForChild("MoneyService"))
local function getSwordMultiplier(level)
return 0.05 * level^2 + 0.35 * level + 1.3
end
local ChoosenModel = nil
local TotalWeaponAvailable = 0
local CraftedItem = sword.Name
local lowestId = math.huge
for _, model in playerPlot.Ground.Objects:GetChildren() do
if string.find(model.Name, "Sword holder") then
local curAmount = model:GetAttribute("Amount")
local maxAmount = model:GetAttribute("MaxAmount")
local holderId = model:GetAttribute("HolderId")
TotalWeaponAvailable += maxAmount
-- Si le rack a encore de la place et que son HolderId est plus petit que le plus bas trouvé
if (maxAmount - curAmount) > 0 and holderId < lowestId then
lowestId = holderId
ChoosenModel = model
end
end
end
local rawPrice = Material.Prices[sword.Material] * getSwordMultiplier(sword.Level)
local selectedTeleportedPart = nil
local lowestRank = math.huge
for i = 1, ChoosenModel:GetAttribute("MaxAmount") do
local swordName = "Sword" .. i .. "Location"
local part = ChoosenModel:FindFirstChild("SwordHolder"):FindFirstChild(swordName)
if part and part:GetAttribute("Availability") then
local rank = part:GetAttribute("Rank")
if rank and rank < lowestRank then
lowestRank = rank
selectedTeleportedPart = part
end
end
end
local playerData = DataService.getData(player)
if playerData then
local holder = playerData.Holders
local IdHolderChoosen = 0
local lowestId = math.huge -- on part de l'infini pour comparer
for _, model in playerPlot.Ground.Objects:GetChildren() do
if string.find(model.Name, "Sword holder") then
local curAmount = model:GetAttribute("Amount")
local maxAmount = model:GetAttribute("MaxAmount")
local holderId = model:GetAttribute("HolderId")
-- Si le rack a encore de la place et que son HolderId est plus petit que le plus bas trouvé
if (maxAmount - curAmount) > 0 and holderId < lowestId then
lowestId = holderId
IdHolderChoosen = holderId
end
end
end
holder["Holder" .. IdHolderChoosen][sword.Material .. " " .. CraftedItem .. string.match(selectedTeleportedPart.Name, "%d+")] = {
Count = 1,
Name = CraftedItem,
MaterialName = sword.Material,
PositionPart = selectedTeleportedPart.Name,
Price = math.floor(rawPrice * 100 + 0.5) / 100,
Level = sword.Level
}
RackService.createNewSword(player, "Holder" .. IdHolderChoosen, sword.Material .. " " .. CraftedItem .. string.match(selectedTeleportedPart.Name, "%d+"))
end
-- 6. Donner l'XP et réorganiser l'ordre
local amountExpGiven = LevelSystem.getExpMaterial(sword.Material .. " Ingot")
LevelSystem.givePlayerExp(player, amountExpGiven)
local LevelService = require(ServerScriptService:WaitForChild("Services"):WaitForChild("LevelService"))
LevelService.increaseExp(player, amountExpGiven)
MoneyService.giveForgePoint(player, sword.Level + 1)
local OrderCrafting = 0
for _, f in ipairs(playerPlot.Forge:FindFirstChild(AnvilOwned):FindFirstChild(AnvilOwned).BillboardGui.Frame.ScrollingFrame:GetChildren()) do
if f:IsA("Frame") then
local img = f:FindFirstChild("ImageLabel")
if img then
OrderCrafting += 1
img:SetAttribute("LayoutOrder", OrderCrafting)
end
end
end
else
local CloneFrame = UIsSword.ScreenGui:FindFirstChild(sword.Name):Clone()
CloneFrame.Parent = playerPlot.Forge:FindFirstChild(AnvilOwned):FindFirstChild(AnvilOwned).BillboardGui.Frame.ScrollingFrame
local ImageLabel = CloneFrame.ImageLabel
sword.Countdown -= elapsed
ImageLabel.Timer.Text = FormatTime(sword.Countdown, true)
ImageLabel:SetAttribute("LayoutOrder", index)
ImageLabel:SetAttribute("Countdown", sword.Countdown)
ImageLabel:SetAttribute("Material", sword.Material)
ImageLabel:SetAttribute("Level", sword.Level)
ImageLabel:SetAttribute("IsFinished", sword.IsFinished)
ImageLabel:SetAttribute("IsRunning", sword.IsRunning)
end
else
local CloneFrame = UIsSword.ScreenGui:FindFirstChild(sword.Name):Clone()
CloneFrame.Parent = playerPlot.Forge:FindFirstChild(AnvilOwned):FindFirstChild(AnvilOwned).BillboardGui.Frame.ScrollingFrame
local ImageLabel = CloneFrame.ImageLabel
sword.Countdown -= elapsed
ImageLabel.Timer.Text = FormatTime(sword.Countdown, true)
ImageLabel:SetAttribute("LayoutOrder", index)
ImageLabel:SetAttribute("Countdown", sword.Countdown)
ImageLabel:SetAttribute("Material", sword.Material)
ImageLabel:SetAttribute("Level", sword.Level)
ImageLabel:SetAttribute("IsFinished", sword.IsFinished)
ImageLabel:SetAttribute("IsRunning", sword.IsRunning)
end
TotalTime += sword.Countdown
end
TotalTimeTextLabel.Text = "TOTAL TIME: " .. FormatTime(TotalTime, false)
print("CURRENT NUMBER RUNNING WEAPON RIGHT NOW IS : ", CurrentNumberRunningWeapon)
end
end
It doesn’t count well the number of running weapon either. Here’s the code that count the number of weapon :
local scrollingFrame = playerPlot.Forge:FindFirstChild(AnvilOwned):FindFirstChild(AnvilOwned).BillboardGui.Frame.ScrollingFrame
for _, frame in ipairs(scrollingFrame:GetChildren()) do
if frame:IsA("Frame") then
CurrentNumberRunningWeapon += 1
print("CURRENT NUMBER RUNNING WEAPON IS : ", CurrentNumberRunningWeapon, player.Name)
end
end
handlePromptTriggered(player, false)
As you can see we got weapons that got removed from the Offlines but it still somehow add 2 weapons back and it was the previous one this is a very annoying bug. The CurrentNumberRunningWeapon counter although initialize at 0 when I assign the plot each time directly skipped through 10 which is like the equivalent of the Swords length it gave me and now I wonder if my problem is when I save the data or when I load the data
Here’s the code to save the last running weapon of the game :
local index = 0
print("OFFLINE SWORDS IS : ", profile.Data.OfflineSwords)
profile.Data.OfflineSwords = {}
for _, frame in ipairs(ScrollingFrame:GetChildren()) do
if frame:IsA("Frame") then
local imageLabel = frame.ImageLabel
index += 1
imageLabel:SetAttribute("LayoutOrder", index)
imageLabel:SetAttribute("IsRunning", false)
profile.Data.OfflineSwords[index] = {
Name = frame.Name,
Countdown = imageLabel:GetAttribute("Countdown"),
Material = imageLabel:GetAttribute("Material"),
Level = imageLabel:GetAttribute("Level"),
IsFinished = imageLabel:GetAttribute("IsFinished"),
IsRunning = imageLabel:GetAttribute("IsRunning")
}
end
end
print("OFFLINE SWORDS LENGTH IS : ", #profile.Data.OfflineSwords)
When I comeback sometimes, it adds some frame for exemple the length of my ScrollingFrame was 4 but it adds the previous cooldown of a sword that has already finished which is very weird and I have no idea about why it’s doing this.
Note that handlePromptTriggered(player, false) is the function that runs the cooldown of each swords in the anvil
Here’s the proof of cooldown not working :
