Placement system issues

Hi, I’m making a tool that has a placement system in it. The tool gets picked up and when equipped it clones a ghost part (Slightly transparent part) from the Replicated Storage and hovers with the mouse, and when the player left clicks it places a part on the location clicked (if it is within the max placing distance).
After the part has been placed I want the player to be able to keep placing parts, while also showing the ghost part. The ghost part is only suppost to be removed once the tool is unequipped or deleted.

The issue i have is that after I unequip and then equip the tool, the ghost part does not appear. I am also not able to place a new part after I have clicked once. For that I have to re-equipping the tool again. If I have unequipped the tool without clicking, then I am able to spawn the part even without holding/equipping the tool, just by clicking anywhere.

https://gyazo.com/6b0a41282cb103fe720126642ae9a9c3

-- RemoteHandler made by: TheDevKing

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Explosives = ReplicatedStorage:WaitForChild("Explosives")
local Events = ReplicatedStorage:WaitForChild("Events")
local PlaceObject = Events.PlaceTnt

PlaceObject.OnServerInvoke = function(player, ObjectName, ObjectCFrame)
	print(PlaceObject)
	
	local crafted
	local realObject = Explosives:FindFirstChild(ObjectName):Clone()
	
	if realObject then
		realObject.CFrame = ObjectCFrame
		realObject.Parent = game.Workspace
		crafted = true
	else 
		crafted = false
	end
	
	return crafted
end
-- ToolHandler LocalScript made by: TheDevKing
-- Edited by: NovaLamp

llocal Tool = script.Parent

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local Explosives = ReplicatedStorage:WaitForChild("Explosives")
local Events = ReplicatedStorage:WaitForChild("Events")
local PlaceObject = Events.PlaceTnt
local TntType1 = Explosives.BasicTnt
local TntType0 = Explosives.GhostTnt

local player = game.Players.LocalPlayer
local char = player.Character or player.Character:Wait()
local HumanoidRootPart = char:WaitForChild("HumanoidRootPart")

local mouse = player:GetMouse()

local yBuildingOffset = 2.5
local maxPlacingDistance = 25
local placingObject = false

Tool.Equipped:Connect(function()
	local goodToPlace = false
	local placedObject
	
	local conns = {}
	
	if placingObject == false then
		placingObject = true
		
		local clientObject = Explosives:FindFirstChild(TntType0.Name):Clone()
		clientObject.Parent = game.Workspace
		clientObject.Name = "ClientGhostTnt"
		
		local startingCFrame = CFrame.new(0,-2,-15)
		clientObject.CFrame = HumanoidRootPart.CFrame:ToWorldSpace(startingCFrame)
		
		conns[#conns+1] = RunService.RenderStepped:Connect(function()
			local mouseRay = mouse.UnitRay
			local castRay = Ray.new(mouseRay.Origin, mouseRay.Direction * 1000)
			local ignoreList = {clientObject, char}
			local hit, position = workspace:FindPartOnRayWithIgnoreList(castRay, ignoreList)
			
			if hit and (HumanoidRootPart.Position - clientObject.Position).Magnitude < maxPlacingDistance then
				goodToPlace = true
				clientObject.Transparency = 0.5
				for num, child in pairs (clientObject:GetChildren()) do
					if child:IsA('Decal') then
						child.Transparency = 0.7
					end
				end					
			else
				goodToPlace = false
				clientObject.Transparency = 1
				for num, child in pairs (clientObject:GetChildren()) do
					if child:IsA('Decal') then
						child.Transparency = 1
					end
				end					
			end
			
			local newCFrame = CFrame.new(position.X, position.Y+yBuildingOffset, position.Z)
			clientObject.CFrame = newCFrame
		end)
		
		conns[#conns+1] = UIS.InputBegan:Connect(function(input)
			if input.UserInputType == Enum.UserInputType.MouseButton1 then
				if placingObject == true then
					if goodToPlace == true then
						local StructureCFrame = clientObject.CFrame
						placedObject = PlaceObject:InvokeServer(TntType1.Name, StructureCFrame)

						if placedObject == true then
							placingObject = false
							clientObject:Destroy()
							
							for i, v in ipairs(conns) do
								v:Disconnect()
							end
							
							if player.Character then 
								local humanoid = player.Character:FindFirstChildOfClass("Humanoid")
								if humanoid then 
									humanoid:UnequipTools()
								end
							end
						end
					end
				end
			end
		end)
	end
end)



Tool.Unequipped:Connect(function()
	for i, v in ipairs(workspace:GetDescendants()) do
		if v.Name == "ClientGhostTnt" then
			v.Color = Color3.fromRGB(255, 165, 38)
		end
	end
	wait(0.1)
	for i, v in ipairs(workspace:GetDescendants()) do
		if v.Name == "ClientGhostTnt" then
			v:Destroy()
		end
	end
end)

image

As of right now I have made it automatically unequip the tool and deleted the ghost part after it has been clicked.

1 Like

This script could help you

ServerSide

-- Define Services
local ReplicatedStorage = game:GetService('ReplicatedStorage')
 
-- Waiting for client to fire RemoteEvent
ReplicatedStorage:WaitForChild('Place').OnServerEvent:Connect(function(player, placePosition, placeObject)
    -- Print out the player, placePosition and placeObject to the console for testing purposes
    print(player, placePosition, placeObject)
    -- Clone the object that the player passed to the event
    local objClone = placeObject:Clone()
    -- Set the position (using CFrame.new)
    objClone.PrimaryPart.CFrame = CFrame.new(placePosition)
    -- Set the parent to the workspace so that the object is visible
    objClone.Parent = workspace
end)

Client side

 
-- Define player objects
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
 
-- Define services needed
local UIS = game:GetService("UserInputService") -- for mouse input
local RunService = game:GetService('RunService') -- for RenderStepped / live input from the user 
local ReplicatedStorage = game:GetService('ReplicatedStorage') -- to define the RemoteEvent
 
local placeEvent = ReplicatedStorage:WaitForChild('Place') -- RemoteEvent to tell server to place object
 
local bed = workspace:WaitForChild('Bed') -- object  being used
 
-- params: X(x position on the screen), Y(y position on the screen), IgnoreList(List of objects to ignore when making raycast)
-- returns: Instance(object that the player's mouse is on), Vector3(position that the player's mouse is on)
function getMousePoint(X, Y, IgnoreList)
    
    -- Create a new set of Raycast Parameters
    local raycastParams = RaycastParams.new()
    raycastParams.FilterType = Enum.RaycastFilterType.Blacklist -- have the mouse ignore objects
    raycastParams.FilterDescendantsInstances = {bed} -- have the mouse ignore the bed
    raycastParams.IgnoreWater = true
 
    local camray = camera:ScreenPointToRay(X, Y) -- get the position on the world relative to the mouse's screen position(x,y)
    
    -- Draw the ray in the world, pointing at wherever the mouse is
    local raycastResult = workspace:Raycast(camray.Origin, camray.Direction * 2048, raycastParams)
    
    -- If the draw failed, or the mouse is pointing at the sky, return nil
    if not raycastResult then return nil end
    
    
    -- Otherwise, return the part and position the mouse is over
    return raycastResult.Instance, raycastResult.Position
end
 
-- [TIP] this was the old way to get the mouse, THIS SHOULD NO LONGER BE USED
local Mouse = game.Players.LocalPlayer:GetMouse()
-- [END OF TIP]
 
UIS.InputBegan:Connect(function(i)
    -- When the user clicks (left mouse button)
    if i.UserInputType == Enum.UserInputType.MouseButton1 then
        -- Get the mouse location using the User Input Service
        local mouseLocation = UIS:GetMouseLocation()
        -- Get the target object and position
        local target, position = getMousePoint(mouseLocation.X, mouseLocation.Y, {bed})
        -- If the target object and position BOTH exist
        if target and position then
            -- Set the bed there for the client, and tell the server
            bed.PrimaryPart.CFrame = CFrame.new(position)
            placeEvent:FireServer(position, bed)
        end
    end
end)
 
-- RenderStepped will run every frame for the client (60ish times a second)
RunService.RenderStepped:Connect(function()
    -- Get the mouse location using the User Input Service
    local mouseLocation = UIS:GetMouseLocation()
    -- Get the target object and position
    local target, position = getMousePoint(mouseLocation.X, mouseLocation.Y, {bed})
    -- If the target object and position BOTH exist
    if target and position then
        -- Set the bed there for the client
        bed.PrimaryPart.CFrame = CFrame.new(position)
    end
end)

Why are you providing free modeled scripts which aren’t related to the thread poster’s scripts?

3 Likes