2 Item Crafting System Randomly Stops Working in-game but is fine in studio?

Hello, developers! I’ve attempted to create a 2-item crafting system for my game, which works perfectly in the studio, but in-game, it randomly stops working without any given errors. It usually only happens when my brother is on console and tries to use it. I’ve tested it with two players in studio, and it worked great. So I assume it’s something to do with the client or a logic error in my code I can’t seem to find.

Server:

-- # Services
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- # Objects
local CraftingTable = workspace.Map.Cabin.CraftingTable
local Pos = CraftingTable.Pos
local Pos2 = CraftingTable.Pos2
local ProximityPrompt = CraftingTable.Part.ProximityPrompt
local Items_Folder = ReplicatedStorage.Items

-- # Remotes
local StartCrafting = ReplicatedStorage.Remotes.StartCrafting
local CheckItems = ReplicatedStorage.Remotes.CheckItems
local ItemAdded = ReplicatedStorage.Remotes.ItemAdded
local ItemCrafted = ReplicatedStorage.Remotes.ItemCrafted
local ClearTable = ReplicatedStorage.Remotes.ClearTable

--local CraftingStatus = Pos.CraftingStatus.TextLabel
-- # Tables, etc.
local Items = {
	"Log",
	"Rope",
	"Stick",
	"Rock"
}

local Recipes = {
	Bow = {"Log", "Rope"},
	Axe = {"Stick", "Rock"}
}

local function changePlayerSpeed(player,speed)
	local char = player.Character or player.CharacterAdded:Wait()
	local humanoid = char:FindFirstChildWhichIsA("Humanoid")
	humanoid.WalkSpeed = speed
end

ProximityPrompt.Triggered:Connect(function(player)
	StartCrafting:FireClient(player)
    changePlayerSpeed(player,0)
end)

local function CheckForItem(Character)
	if not Character then
		warn(Character)
		return
	end
	
	local hasTool = Character:FindFirstChildWhichIsA("Tool")
	if hasTool then
		if table.find(Items,hasTool.Name) then
			return true
		end
	end
	return false
end

CheckItems.OnServerEvent:Connect(function(player,posLocation)
	local Character = player.Character or player.CharacterAdded:Wait()
	if Character then
		if CheckForItem(Character) then
			-- Has tool
			local hasTool = Character:FindFirstChildWhichIsA("Tool")
			ItemAdded:FireClient(player,hasTool,posLocation)
		end
	end
end)

local playerItem1 = {}
local playerItem2 = {}
local function isRecipeThenCraft(player)
	for result,v in pairs(Recipes) do
		local item1 = playerItem1[player]
		local item2 = playerItem2[player]
		
		if (
			(item1 == v[1] and item2 == v[2]) or
			(item1 == v[2] and item2 == v[1])
			) 
		then
			return result
		end
	end
	return nil
end

ItemAdded.OnServerEvent:Connect(function(player:Player,Item:Tool,PosLocation:Part)
	if table.find(Items,Item.Name) and PosLocation.Name == Pos.Name then
		playerItem1[player] = Item.Name
		Item:Destroy()
	elseif table.find(Items,Item.Name) and PosLocation.Name == Pos2.Name then
		playerItem2[player] = Item.Name
		Item:Destroy()
		
		local foundItem = isRecipeThenCraft(player)
		if foundItem then
			local newItem = Items_Folder:FindFirstChild(foundItem):Clone()
			newItem.Parent = player.Backpack
			
			ItemCrafted:FireClient(player)
			
			playerItem1[player] = nil
			playerItem2[player] = nil
			
			changePlayerSpeed(player,16)
			--warn("PlayerItem1:",playerItem1,"PlayerItem2:",playerItem2)
		end
	end
end)

ClearTable.OnServerEvent:Connect(function(player)
	changePlayerSpeed(player,16)
	
	if playerItem1[player] ~= nil then
		local returnItem = Items_Folder:FindFirstChild(playerItem1[player]):Clone()
		returnItem.Parent = player.Backpack
	end
	
	if playerItem2[player] ~= nil then
		local returnItem = Items_Folder:FindFirstChild(playerItem2[player]):Clone()
		returnItem.Parent = player.Backpack
	end
	
	playerItem1[player] = nil
	playerItem2[player] = nil
	--warn("PlayerItem1:",playerItem1,"PlayerItem2:",playerItem2)
end)

Client:

-- # Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local players = game:GetService("Players")

-- # Player
local Player = players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
repeat task.wait() until Character~= nil

if Character then
	warn("Character loaded")
end

local humanoid = Character:WaitForChild("Humanoid")
local PlayerGui = Player.PlayerGui

-- # UI
local CraftingScreen = PlayerGui:WaitForChild("CraftingScreen")
local Container = CraftingScreen:WaitForChild("Container")
local Leave = Container:WaitForChild("Leave")

-- # Camera
local CurrentCamera = workspace.CurrentCamera

-- # Objects
local Cabin = workspace.Map.Cabin
local CraftingTable = Cabin:WaitForChild("CraftingTable")
local Pos = CraftingTable:WaitForChild("Pos")
local Pos2 = CraftingTable:WaitForChild("Pos2")
local CamPos = CraftingTable:WaitForChild("CameraPos")
local Items_Folder = ReplicatedStorage.Items

-- # Remotes
local StartCrafting = ReplicatedStorage.Remotes.StartCrafting
local CheckItems = ReplicatedStorage.Remotes.CheckItems
local ItemAdded = ReplicatedStorage.Remotes.ItemAdded
local ItemCrafted = ReplicatedStorage.Remotes.ItemCrafted
local ClearTable = ReplicatedStorage.Remotes.ClearTable

-- # Prompts
local TablePrompt = CraftingTable:WaitForChild("Part"):WaitForChild("ProximityPrompt")
local PosPrompt = Pos:WaitForChild("ProximityPrompt")
local Pos2Prompt = Pos2:WaitForChild("ProximityPrompt")

-- # Sets when player joins
local DefaultWalkSpeed = humanoid.WalkSpeed

local function moveCamera(Object,Reset)
	if not Reset and Object then
		CurrentCamera.CameraType = Enum.CameraType.Scriptable
		TweenService:Create(
			CurrentCamera,
			TweenInfo.new(1),
			{CFrame = Object.CFrame}
		):Play()
	elseif Reset and Object.Name == "Head" then
		TweenService:Create(
			CurrentCamera,
			TweenInfo.new(1),
			{CFrame = Object.CFrame}
		):Play()
		
		task.delay(1,function()
			CurrentCamera.CameraType = Enum.CameraType.Custom
		end)
	elseif Reset and not Object then
		CurrentCamera.CameraType = Enum.CameraType.Custom
	end
end

StartCrafting.OnClientEvent:Connect(function(isCrafting)
	--humanoid.WalkSpeed = 0
	CraftingScreen.Enabled = true
	TablePrompt.Enabled = false
	PosPrompt.Enabled = true
	moveCamera(CamPos,false)
end)

PosPrompt.Triggered:Connect(function()
	CheckItems:FireServer(Pos)
end)

Pos2Prompt.Triggered:Connect(function()
	CheckItems:FireServer(Pos2)
end)

local function CheckForExistingDisplay(PosLocation)
	for _,isItem in pairs(PosLocation:GetChildren()) do
		if isItem:IsA("Tool") then
			return true
		end
	end
	return false
end

local function placeDisplay(PosLocation,Item)
	-- Place Display item
	local success, Error = pcall(function()
		local DisplayItem = Items_Folder:FindFirstChild(Item.Name):Clone()
		DisplayItem.Parent = PosLocation
		if DisplayItem:FindFirstChild("Handle") then
			DisplayItem.Handle.CFrame = PosLocation.CFrame
			DisplayItem.Handle.Anchored = true
			DisplayItem.RequiresHandle = false
		end
	end)
	if Error then
		warn("Issue with Display Item")
	end
end

local function enableOtherPrompt(PosLocation)
	for _,v in pairs(CraftingTable:GetChildren()) do
		local posName = string.match(v.Name, "Pos")
		if v:IsA("Part") and posName and v.Name ~= PosLocation.Name then
			if not CheckForExistingDisplay(v) then
				local prompt = v:FindFirstChildWhichIsA("ProximityPrompt")
				if prompt then
					prompt.Enabled = true
				end
			end
		end
	end
end

local function clearDisplays()
	for _,v in pairs(CraftingTable:GetChildren()) do
		local posName = string.match(v.Name, "Pos")
		if v:IsA("Part") and posName then
			if CheckForExistingDisplay(v) then
				local tool = v:FindFirstChildWhichIsA("Tool")
				if tool then
					tool:Destroy()
				end
			end
		end
	end
end

local function disablePOSPrompts()
	for _,v in pairs(CraftingTable:GetChildren()) do
		local posName = string.match(v.Name, "Pos")
		if v:IsA("Part") and posName then
			if not CheckForExistingDisplay(v) then
				local prompt = v:FindFirstChildWhichIsA("ProximityPrompt")
				if prompt then
					prompt.Enabled = false
				end
			end
		end
	end
end

local function visual(part)
	for _,v in pairs(part:GetChildren()) do
		if v:IsA("ParticleEmitter") then
			v:Emit(7)
		elseif v:IsA("Sound") then
			v.PlaybackSpeed = math.random(8,10)/10
			v:Play()
		end
	end
end

ItemAdded.OnClientEvent:Connect(function(Item,PosLocation)
	if Items_Folder:FindFirstChild(Item.Name) then
		if not CheckForExistingDisplay(PosLocation) then
			-- Disable Prompt
			PosLocation:FindFirstChildWhichIsA("ProximityPrompt").Enabled = false
		
			visual(PosLocation)
			enableOtherPrompt(PosLocation)
			
			placeDisplay(PosLocation,Item)
			ItemAdded:FireServer(Item,PosLocation)
		end
	end
end)

local function endCrafting()
	if Character:FindFirstChild("Head") then
		local head = Character:FindFirstChild("Head")
		moveCamera(head,true)
	else
		moveCamera(nil,true)
	end
	
	--humanoid.WalkSpeed = DefaultWalkSpeed
	clearDisplays()
	disablePOSPrompts()
	CraftingScreen.Enabled = false
	TablePrompt.Enabled = true
end

ItemCrafted.OnClientEvent:Connect(function()
	endCrafting()
	visual(CraftingTable:WaitForChild("Part"))
end)

Leave.MouseButton1Down:Connect(function()
	ClearTable:FireServer()
	endCrafting()
end)

Player.CharacterRemoving:Connect(function()
	ClearTable:FireServer()
	endCrafting()
end)

players.PlayerRemoving:Connect(function(player)
	if player == Player then
		ClearTable:FireServer()
		endCrafting()
	end
end)
3 Likes

Your system is not meant for multiplayer probably.
Do a playtesting with 2 player server inside studio and if it errors then its the system at fault.
image

3 Likes

Have you tried putting your sister on console instead?

If it’s silently failing, simply use print statements for a better diagnosis

1 Like

I have already tried this, as stated if you read my post.

1 Like

Lol, right.
This only happens outside of studio, and not all the time. I also tried 2 player testing in studio as I said in my post which gave me no issues. But I’ll try using print statements anyways.

1 Like

I found no issues, unfortunately. :melting_face:

1 Like

Could you show what you’ve tried? My best guess after looking at the code for a bit is you’re not clearing the contents of the folder which contains the positions.

Also not really necessary but it would help with making the system smoother if crafting was handled by the client and the server does a sanity checks for the items.

1 Like

Hey! Thank you for the reply :grin:

I’ve tried experimenting with multiple players in studio and found no issues, I tried using my phone which also was fine. My brother who’s on console though always seemed to run into issues where he couldn’t place any items, there were no errors I could find so I assumed it was just because the players weren’t loading in on time.

I tried turning off streaming enabled not knowing what it really even did at the time and tried using task.wait(3) at the start of both the server and client scripts, after that failed I tried making the client wait to run till the players character was fully loaded. Which also failed

1 Like

Sorry for responding late!

Anyways, I’d recommend checking if all your if statements related to this are working. It has to be because of them as there’s no error output as you’ve stated.

I haven’t tried replicating your environment besides from reading it, so I’m not fully sure whats fully causing it.

1 Like

Hey! So I just wanted to say I did more testing, today it seems like the issue just kind of fixed itself. I have no idea why that was happening. But no matter how many times I tried, I couldn’t replicate the issue. I’m sure after I mark this post as a solution, it’s gonna break again, lol.

Edit:
The issue only happens if the items aren’t already in the player’s inventory when they spawn. I appreciate everyone’s help. So I know the root cause of the issue now, and I’ll just try working it out myself from here. Take care, and God bless.

1 Like

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