Script crashing all servers

Hey everyone, Recently I’ve been working on a script for my shop system the resets the shop every 5 minutes and every so often it crashes all servers when it refreshes and I can’t figure out how to fix it, I’ve gotten so desperate I even ran it through ChatGPT and it couldn’t even solve it. If you have any ideas on how to fix it please let me know!

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")

local SkinData = require(ReplicatedStorage.Server.Modules.SkinShop:WaitForChild("SkinData"))
local PlayerData = require(ReplicatedStorage.Server.Modules:WaitForChild("PlayerDataHandler"))

local NotifyEvent = ReplicatedStorage:WaitForChild("NotifyEvent")
local SkinFolder = ReplicatedStorage.Server.Assets:WaitForChild("Tables")

local SkinShop = Workspace.Map:WaitForChild("SkinShop")
local DisplaySkins = SkinShop:WaitForChild("DisplaySkins")
local RotateTimeLabel = SkinShop.Stock.Label.Desc

local PriceLabels = {
	SkinShop.SkinPrices["1"].Main.SurfaceGui.TextLabel,
	SkinShop.SkinPrices["2"].Main.SurfaceGui.TextLabel,
	SkinShop.SkinPrices["3"].Main.SurfaceGui.TextLabel
}

local NameLabels = {
	SkinShop.SkinName["1"].Label.Title,
	SkinShop.SkinName["2"].Label.Title,
	SkinShop.SkinName["3"].Label.Title
}

local Prompts = {
	SkinShop.SkinPrices["1"].Main.ProximityPrompt,
	SkinShop.SkinPrices["2"].Main.ProximityPrompt,
	SkinShop.SkinPrices["3"].Main.ProximityPrompt
}

local rarityWeights = {Common = 55, Uncommon = 25, Rare = 12, Epic = 6, Legendary = 2}
local ignoredNames = {TabelSpawn = true, VFX = true, CoinLand = true}
local activeDisplays = {}
local rotationInProgress = false

local function formatSkinName(name)
	return name:gsub("(%u)", " %1"):gsub("^%s+", "")
end


local function formatPrice(price)
	local str = tostring(price)
	while true do
		local formatted, k = str:gsub("^(-?%d+)(%d%d%d)", "%1,%2")
		str = formatted
		if k == 0 then break end
	end
	return str
end

local function alignModel(model, index)
	if not model.PrimaryPart then return end
	local rotations = {[1] = -24.56, [2] = -40.069, [3] = -58.022}
	local spot = DisplaySkins[tostring(index)]
	model:PivotTo(CFrame.new(spot.Position) * CFrame.Angles(0, math.rad(rotations[index]), 0))
end

local function fadeOut(model)
	if not model or not model.Parent then return end
	local parts = {}
	for _, p in ipairs(model:GetDescendants()) do
		if p:IsA("BasePart") and not ignoredNames[p.Name] then
			table.insert(parts, p)
		end
	end
	for _, p in ipairs(parts) do
		TweenService:Create(p, TweenInfo.new(0.4, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
			Transparency = 1,
			Size = p.Size * 0.7
		}):Play()
	end
	task.delay(0.45, function()
		if model then model:Destroy() end
	end)
end

local function spawnModel(template, index)
	local clone = template:Clone()
	clone.Parent = Workspace
	alignModel(clone, index)
	for _, p in ipairs(clone:GetDescendants()) do
		if p:IsA("BasePart") and not ignoredNames[p.Name] then
			p.Transparency = 1
			p.CFrame *= CFrame.new(0, -5, 0)
			TweenService:Create(p, TweenInfo.new(0.4, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {
				CFrame = p.CFrame * CFrame.new(0, 5, 0),
				Transparency = 0
			}):Play()
		end
	end
	return clone
end

local function deterministicSeed()
	local now = os.date("*t")
	local interval = math.floor(now.min / 5)
	return now.year * 1000000 + now.yday * 10000 + now.hour * 100 + interval
end

local function pickSkins()
	local all = SkinData.GetAll()
	local pool = {}
	for name, data in pairs(all) do
		if data.InRotation and name ~= "DefaultTable" then
			local weight = rarityWeights[data.Rarity] or 1
			for _ = 1, weight do
				table.insert(pool, name)
			end
		end
	end

	math.randomseed(deterministicSeed())
	local chosen = {}
	while #chosen < 3 and #pool > 0 do
		local pick = pool[math.random(#pool)]
		if not table.find(chosen, pick) then
			table.insert(chosen, pick)
		end
	end
	return chosen
end

local function updateDisplays(list)
	for _, model in ipairs(activeDisplays) do
		task.spawn(fadeOut, model)
	end
	activeDisplays = {}

	for i = 1, 3 do
		local name = list[i]
		local template = SkinFolder:FindFirstChild(name)
		if template then
			local info = SkinData.GetSkin(name)
			activeDisplays[i] = spawnModel(template, i)
			local displayName = formatSkinName(name)
			NameLabels[i].Text = displayName
			PriceLabels[i].Text = formatPrice(info.Price) .. "₵"
			Prompts[i].ObjectText = displayName
			Prompts[i].Name = name


		else
			NameLabels[i].Text = "N/A"
			PriceLabels[i].Text = "N/A"
			Prompts[i].ObjectText = "N/A"
		end
	end
end

local function secondsUntilNextRotation()
	local now = os.date("*t")
	local mins = now.min
	local secs = now.sec
	local nextMark = math.ceil((mins + 1) / 5) * 5
	if nextMark >= 60 then nextMark = 0 end
	local diff = (nextMark - mins)
	if diff < 0 then diff += 5 end
	local total = diff * 60 - secs
	if total < 3 then total += 300 end
	return total
end

local function rotateShop()
	if rotationInProgress then return end
	rotationInProgress = true
	while true do
		local skins = pickSkins()
		updateDisplays(skins)
		NotifyEvent:FireAllClients("<font color='#16f700'>The Shop Has Reset!</font>", 4)

		local waitTime = secondsUntilNextRotation()
		local endTime = os.clock() + waitTime
		while os.clock() < endTime do
			local remaining = math.max(0, math.floor(endTime - os.clock()))
			local mins = math.floor(remaining / 60)
			local secs = remaining % 60
			RotateTimeLabel.Text = string.format("%02d:%02d", mins, secs)
			task.wait(1)
		end
	end
end

local function buySkin(player, slot)
	local name = Prompts[slot].Name
	if name == "N/A" then return end
	local data = SkinData.GetSkin(name)
	if not data then return end

	local stats = player:FindFirstChild("leaderstats")
	local coins = stats and stats:FindFirstChild("Coins")
	if not coins then return end

	if PlayerData.HasSkin(player, name) then
		NotifyEvent:FireClient(player, "You already own this skin!", 3)
		return
	end
	if coins.Value < data.Price then
		NotifyEvent:FireClient(player, "Not enough coins!", 3)
		return
	end

	coins.Value -= data.Price
	PlayerData.AddSkin(player, name)
	NotifyEvent:FireClient(player, "Purchased " .. name .. "!", 3)
end

for i, prompt in ipairs(Prompts) do
	prompt.Triggered:Connect(function(player)
		buySkin(player, i)
	end)
end

task.spawn(function()
	local success, err = pcall(rotateShop)
	if not success then
		warn("Shop rotation failed:", err)
	end
end)
1 Like

add a task.wait() at the end of the while true do loop. if they don’t have this, the function is impossible to do without crashing or timing out due to execution exhaustion.

Like this?

local function rotateShop()
	if rotationInProgress then return end
	rotationInProgress = true
	while true do
		local skins = pickSkins()
		updateDisplays(skins)
		NotifyEvent:FireAllClients("<font color='#16f700'>The Shop Has Reset!</font>", 4)

		local waitTime = secondsUntilNextRotation()
		local endTime = os.clock() + waitTime
		while os.clock() < endTime do
			local remaining = math.max(0, math.floor(endTime - os.clock()))
			local mins = math.floor(remaining / 60)
			local secs = remaining % 60
			RotateTimeLabel.Text = string.format("%02d:%02d", mins, secs)
			task.wait(1)
		end

		task.wait()
	end
end
1 Like

yes, like that. test how it is and see if it crashes this time.

1 Like

it does still and it spams refreshes the shop

1 Like