The Parent property of Stone is locked

So I’m trying to make a mining system, I made it where if any rock is mined it will clone a few parts called “Stone” and a random Ore. But For some odd reason when I mine one rock it works but once i mine another rock I get this error and the stone parts won’t clone nor will the random ore. I didn’t know how to fix this, and tried to look up solutions but i couldn’t find much so far.

Screenshot 2021-06-22 184509

Here’s the script, sorry if its a bit long:

local stones = {}
local items = {}

local respawnTime = script.Parent.RespawnTime

--Services
local ss = game:GetService("ServerStorage")
local UIS = game:GetService("UserInputService")

--LootTable
local Drops = {
	--Common
	{Name = "Coal"},
	{Name = "Copper"},
	{Name = "Iron"},
	{Name = "Lead"},
	{Name = "Tin"},
	--Uncommon
	{Name = "Amber"},
	{Name = "Gold"},
	{Name = "Platinum"},
	{Name = "Sapphire"},
	{Name = "Topaz"},
	{Name = "Tungesten"},
	--Rare
	{Name = "Cobalt"},
	{Name = "Diamond"},
	{Name = "Emerald"},
	{Name = "Garnet"},
	{Name = "Onyx"},
	{Name = "Ruby"},
	{Name = "SkyBlueTopaz"}
}


local lootTable = {
	--Common Drops
	{Item = Drops[1], Weight = 100}, --Coal
	{Item = Drops[2], Weight = 100}, --Copper
	{Item = Drops[3], Weight = 100}, --Iron
	{Item = Drops[4], Weight = 100}, --Lead
	{Item = Drops[5], Weight = 100}, --Tin

	--Uncommon Drops
	{Item = Drops[6], Weight = 45}, --Amber
	{Item = Drops[7], Weight = 45}, --Gold
	{Item = Drops[8], Weight = 45}, --Platinum
	{Item = Drops[9], Weight = 45}, --Sapphire
	{Item = Drops[10], Weight = 45}, --Topaz
	{Item = Drops[11], Weight = 45}, --Tungesten

	--Rare Drops
	{Item = Drops[12], Weight = 15}, --Cobalt
	{Item = Drops[13], Weight = 15}, --Diamond
	{Item = Drops[14], Weight = 15}, --Emerald
	{Item = Drops[15], Weight = 15}, --Garnet
	{Item = Drops[16], Weight = 15}, --Onyx
	{Item = Drops[17], Weight = 15}, --Ruby
	{Item = Drops[18], Weight = 15}, --Sky Blue Topaz
}

local function returnSumOfWeight(lootTable)
	local sum = 0
	for _, entry in pairs(lootTable) do
		sum = sum + entry.Weight
	end
	return sum
end

local function getRandomItem(lootTable)
	local randomNumber = math.random(returnSumOfWeight(lootTable))

	for _, entry in ipairs(lootTable) do
		if randomNumber <= entry.Weight then
			return entry.Item
		else
			randomNumber = randomNumber - entry.Weight
		end
	end
end

for i,object in pairs((script.Parent:GetChildren())) do --Will Get all of the stone
	if(object:IsA("BasePart")) then
		if(object:FindFirstChild("Health"))then
			--Rock Variables
			local label = object.HealthInfo
			local hit_sound = script.Parent.Hit
			local rockPos = object.Position
			local Health = object.Health
			local MaxHealth = object.MaxHealth
			local RockMined = object.Mined.Value
			
			--Mining Manager
			object.Touched:Connect(function(otherPart)
				local rockhit = false
				local tool = otherPart.Parent
				if tool:IsA('Tool') and tool.Mining.Value == true then
					if rockhit == false then
						rockhit = true
						local damage = tool.Damage.Value
						hit_sound:Play()
						Health.Value = Health.Value - damage
						label.TextLabel.Text = Health.Value.."/"..MaxHealth.Value
						if(object.Health.Value <= 0) then --
							if RockMined == false then

								RockMined = true
								
								local stone = ss.Drops.Normal:WaitForChild("Stone")

								--Stone Generator
								for i = 1, math.random(1,4) do
									local clonedStone = stone:Clone()
									table.insert(stones, #stones + 1, clonedStone)
								end

								for index, clonedStone in ipairs(stones) do
									clonedStone.Position = rockPos 
									clonedStone.Parent = workspace
								end

								--Crystal/Ore Generator
								local RandomDrop = math.random(96,99)
								local item = getRandomItem(lootTable)
								local Item = ss.Drops.Ores:FindFirstChild(item.Name)

								for i = 1, math.random(1,3) do
									local clonedItem = Item:Clone()
									table.insert(items, #items + 1, clonedItem)
								end

								for index, clonedItem in ipairs(items) do
									clonedItem.Position = rockPos 
									clonedItem.Parent = workspace
								end
                                                                object:Destroy()
							end
						end
						wait(0.05)
						rockhit = false
					end
				end
			end)
		end
	end
end
1 Like

From what it looks like, this:

for i,object in pairs((script.Parent:GetChildren())) do --Will Get all of the stone
	if(object:IsA("BasePart")) then
		if(object:FindFirstChild("Health"))then

gets all the stones, some of which are in the ‘stones’ table from the last time the for loop ran.
You parent the stones with this line:

								for index, clonedStone in ipairs(stones) do
									clonedStone.Position = rockPos 
									clonedStone.Parent = workspace
								end

But remember you called object:Destroy(), on what may be one of those stones.
So now the next time it loops through you’re attempting to parent a destroyed stone which was left in the stones table, and its parent is locked because of this.

I would consider looping through the stones a bit differently, like placing them into a Model in workspace and using :GetChildren() rather than using a table to store them.

I hope this helps

2 Likes

ok im going to try to Clone the Stones from a folder in Serverstorage and see if that works and move them into the folder where all the items go, with the position of the stone.

oh yeah forgot to send this earlier hopefully this helps
Screenshot 2021-06-22 195043

I think I see a possible cause.
You have your “debounce” variable defined in the Touched event:

object.Touched:Connect(function(otherPart)
    local rockhit = false -- 'rockhit' becomes false each time this is touched

when it should be:

local rockhit = false;
object.Touched:Connect(function(otherPart)
    -- once rockhit is true, it stays true

roblox’s touched events usually get spammed a few times, which could make it call :Destroy() on the same object multiple times.

If that’s not it, then it could be something else calling :Destroy() on it

So I deleted the :Destroy() making it where the rock never fully breaks. But for some reason, it still gives me the same error and I did what you told and you manage to fix another bug for me which was the pickaxe doing more than 50 damage once the rock was hit. But I put the debounce outside and made it stay true and made it wait 0.1 sec and go false. But now another problem arose, now I can only hit the rock once and it won’t let me hit it again. Here’s what it looks like now

local debounce = false
script.Parent.Touched:Connect(function(otherPart)
	
	local tool = otherPart.Parent
	if tool:IsA('Tool') and tool.Mining.Value == true then
		if debounce == false then
			debounce = true
			local damage = tool.Damage.Value
			hit_sound:Play()
			Health.Value = Health.Value - damage
			label.TextLabel.Text = Health.Value.."/"..MaxHealth.Value
			if script.Parent.Health.Value <= 0 then
				if RockMined == false then
					
					RockMined = true

					local stone = ss.Drops.Normal:WaitForChild("Stone")

					--Stone Generator
					for i = 1, math.random(1,4) do
						local clonedStone = stone:Clone()
						table.insert(stones, #stones + 1, clonedStone)
					end

					for index, clonedStone in ipairs(stones) do
						clonedStone.Position = rockPos 
						clonedStone.Parent = workspace
					end

					--Crystal/Ore Generator
					local RandomDrop = math.random(96,99)
					local item = getRandomItem(lootTable)
					local Item = ss.Drops.Ores:FindFirstChild(item.Name)

					for i = 1, math.random(1,3) do
						local clonedItem = Item:Clone()
						table.insert(items, #items + 1, clonedItem)
					end

					for index, clonedItem in ipairs(items) do
						clonedItem.Position = rockPos 
						clonedItem.Parent = workspace
					end
					wait(0.1)
					debounce = false
				end
			end
		end
	end
end)