Why do objects sometimes dupe?

This is a major issue in my “Steal a” type game. Sometimes, objects dupe, one time a limited-time object duped into FIFTEEN of the same object when it was stolen! (According to a bug report)

I swear, I will give whoever helps me fix this like 10k robux :sob:

Seriously though, does anyone know the issue??

local STEAL_COOLDOWN = 5
stealEvent.OnServerInvoke = function(player, object, am_i_a_skid)
	if not object then
		warn("Trying to steal non-existent object")
		return false, "This object does not exist!"
	end

	local plrName = object.Parent.Parent.Name
	local originalPlayer = Players:FindFirstChild(plrName)
	local ownerUserId = originalPlayer and originalPlayer.UserId or Players:GetUserIdFromNameAsync(plrName)

	if not ownerUserId then
		warn("Object doesn't belong to any player")
		return false, "This object does not exist!"
	end

	if plrName == "mlnitoon2" then
		return false, "Please don't steal from the creator, thanks!!"
	end

	local function getOriginalPlayer()
		return Players:GetPlayerByUserId(ownerUserId)
	end

	if player:GetAttribute("Stealing") then
		warn("Already stealing another object")
		return false, "You are already in the middle of stealing."
	end

	local char = player.Character
	if not char or not char.PrimaryPart then
		return false, "Your character does not exist."
	end

	local openPlotSpot = getPlotSpot(player)
	if not openPlotSpot then
		return false, "You need more room in your base to steal an object."
	end

	if (char.PrimaryPart.Position - object.PrimaryPart.Position).Magnitude > 10 then
		return false, "You need to be closer to steal this object."
	end

	local lastStealTime = player:GetAttribute("LastStealTime")
	if lastStealTime and tick() - lastStealTime < STEAL_COOLDOWN then
		return false, "You are stealing objects too fast!"
	end

	if am_i_a_skid == "Steal" then
		sendExploiterMessage(player, "Fake auto stealer detected!", "https://discord.com/api/webhooks/1423095928352669812/STt_AQR_jlV6DnKu4NRB9rs9Oz_pve0BA_uDvKWE9YXr-uYqRWV3R7YKSczIF8rxzbT2")
		return false, "skid LOL"
	end

	if object:GetAttribute("BeingStolen") then
		return false, "This object is already being stolen."
	end

	local currentOwner = getOriginalPlayer()
	if object.Parent and object.Parent.Parent.LockBase.BillboardGui.TextLabel.Text ~= "Lock Base" 
		and (not currentOwner or not player:IsFriendsWith(ownerUserId))
		and player.Name ~= "mlnitoon2" then
		return false, "This object's base is locked!"
	end

	object:SetAttribute("BeingStolen", true)

	local clone = object:Clone()
	clone.PrimaryPart.Anchored = false
	clone:SetPrimaryPartCFrame(char.PrimaryPart.CFrame + char.PrimaryPart.CFrame.LookVector)
	clone.Parent = workspace

	local weld = Instance.new("WeldConstraint")
	weld.Part0 = clone.PrimaryPart
	weld.Part1 = char.PrimaryPart
	weld.Parent = clone.PrimaryPart

	clone:FindFirstChildOfClass("Humanoid"):Destroy()
	player.Character.Humanoid.WalkSpeed = game.StarterPlayer.CharacterWalkSpeed / 1.5

	for _, part in pairs(clone:GetChildren()) do
		if part:IsA("BasePart") then
			part.CanCollide = false
			part.Massless = true
		elseif part:IsA("Script") or part:IsA("Model") or part.Name == "CollectPad" then
			part:Destroy()
		end
	end
	if clone.PrimaryPart:FindFirstChild("Action") then
		clone.PrimaryPart.Action:Destroy()
	end

	player:SetAttribute("Stealing", true)
	player:SetAttribute("LastStealTime", tick())

	stealNotifEvent:FireClient(currentOwner, player.Name, object.Name)

	local connections = {}
	local function cleanup(reason)
		for _, c in ipairs(connections) do c:Disconnect() end
		if clone then clone:Destroy() end
		object:SetAttribute("BeingStolen", false)
		player:SetAttribute("Stealing", false)
		player.Character.Humanoid.WalkSpeed = game.StarterPlayer.CharacterWalkSpeed
		if reason then warn(reason) end
	end

	table.insert(connections, player:GetAttributeChangedSignal("Stealing"):Connect(function()
		if not player:GetAttribute("Stealing") then
			cleanup("Stealing cancelled")
		end
	end))

	table.insert(connections, Players.PlayerRemoving:Connect(function(leaving)
		if leaving == player then
			cleanup("Stealer left")
		end
	end))

	table.insert(connections, char.Humanoid.Died:Connect(function()
		cleanup("Stealer died")
	end))

	table.insert(connections, workspace.Plots:FindFirstChild(player.Name).Pivot.Touched:Connect(function(hit)
		if hit.Parent.Name == player.Name then
			local owner = getOriginalPlayer()
			local plotSpot = object:GetAttribute("Spot")

			if not owner or not PlayerData[owner] then
				local offline = PlayerState.GetOfflineData(ownerUserId)
				if offline and offline.OwnedObjects then
					for i = #offline.OwnedObjects, 1, -1 do
						if offline.OwnedObjects[i].PlotSpot == plotSpot then
							table.remove(offline.OwnedObjects, i)
							break
						end
					end
					PlayerState.SetOfflineData(ownerUserId, "OwnedObjects", offline.OwnedObjects)
				end
			else
				for i = #PlayerData[owner].OwnedObjects, 1, -1 do
					if PlayerData[owner].OwnedObjects[i].PlotSpot == plotSpot then
						table.remove(PlayerData[owner].OwnedObjects, i)
						break
					end
				end
			end

			openPlotSpot = getPlotSpot(player) or 1
			table.insert(PlayerData[player].OwnedObjects, {Object = object.Name, Mutations = {object:GetAttribute("Mutation")}, PlotSpot = openPlotSpot})
			table.insert(PlayerData[player].ObjectsEverOwned, {Object = object.Name})

			local plot = workspace.Plots:FindFirstChild(player.Name)
			local base = plot.ObjectSpawns["Spot" .. openPlotSpot].CFrame

			local newOwnedObject = ReplicatedStorage.Objects:FindFirstChild(object.Name):Clone()
			newOwnedObject.Parent = plot.Objects
			newOwnedObject:PivotTo(base * CFrame.new(0,3,0))
			newOwnedObject.PrimaryPart.Anchored = true
			newOwnedObject:SetAttribute("Spot", openPlotSpot)

			attachCollector(newOwnedObject, player, Objects.Data[object.Name], base, {object:GetAttribute("Mutation")})

			PlayerState.Increment(player, "Steals", 1)
			PlayerState.Increment(player, "S1XP", (math.min(math.round(1 + (0.01 * Objects.Data[object.Name].Price)), 500)) * (MarketplaceService:UserOwnsGamePassAsync(player.UserId, 1510520508) and 2 or 1))
			PlayerState.SaveData(player)

			updateIndexEvent:FireClient(player)
			object:Destroy()
			cleanup()
			return true, "You successfully stole this object."
		end
	end))
end

try giving each stealable object unique identification (like an id number), and have it delete all the objects with the same exact identification to prevent duping.

only downside for this is that might require some tedious data storing or sending requests to a server to check in all servers.

1 Like

That will require more than 10K dollars

1 Like

You can use memorystoreservice for temporary memory storage, so servers can go through recent items in a queue and delete duplicate IDs

And when specifically does the dupe happen

i fixed it by adding a debounce lol

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.