Please help me fix my script!

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I want some help to possibly fix some bugs in a script I have made.

  2. What is the issue? I’m making a system where you buy a developer product and then it will spawn a certain amount of parts at a part in the workspace. The problem is, is sometimes the script works and spawns the parts but most of the time it only prompts me with my product and it doesn’t spawn the parts?

  3. What solutions have you tried so far? I’ve tried to change different things inside my script to make it detect the folder in server storage with the parts so if it doesn’t find the folder it will keep trying. I’m really stuck on this and I could use some help. Thanks

local MarketplaceService = game:GetService("MarketplaceService")
local ServerStorage = game:GetService("ServerStorage")
local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")

local promptConfig = {
    {partName = "Prompt1", devProductId = 3418468965},
    {partName = "Prompt2", devProductId = 3418479390},
    {partName = "Prompt3", devProductId = 3418479558},
    {partName = "Prompt4", devProductId = 3418479923},
    {partName = "Prompt5", devProductId = 3418480074},
    {partName = "Prompt6", devProductId = 3418480475},
    {partName = "Prompt7", devProductId = 3418480567},
    {partName = "Prompt8", devProductId = 3418480647},
    {partName = "Prompt9", devProductId = 3418482472},
    {partName = "Prompt10", devProductId = 3418482589},
    {partName = "Prompt11", devProductId = 3418482854},
    {partName = "Prompt12", devProductId = 3418482940},
    {partName = "Prompt13", devProductId = 3418483009},
    {partName = "Prompt14", devProductId = 3418483164},
    {partName = "Prompt15", devProductId = 3418483233},
    {partName = "Prompt250", devProductId = 3418502347},
}

local devProductIdToSpawnCount = {}
for i, config in promptConfig do
    local promptNumber = tonumber(config.partName:match("%d+")) or 1
    devProductIdToSpawnCount[config.devProductId] = promptNumber * 2
end

local function getPrompt(part)
    for k, v in part:GetChildren() do
        if v:IsA("ProximityPrompt") then
            return v
        end
    end
    return nil
end

local function spawnShapes(player, count)
    print("[DevProductSpawner] spawnShapes called for player:", player and player.Name or "nil", "count:", count)
    local objectsFolder = ServerStorage:FindFirstChild("Objects")
    if not objectsFolder then
        warn("[DevProductSpawner] ServerStorage.Objects folder not found at spawn time")
        return false, "ObjectsFolderMissing"
    end

    local objects = objectsFolder:GetChildren()
    local totalObjects = #objects
    print("[DevProductSpawner] Objects in folder:", totalObjects)
    if totalObjects == 0 then
        warn("[DevProductSpawner] No objects found in ServerStorage.Objects")
        return false, "ObjectsEmpty"
    end

    local spawnPart = Workspace:FindFirstChild("SpawnPart")
    local baseCFrame
    if spawnPart then
        baseCFrame = spawnPart:GetPivot()
        print("[DevProductSpawner] Using SpawnPart at:", tostring(baseCFrame.Position))
    else
        warn("[DevProductSpawner] Workspace.SpawnPart not found, spawning at origin")
        baseCFrame = CFrame.new(0, 5, 0)
    end

    local spawned = 0
    local objIndex = 1
    for i = 1, count do
        local obj = objects[objIndex]
        if obj then
            local clone = obj:Clone()
            clone.Parent = Workspace
            if clone:IsA("Model") then
                clone:PivotTo(baseCFrame)
                print("[DevProductSpawner] Spawned Model: " .. tostring(clone.Name) .. " at " .. tostring(baseCFrame.Position))
            elseif clone:IsA("BasePart") then
                clone.CFrame = baseCFrame
                print("[DevProductSpawner] Spawned Part: " .. tostring(clone.Name) .. " at " .. tostring(baseCFrame.Position))
            else
                print("[DevProductSpawner] Spawned object: " .. tostring(clone.Name) .. " (type: " .. clone.ClassName .. ")")
            end
            spawned = spawned + 1
        else
            warn("[DevProductSpawner] Object index " .. tostring(objIndex) .. " not found in objects list")
        end
        objIndex = objIndex + 1
        if objIndex > totalObjects then
            objIndex = 1
        end
    end
    local leaderstats = player and player:FindFirstChild("leaderstats")
    if leaderstats then
        local amountDropped = leaderstats:FindFirstChild("AmountDropped")
        if amountDropped then
            amountDropped.Value = amountDropped.Value + spawned
        else
            warn("[DevProductSpawner] AmountDropped leaderstat not found for player: " .. (player and player.Name or "nil"))
        end
    else
        warn("[DevProductSpawner] leaderstats not found for player: " .. (player and player.Name or "nil"))
    end
    print("[DevProductSpawner] Finished spawning " .. tostring(spawned) .. " objects for " .. (player and player.Name or "nil"))
    if spawned > 0 then
        return true
    else
        return false, "NothingSpawned"
    end
end

for i, config in promptConfig do
    local part = Workspace:FindFirstChild(config.partName)
    if part then
        local prompt = getPrompt(part)
        if prompt then
            prompt.Triggered:Connect(function(player)
                MarketplaceService:PromptProductPurchase(player, config.devProductId)
                print("[DevProductSpawner] Prompted product purchase for " .. player.Name .. " (" .. config.partName .. ")")
            end)
        else
            warn("[DevProductSpawner] No ProximityPrompt found in part: " .. config.partName)
        end
    else
        warn("[DevProductSpawner] Part not found in Workspace: " .. config.partName)
    end
end

local function getPlayerByUserIdWithRetry(userId, maxWait)
    local player = Players:GetPlayerByUserId(userId)
    local waited = 0
    while not player and waited < maxWait do
        task.wait(0.2)
        waited = waited + 0.2
        player = Players:GetPlayerByUserId(userId)
    end
    return player
end

local processedReceipts = {}

MarketplaceService.ProcessReceipt = function(receiptInfo)
    print("[DevProductSpawner] ProcessReceipt called for ProductId: " .. tostring(receiptInfo.ProductId) .. ", PlayerId: " .. tostring(receiptInfo.PlayerId) .. ", ReceiptId: " .. tostring(receiptInfo.PurchaseId))
    if processedReceipts[receiptInfo.PurchaseId] then
        warn("[DevProductSpawner] Receipt already processed: " .. tostring(receiptInfo.PurchaseId))
        return Enum.ProductPurchaseDecision.PurchaseGranted
    end

    local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
    if not player then
        print("[DevProductSpawner] Player not found for receipt: " .. tostring(receiptInfo.PlayerId) .. ", retrying for up to 5 seconds...")
        player = getPlayerByUserIdWithRetry(receiptInfo.PlayerId, 5)
        if not player then
            warn("[DevProductSpawner] Player still not found after retry for receipt: " .. tostring(receiptInfo.PlayerId))
            return Enum.ProductPurchaseDecision.NotProcessedYet
        else
            print("[DevProductSpawner] Player found after retry: " .. player.Name)
        end
    end

    local spawnCount = devProductIdToSpawnCount[receiptInfo.ProductId]
    print("[DevProductSpawner] spawnCount for ProductId:", receiptInfo.ProductId, "is", spawnCount)
    if spawnCount then
        local success, failReason = spawnShapes(player, spawnCount)
        if success then
            print("[DevProductSpawner] Purchase granted for " .. player.Name .. ", spawned " .. tostring(spawnCount) .. " objects.")
            processedReceipts[receiptInfo.PurchaseId] = true
            return Enum.ProductPurchaseDecision.PurchaseGranted
        else
            warn("[DevProductSpawner] spawnShapes failed for player: " .. player.Name .. " (reason: " .. tostring(failReason) .. ")")
            if failReason == "ObjectsFolderMissing" then
                warn("[DevProductSpawner] ServerStorage.Objects folder missing at time of spawn.")
            elseif failReason == "ObjectsEmpty" then
                warn("[DevProductSpawner] ServerStorage.Objects folder is empty.")
            elseif failReason == "NothingSpawned" then
                warn("[DevProductSpawner] No objects were spawned, possible logic error.")
            end
            return Enum.ProductPurchaseDecision.NotProcessedYet
        end
    else
        warn("[DevProductSpawner] Unknown dev product ID: " .. tostring(receiptInfo.ProductId))
        return Enum.ProductPurchaseDecision.NotProcessedYet
    end
end


This is my first time posting im not sure how all of this works.

3 Likes

Hi! I’m really only noticing one issue which could be the cause.

On this line:
for i, config in promptConfig do

You need to do:
for i,config in ipairs(promptConfig) do.
Otherwise it won’t work at all. Give that a go, not entirely sure if that would be the cause.

What is the runcontext of the script?

I’m fairly certain pairs / ipairs is no longer required to iterate through arrays and dictionaries

You have a lot of debug prints, which is good. Which ones show up when the parts fail to place? Does the entire thing not run? Is this code stored within a ModuleScript or used across multiple Script copies?

Nope, just a server script inside serverscriptservice

Hey I just tested that and it still doesnt want to spawn the parts

1 Like

Server Script in server script service

What prints/warnings do and don’t show up? Copy/pasting the full log might be easy and best.

Only “Prompted product purchase for Stone_Sour12”. which is when i pressed e on one of my prompts